What is Vue?
from the Vue website
Vue is a "progressive" JavaScript framework for building user interfaces. It works by building on top of standard HTML, CSS, and JavaScript. It is a component-based programming model similar to that of Anuglar, AngularJS, and React. As a framework, Vue aims to be flexible so that it can adapt to the projects of any scale. It can be implemented for any purpose ranging from creating a static HTML page, embedding web components, and dynamic DOM rendering based on server interactions.
What are the strengths of the Vue framework?
from the Vue website
- Single-File Components (SFC) provide a modularized development model that allows different parts of an application to be developed in isolation.
- Composition API enables clean patterns for organizing, extracting, and reusing complex logic.
- Comprehensive tooling support ensures a smooth development experience as the application grows, which can translate to a more efficient development cycle.
- Lower barrier to entry and excellent documentation translates to lower onboarding/training costs for new developers.
The Basics of the Vue Framework
How can Vue be used to render items to the page?
A simple Component example
<script setup>
import { ref } from 'vue'
// A "ref" is a reactive data source that stores a value.
const message = ref('Hello World!')
</script>
<template>
<h1>{{ message }}</h1>
</template>
- We import the
ref()
function from Vue, which allows us to reference a reactive data source. - We declare a constant variable
message
which refers to the string'Hello World'
. - Our template uses this constant variable, specifically the value it references, to render to the Document Object Model (DOM).
How can Vue be used to handle user input fields?
Initializing scripts for the Component
<script setup>
import { ref } from 'vue'
const message = ref('Hello World!')
function reverseMessage() {
message.value = message.value.split('').reverse().join('')
}
function notify() {
alert('navigation was prevented.')
}
</script>
- The
ref()
function is imported from Vue. - The
ref()
function is used to refer to amessage
. - We define two functions in our scripts, so that we can use them in our templates. Function
reverseMessage()
can be used to modify the render for our reference message. Functionnotify()
can be used to alert the user if something went wrong.
Creating the template for the Component
<template>
<h1>{{ message }}</h1>
<button @click="reverseMessage">Reverse Message</button>
<button @click="message += '!'">Append "!"</button>
<a href="https://vuejs.org" @click.prevent="notify">
A link with e.preventDefault()
</a>
</template>
- The template section will render to the page, and we begin by displaying the referenced
message
within header tags. - We create one button with a 'click' event listener, which references the
reverseMessage()
function that we defined in our scripts. Another button is also created, but in this case we use an in-line expression to edit our referencedmessage
. - On our hypertext reference link, we add a specialized 'click' event listener by chaining 'prevent' to the event listener. This is how Vue can be used to prevent defaults!
Optional styling for the Component
<style>
button, a {
display: block;
margin-bottom: 1em;
}
</style>
How does Vue handle attribute bindings and states?
Initializing scripts for the Component
<script setup>
import { ref } from 'vue'
const message = ref('Hello World!')
const isRed = ref(true)
const color = ref('green')
function toggleRed() {
isRed.value = !isRed.value
}
function toggleColor() {
color.value = color.value === 'green' ? 'blue' : 'green'
}
</script>
First, we reference the data
message
that we will eventually render.We also reference constant variable
isRed
to the boolean true. FunctiontoggleRed()
is used to toggle this referenced value to either true or false.We also reference constant variable color to the string
'green'
. FunctiontoggleColor()
is used with a ternary operator, toggling the reference value to a string of either'green'
or'blue'
.The references declared in these scripts enables a developer to initialize the state, and then the functions declared therein may also be used to manage/modify the state of the page.
Creating the template for the Component
Now that we have our state initialized, in addition to the tools necessary to modify it, we can begin working on our template. This is where 'fusion' occurs; at this stage we implementing our state references and functions to actually modify what is rendered!
<template>
<!-- 1 -->
<p>
<span :title="message">
Hover your mouse over me for a few seconds to see my dynamically bound title!
</span>
</p>
<!-- 2 -->
<p :class="{ red: isRed }" @click="toggleRed">
This should be red... but click me to toggle it.
</p>
<!-- 3 -->
<p :style="{ color }" @click="toggleColor">
This should be green, and should toggle between green and blue on click.
</p>
</template>
<style>
.red {
color: red;
}
</style>
Let's break down what is happening here; each paragraph listed above is denoted with a corresponding number:
-
In the first paragraph, we target the
'title'
property of the current HTML element.1. The
'title'
property is set equal to that of our referenced message in scripts.2. When the output is hovered, our message will display!
-
In the second paragraph, we are targeting the 'red' class property and we are setting it equal to the current value of
isRed
.1. On a click event the
toggleRed()
function determines atrue
orfalse
boolean.2. The state reference value
isRed
is assigned to thistrue
orfalse
boolean.3. When the boolean changes our render will dynamically react to this change; this is because the template is referencing
ref()
the state ofisRed
and will change dynamically when this state value is changed. -
In the third paragraph, we are targeting the 'style' property and we are setting it equal to the current value of
color
.1. On a click event the
toggleColor()
function determines a string value.2. The state reference value
color
is reassigned to this string value.3. Because our paragraph refers to the value of
color
, our paragraph styling property is reassigned the value ofcolor
.
How does Vue implement conditionals and loops?
Let's take our approach closer to the real-world, so that we can start understanding what the actual workflow would look like when we are working on our own. First, let's start by creating a template of everything we might want to render to the DOM.
Initializing a Component
<template>
<button>Toggle List</button>
<button>Push Number</button>
<button>Pop Number</button>
<button>Reverse List</button>
<ul>
<li></li>
</ul>
</template>
For now, we have created a few buttons that will be statically rendered to the DOM. We also have created an unordered list, but right now we don't know how long our list will be and we don't even know what we want it to display. At this point, we need to understand what our objectives are.
- The button
Toggle List
will hide our unordered list. - The button
Push Number
will add an item to our list. - The button
Pop Number
will remove an item from our list. - The button
Reverse List
should change the render, causing the list to be displayed in reverse. - Our unordered list needs to reflect a collection of items, and each item needs to be dynamically rendered to the DOM.
I think it is best that we start with displaying each item of our list, so that way we have a way to visualize the DOM before we start implementing scripts that will change what is rendered. In this case, we want our unordered list to have a new list entry for every item in a collection of data.
Adding references and looping through a collection
<script setup>
import { ref } from 'vue'
const list = ref([1, 2, 3])
</script>
<template>
<button>Toggle List</button>
<button>Push Number</button>
<button>Pop Number</button>
<button>Reverse List</button>
<ul>
<li v-for="listEntry of list">{{listEntry}}</li>
</ul>
</template>
Great, now we have established a reference to a collection within our scripts! Let's see if we can break down what we did here into something that we can understand.
- The constant variable
list
refers to a collection (array of numbers). - The list entry now has an attribute respective to the
v-for
directive. ######1. Thev-for
directive receives a collection, and iterates over every item it contains. ######2. As thev-for
directive is looking at the current item, it creates a new list entry and inserts the specified data there. ######3. In this case we are displaying the entire item in the collection, but that is okay because our collection is only primitive data types and not nested arrays or objects.
Now that we have a way to dynamically render these items, we can review the functionality of our buttons. We will start with the Toggle List
button for the time being. In this case, we want the display of our list to switch between two states 'shown' and 'hidden'. Because there are only two states, we can think of this as a true
or false
expression.
Adding to our Component states
<script setup>
import { ref } from 'vue'
const list = ref([1, 2, 3])
const show = ref(true)
</script>
<template>
<button @click="show = !show">Toggle List</button>
<button>Push Number</button>
<button>Pop Number</button>
<button>Reverse List</button>
<ul>
<li v-for="listEntry of list">{{listEntry}}</li>
</ul>
</template>
- First we declare a constant variable
show
in our scripts. It refers to a boolean value. - After we add this variable, we can use it for managing the state of content on our page.
- We attach a click event listener to the
Toggle List
button. On click, an expression is evaluated. This inverts the current value of theshow
variable.
We are close to implementing this functionality, but now we need to account for some edge conditions. What if our list is empty? What if our list is hidden, but it isn't empty? Our current design establishes a way to toggle whether something is rendered to the DOM, but there are no conditional expressions that rely on the state of the show variable. Let's fix that.
Adding conditional expressions to check our states
<script setup>
import { ref } from 'vue'
const list = ref([1, 2, 3])
const show = ref(true)
</script>
<template>
<button @click="show = !show">Toggle List</button>
<button>Push Number</button>
<button>Pop Number</button>
<button>Reverse List</button>
<ul v-if="show && list.length">
<li v-for="listEntry of list">{{listEntry}}</li>
</ul>
</template>
First, we have added a Vue directive known as v-if
to our unordered list. When the DOM attempts to render the list, it first checks the following conditions:
1. If the value of show
is true.
2. If the value of list.length
is above zero (a truthy value).
If either of these conditions fail, with our current implementation, it would refuse to render the list to the DOM. However, we want to be a bit clearer with our implementation. In this case, we want to expand our conditional expressions so that they will inform the user about the current state of the list.
1. If the list is hidden, but the list is not empty, then we want a message reflecting that.
2. If the list is empty (list.length === 0
), then we want a message reflecting that.
Other modifications to states
<script setup>
import { ref } from 'vue'
const list = ref([1, 2, 3])
const show = ref(true)
</script>
<template>
<button @click="show = !show">Toggle List</button>
<button>Push Number</button>
<button>Pop Number</button>
<button>Reverse List</button>
<ul v-if="show && list.length">
<li v-for="listEntry of list">{{listEntry}}</li>
</ul>
<p v-else-if="list.length">List is not empty, but hidden.</p>
<p v-else>List is empty.</p>
</template>
At this point, we should now have three conditions which are capable of informing the end-user about the state of the list that they are interacting with. This is great progress, but we still need to implement the rest of our buttons. You might notice that, in the previous examples, we are using the properties and methods native to the JavaScript Array prototype. Because we have this functionality, we can interact with our list in the same way.
Final version of our Component
<script setup>
import { ref } from 'vue'
const list = ref([1, 2, 3])
const show = ref(true)
</script>
<template>
<button @click="show = !show">Toggle List</button>
<button @click="list.push(list.length + 1)">Push Number</button>
<button @click="list.pop()">Pop Number</button>
<button @click="list.reverse()">Reverse List</button>
<ul v-if="show && list.length">
<li v-for="listEntry of list">{{listEntry}}</li>
</ul>
<p v-else-if="list.length">List is not empty, but hidden.</p>
<p v-else>List is empty.</p>
</template>
At this point, our DOM should have all of the functionality that we originally set out for it to have! This is what is so powerful about Vue; despite the fact that many similar frameworks and libraries can accomplish this, the approach with Vue feels more natural and developer-friendly.
In the beginning, we starting with a basic and static HTML page. We increased our scale slightly when we made our page somewhat dynamic; we added a reference to list and we also added a directive that helped dynamically render items from that list.
After we added this somewhat dynamic feature, we expanded upon it so that other items could change the state of the DOM. In this case, we increased our scale again as we began handling more states.
If we began increasing our scale further, such as in the case were the list reference pointed to data that is received from the server, then we already have a solid foundation that can be tweaked to reflect data appropriately.
How does Vue interact with other components?
So far, we have only looked at how an individual component can change what is rendered to the DOM. However the reality is that, in most cases, your components should be interacting with one another so that you can reuse them in other parts of the DOM. Let's take a look at an example with a simple component.
Scripts for our Component
<script setup>
import { ref } from 'vue'
import TodoItem from './TodoItem.vue'
const groceryList = ref([
{ id: 0, text: 'Vegetables' },
{ id: 1, text: 'Cheese' },
{ id: 2, text: 'Whatever else humans are supposed to eat' }
])
</script>
We import the ref()
function from Vue, but we are also importing the component TodoItem
so that we can use it inside of this component. Because subcomponents must be imported and implemented, this creates a separation of concerns.
In separations of concerns, the system's components are organized in a way where each component addresses a single concern; the concern could be simple or it could address a (larger) specific functionality for the DOM. This means that each component only interacts with other components when necessary; this is especially beneficial for ensuring that the overall state of our DOM is not affected when we only want changes to occur within a specific component's scope.
Before we move onto our template for this component, we should understand how the subcomponent that it has imported will work. After all, if we don't know what it is doing then we don't know how to use that component.
The TodoItem Component
<script setup>
const props = defineProps({
todo: Object
})
</script>
<template>
<li>{{ todo.text }}</li>
</template>
It looks like when this component is being setup, it is defining its own properties props
to include a key todo
that will be assigned to the value of an object. In this case, the properties are looking back to see which data was passed to it as an attribute. Specifically, it is looking for an attribute name todo
and it is expecting it to be an Object instance. More documentation on the defineProps()
function can be found here.
After the object has been received, the TodoItem
component tries to render the text
property from the object that has been passed into it. If we have passed the values to it properly, then this should render whatever the value of the text
property is for that object. Now we can take a look at how our main App
component will try to use the TodoItem
component when it renders.
Our template references the TodoItem Component
<template>
<ol>
<TodoItem
v-for="item in groceryList"
:todo="item"
:key="item.id"
></TodoItem>
</ol>
</template>
Inside of our template we are using the Vue directive v-for
to iterate through the groceryList
collection, which is an array of objects. However, in this case, we are referencing the component TodoItem
which we imported earlier. In this case, we are saying the following:
- For each
item
(object) ingroceryList
(array), pass the item to theTodoItem
component. -
TodoItem
receives two attributes during each iteration:1. The
todo
attribute stores the item (object).2. The
key
attribute is used to create a unique 'key' for each item. We expect that, for every item in our collection, the
TodoItem
component will return something to be rendered to the DOM.
Conclusion
I hope that you found this introduction to Vue somewhat helpful, it was a pleasure to research into how this framework can be used to make developers more efficient and effective. If you are familiar with similar frameworks and libraries, you might still be wondering whether or not Vue is something that you would want to use for your own projects. If you feel that way, I recommend that you read through Vue's FAQ to see if its benefits fit the needs of your team, project, or organization.
Is the knowledge of the Vue framework in demand?
According to the 2023 StackOverflow Developer Survey, Vue ranked eighth for one of the most popular web frameworks and technologies at 16.38%. In comparison, similar frameworks and libraries such as React ranked second at 40.58% whereas Angular ranked fifth at 17.46%.
Who uses the Vue framework?
from the Vue website
Vue is one of the most widely used JavaScript frameworks in production today, with over 1.5 million users worldwide. It is downloaded approximately 10 million times a month on Node Package Manager (NPM)!
- Wikimedia Foundation
- National Aeronautics and Space Administration (NASA)
- Apple
- Microsoft
- GitLab
- Zoom
- Tencent
- Bilibili
- Kuaishou
Top comments (0)