DEV Community

Cover image for Getting Started with Vue
Thomas Lombart
Thomas Lombart

Posted on • Updated on • Originally published at thomlom.dev

Getting Started with Vue

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>
Enter fullscreen mode Exit fullscreen mode
new Vue({
  el: "#app",
  data: {
    name: "James Bond",
  },
});
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
new Vue({
  el: "#app",
  data: {
    placeholder: "James Bond",
  },
});
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
new Vue({
  el: "#app",
  data: {
    admin: false,
  },
});
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
new Vue({
  el: "#app",
  data: {
    message: "Hello world!",
  },
  methods: {
    changeMessage() {
      this.message = "Hey everyone!";
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
new Vue({
  el: "#app",
  data: {
    message: "Hello World",
  },
});
Enter fullscreen mode Exit fullscreen mode

Here's what happens behind the scenes when you use v-model:

  1. The input is bound to the property using v-model (which makes two-way binding happen)
  2. The input takes the initial value of message, which is Hello World.
  3. You input something, let’s say Hey everyone!
  4. Whenever the input changes, an input event is sent back to the Vue instance.
  5. Vue changes the message property.
  6. As message changed and it's a reactive property, the view updates and the changes have been reflected to your elements. In other words, the p tag contains the new value of message

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" />
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
new Vue({
  el: "#app",
  data: {
    things: ["Piano", "Car", "House"],
  },
});
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>",
});
Enter fullscreen mode Exit fullscreen mode

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 of props 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>
Enter fullscreen mode Exit fullscreen mode
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",
});
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
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);
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

Here is what happens when you click on the button whose value is Send a message:

  1. As the child has a click listener, the send method is triggered
  2. In send, the child emits a send event to the parent and transmits the string Hello!
  3. The parent receives the send event from the child. The alertMessage method is triggered.
  4. in alertMessage, we call the alert function and display the child's message, which is Hello!

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>
Enter fullscreen mode Exit fullscreen mode
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;
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

Here it is! You now have a basic app built with Vue. It's just the beginning but trust me, Vue and its ecosystem has 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.

What about Vue 3

What you learned above corresponds to Vue 2's API. Maybe you heard about Vue 3, and you're wondering whether what you're learning is worth it or not. Don't worry, Vue 3's API is backward compatible with Vue 2!

Discussion (0)