Vue.js is a progressive framework created in 2014 by Evan You that allows you to build user interfaces. If you come from a React background, learning Vue will be easy. The concepts stay the same. But if you're used to pure JavaScript or jQuery, well, things are going to be way different here!
Indeed, it's a pain to manage the state in your applications. Vue solves this problem by bringing reactivity to your apps. What does that mean? Well, whenever something changes, your UI updates automatically. On top of that, you can split your app into pieces of code that are called components. The point of components is that it's easy to create, compose and reuse them.
Declarative rendering and first directive: v-bind
One of the great things you can do with Vue is to render data to the DOM (Document Object Model) in a simple way. You'll find below a first example of how to use reactive data with Vue:
<div id="app">
<p>My name is {{ name }}</p>
</div>
new Vue({
el: "#app",
data: {
name: "James Bond",
},
});
Wow. What happened here? What's data
? {{ name }}
? el
? These are legit questions, and I'll answer them right away.
If you look at the JavaScript code, you can see we created a new Vue instance (new Vue
). We specified where to mount this instance with the el
property, that is to say, in the div
whose id
is #app
. Finally, we provided a data
object to that instance. We set a name
property whose value is James Bond
.
Go back to the HTML file. You can see a p
tag containing My name is {{ name }}
. By using these double brackets, you told Vue:
"Do you see this name property that you have in your data? I want you to put its value in these brackets!"
And the magic happened. Vue, behind the scenes, did a lot of stuff and made your data reactive. It means that the changes are reflected immediately into the DOM whenever you modify the name
property. How cool is this?
Bind attributes
Vue can bind the attributes of your elements to your data properties. Binding means keeping your attributes up-to-date with your properties. You can do so using the directive v-bind:ATTRIBUTE
or with the shorthand :ATTRIBUTE
. Let's see an example of that:
<div id="app">
<input v-bind:placeholder="placeholder" />
</div>
new Vue({
el: "#app",
data: {
placeholder: "James Bond",
},
});
Conditional rendering: v-if
I bet you can guess what is the purpose of v-if
just with the name. It’s about conditional rendering: render elements based on a condition. As an example, you may want to render elements only if the user is an admin:
<div id="app">
<p>Hello World</p>
<p v-if="admin">You can see this sentence because you're an admin</p>
</div>
new Vue({
el: "#app",
data: {
admin: false,
},
});
On the example above, you have: You can see this sentence because you’re an admin
. If you were to use the app, you would only see this sentence because the condition passed to v-if
is true
(admin
).
Vue provides another conditional directive: v-else
. For instance, have you noticed how the navigation bar of certain websites changes when you’ve just logged in? You could imagine a login button and a register button replaced by a profile or account button. Well, that behavior is the perfect use case for v-if
and v-else
.
Events with v-on
That's a directive you will often use. Indeed, it allows you to attach event listeners to elements. These events, when triggered, will invoke methods of your Vue instance. You can use them by writing v-on:event="method"
or the shorthand @event="method"
.
If you come from a React background, this is similar to onClick
, onChange
, etc. There are similar events for Vue: @click
, @keyup
, @input
, etc.
Now you might think "Wait. What methods is he talking about?". In Vue, you can attach methods to your component by providing a methods
object to the Vue instance just like you do with data
. The advantage of using methods over regular JS functions is that methods have access to the data declared in your Vue instance. As you have access to the data, you can change your data
properties from your methods:
<div id="app">
<button @click="changeMessage">
Click on me to change the sentence below
</button>
<p>{{ message }}</p>
</div>
new Vue({
el: "#app",
data: {
message: "Hello world!",
},
methods: {
changeMessage() {
this.message = "Hey everyone!";
},
},
});
The new thing you discover here is the use of this
. Here, this
refers directly to the Vue instance. Thus, you can easily access your data properties from your methods using this.PROPERTY_NAME
. Here, we accessed and changed the message by assigning a new value to this.message
in changeMessage
method.
User input with v-model
You often need to get user input in an app. Lucky you! Vue's got your back on that one with v-model
. Indeed, you can use two-way binding with that directive. Two-way binding means:
- Whenever a model’s property changes, change the bound element.
- Whenever the bound element change, change the model’s property.
<div id="app">
<input v-model="message" />
<p>{{ message }}</p>
</div>
new Vue({
el: "#app",
data: {
message: "Hello World",
},
});
Here's what happens behind the scenes when you use v-model
:
- The
input
is bound to the property usingv-model
(which makes two-way binding happen) - The input takes the initial value of
message
, which isHello World
. - You input something, let’s say
Hey everyone!
- Whenever the input changes, an
input
event is sent back to the Vue instance. - Vue changes the
message
property. - As
message
changed and it's a reactive property, the view updates and the changes have been reflected to your elements. In other words, thep
tag contains the new value ofmessage
Did you know? v-model
is just syntactic sugar for :value
and @input
. The code below does the same as v-model
:
<input :value="message" @input="message = $event.target.value" />
What really happens is that whenever you change the input
, an event is dispatched to the Vue instance. This event contains a target
object, which refers to your input element. Therefore, you can access its value and modify the data
property. As :value
is bound to that data property, the changes are reflected. That’s not rocket science, is it? 🚀
Loops with v-for
When you're building an app, there's always a time when you want to render lists:
- Chat messages
- Search results
- Settings
- Cart items
- Etc.
Once again, Vue provides you another directive to deal with lists: v-for
.
You can use it with the following syntax: v-for="item in list"
. Here, list
refers to the array that you iterate over and item
is an alias for the array's element:
<div id="app">
<p>Things I want to buy:</p>
<ul>
<li v-for="thing in things">{{ thing }}</li>
</ul>
</div>
new Vue({
el: "#app",
data: {
things: ["Piano", "Car", "House"],
},
});
You can also provide a second argument to v-for
:
- For an array, the second argument will be the index of the array’s current element
- For an object, the second argument will be the key of the object’s current element
<li v-for="(thing, index) in things">{{ thing }}</li>
Components
So far, you saw Vue directives and reactivity only. But as mentioned previously, Vue also allows you to create components:
Vue.component("my-component", {
template: "<div>My component</div>",
});
You can create a new component with Vue.component
. The first parameter of that method is the component name (my-component
in our case). In contrast, the second is an object that defines your component. One property of this object is template
, which corresponds to your component’s HTML code. But there's also data
and methods
, in fact, nearly every property of a Vue instance since these components are Vue instances too!
Props
That’s where components are really interesting. When you compose components across your app, you will have parent components and child components. Therefore, it’s essential to have communication between both of the components. One way of doing it is via props
. They are used to communicate from the parent to the child.
Here is how to use props:
- On the child, set a
props
property. The value ofprops
is an array containing all the props the parent gave to the child. - On the parent’s template, give all the props needed into your component element
Note: you can also bind props if you need to pass data from your Vue instance.
<div id="app">
<person name="Jack" age="19" country="Australia"></person>
<person name="Emily" age="28" country="France"></person>
</div>
Vue.component("person", {
template: `
<div>
<p>{{ name }}</p>
<p>Hello my name is {{ name }} and I'm {{ age }}! I live in {{ country }}.</p>
</div>
`,
props: ["name", "age", "country"],
});
new Vue({
el: "#app",
});
Bypassing a props
property to our component, we passed data from the parent component to the child component.
Notes:
- You have to be exhaustive when you build your
props
array. If you forget just one prop, it won’t work. - As your template can grow, you have to use template strings to define a multi-line template.
- Always have a single root element when you define your templates. Otherwise, it won’t work too.
Custom events
We know how to communicate from parent to child components. Let's see the other way round. We can do it by using custom events. Just like props, we have to define one thing on the parent and one thing on the child:
- On the child, you have to use the
$emit
function. This function takes two parameters: the event name and the data you want to send to the parent (it can be an object, a string, an array, etc.) - On the parent's template, use
v-on
(or@
) to listen to the event your child will emit.
<div id="app">
<p>I'm the parent</p>
<child @send="alertMessage"></child>
</div>
Vue.component("child", {
template: `
<div>
<p>I'm the child</p>
<button @click="send">Send a message</button>
</div>
`,
methods: {
send() {
this.$emit("send", "Hello!");
},
},
});
new Vue({
el: "#app",
methods: {
alertMessage(message) {
alert("My child sent me a message, it says: " + message);
},
},
});
Here is what happens when you click on the button whose value is Send a message
:
- As the child has a
click
listener, thesend
method is triggered - In
send
, the child emits asend
event to the parent and transmits the stringHello!
- The parent receives the
send
event from the child. ThealertMessage
method is triggered. - in
alertMessage
, we call thealert
function and display the child's message, which isHello!
Recap by building a to-do app
Believe it or not, you are now ready to build a small app with what you saw above. You'll find below how you can build a to-do app with Vue:
<div id="app">
<p>What should I do today?</p>
<ul>
<todo-item v-for="todo in todos" :todo="todo" @toggle="toggle"></todo-item>
</ul>
<input
v-model="nextTodo"
@keyup.enter="addTodo"
placeholder="What's your next task?"
/>
</div>
Vue.component("todo-item", {
template: `
<li class="todo-item">
<input type="checkbox" @change="$emit('toggle', todo)" :checked="todo.done" />
<span class="todo-item-text" :class="{'todo-item-checked': todo.done}">{{ todo.name }}</span>
</li>
`,
props: ["todo"],
});
new Vue({
el: "#app",
data: {
todos: [
{ name: "Learn Vue.js", done: true },
{ name: "Build an app", done: false },
],
nextTodo: "",
},
methods: {
addTodo(event) {
this.todos.push({ name: this.nextTodo, done: false });
this.nextTodo = "";
},
toggle(todo) {
todo.done = !todo.done;
},
},
});
Here it is! You now have a basic app built with Vue. It's just the beginning but trust me, Vue and its ecosystem have much more to offer: computed properties and watchers, lifecycle hooks, slots, generating a project with Vue CLI, Routing with Vue Router or centralized store with Vuex.
Top comments (0)