Getting started with Vue.js for complete beginners.

This post covers everything we learned from Fresh Friday at 01/03/2019 in Clockwork, if you’re not in our meetup group yet please join us on Meetup!.
The content is different, but you can find the exercises Wimbarelds went through over here, the post goes through all the features we covered, but in a different way 😁.


Vue is a progressive javascript framework that is performant and versatile.
Let’s understand what all this gibberish means 🤯.

Progressive: Means that we can progressively (steadily; in stages.) opt into, that is you can convert existing projects to Vue in steps, and don’t have to do a complete rewrite to existing projects.

Javascript framework: Javascript frameworks are very popular lately, but the exact definition for a software framework is open for interpretation, so I will use the dictionary definition: “a basic structure underlying a system, concept, or text.”, basically, it means that we are building our application on top of Vue’s foundations, It will provide us with different tools and abstractions to build our application.

Performant: Vue is very performant, it applies changes using a simple reactivity model, uses well-defined web standards and utilizes a virtual dom — A virtual dom is usually a javascript object that defines how the dom looks, Vue will check the new virtual dom after each change and decide if the changes need to be rendered by inspecting the last virtual dom, and rendering is one of the most memory and time-consuming works that the browser does.

Versatile: Vue has a massive ecosystem and can be used either as a small framework for building simple UI, or as a full blown framework (like Angular) that handles pretty much everything for us.

What problem does Vue solve for us?

As with any modern javascript framework (React/Angular/Ember/polymer, etc…), Vue’s main purpose is to allow us to build UI using components — components are units of code that we can control their scope — where and when they should be rendered and what each of them should do, to explain what components are, it’s easier to use an example.

We will get into every aspect later, but in the following code pen, you can see that we have included Vue from a CDN, and we create a Vue instance on an HTML element, this is a single Vue component. 
This component is independent, and when we click the button, Vue is the one binding the event for us, then we increment a counter and Vue recalculates a “fullMessage” variable, and display it, this is a good example of vue’s reactivity model.

Let’s start by analyzing what we see in this code pen, other than including the Vue script from CDN, we need to create a component for Vue to bind to, here Vue binds the element with the id “app”, and I assigned a `v-on:click=”clickme”` property to the element, this is the way we do data binding in Vue, it also has a shorthand written like this `@click=”clickme”`.
The next thing we can see is the template syntax ({{text}}), it binds our text to the HTML.

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<h3>Try to click this button</h3>
<button v-on:click="clickme">
{{ fullMessage }}
</button>
</div>

Now let’s take a look at the javascript part, the script we loaded gave us a global Vue function, this is called the Vue instance, and we can create components from it, we are creating a component named app, and pass some configuration to is.
The configuration object we pass to the component includes these properties:

el: An element to bind the component to, or an element selector.

data: An object, or a function that returns an object, we usually use a function since we want our components to be independent and isolated from one another, every property passed to data will be bound to the component when it’s created.

methods: An object that defines what methods our component will have, in our case we have a method named clickme, which access the counter variable we defined in the data function and increments it.

computed: Computed variables are very powerful in Vue, look at it, it defines a function called fullMessage, this function is a getter for a variable named fullMessage, and it is recalculated whenever the counter changes to produce a completely new variable.

watch: Watch is an object that contains watcher functions, those functions can be triggered whenever a property is changed, and it will get the new and old value of the changed property (check the console when playing with the pen).

Building an app with vue-cli

The example we saw was very nice, but it’s not so comfortable to work like that, especially if we want to scale up into a project that contains thousands of lines of code.
We are going to build a cat posts app, to see some posts from a given API, and create new posts, we will use json place holder (mock rest API) and cat as a service (random cat images) to build a small fun project.
You can check the app repository for the full code here.

In order to make the development easier and faster, the Vue team have created a tool named vue-cli, it is a CLI tool that allows us to bootstrap a new Vue project, complete with tools to help us start fast such as webpack, eslint, babel, preprocessors, autoprefixer, and the vue-loader.
vue-cli also allows us to install different plugins for different things, tests, typescript support and more.

To get started we can use npm or yarn:

npm install -g @vue/cli
# OR
yarn global add @vue/cli

Now let’s create a new project, Vue will ask you to pick a preset, you can customize it in a lot of ways, but those will not be covered in this article, just use the default and press enter.

vue create cat-posts
? Please pick a preset:
❯ default (babel, eslint)

Vue generated this file structure for us:

The main files and directories we are currently interested in are:

src: where we are going to write all of our code, components, logic, and routing.

src/components: where our components will be.

src/App.vue: Our main Vue component, it will hold the entire app, every component we will build will be a child of this component.

src/main.js: This is our entry point, it will set up App.vue and will register plugins, extensions and more for Vue.

Understanding .vue files

.vue is Vue’s file extension, vue-cli already set up vue-loader for us, and it will process each .vue file and optimize it for us.

Vue should have installed all the dependencies for us, we need to start a development server to view our web app, the development server will update whenever we change our code without a need for us to refresh the browser (often called hot-reloading), it makes development much easier.

cd cat-posts
npm run serve

Let’s start by deleting src/components/HelloWorld.vue, since we are not going to need it, and replace the content of src/App.vue with:

As you can see, a vue file in made out of 3 parts:

template: The template section contains the template for our component, just as we did before in the code pen, we can use text interpolation ({{}}) to show a message in the HTML.

script: The script is where our component logic lives, we need to export a component options object like we did when calling new Vue in the code pen.

style: A regular CSS stylesheet, Vue allows us to add a “scoped” attribute to it, this lets us scope the CSS to this specific component, if other components will use the “app” class, it will not work for them unless they implement it too.

Our application should have updated automatically, you can inspect the element to understand how Vue scoping works, as you can see every element inside the component will receive a special id, the id is prefixed with data-v-<id> for two reasons:

  1. data- is a web standard defined so developers will not run over possible existing attributes.
  2. -v- Is used so Vue will not collide with other libraries that do dom manipulations using the data attributes.
<div data-v-7ba5bd90 class="app">
Hello Vue!
</div>

And our CSS file changed too, our class is now scoped to elements that have the corresponding data attributes.

.app[data-v-7ba5bd90] {
color: red;
}

This is why we shouldn’t be afraid to style by tag or give very short names to the classes, we also don’t need BEM or modules, vue covers all of that for us!
That being said, if you want to have global styles, you should use BEM or a similar method, so writing this kind of code is totally ok thanks to the scoping mechanism of vue:

<style scoped>
form {
color: red;
}
div {
padding: 10px;
}
</style>

Let’s start coding!

Now that we know what .vue files are, we can start by building a file that fetches some data and renders it on the page, here we will learn about the component lifecycle, loops, and conditionals.

Look at the code, and we will analyze it below (and later we will refactor it to make it cleaner):

We can see multiple new things, let’s understand what each of those means:

Lifecycle Hooks

We can see in our script section a new function “mounted”, this function is being called by Vue whenever the component is connected to the view and is ready to render new information to the HTML, Vue has a bunch of lifecycle hooks, the schema from the official Vue tutorial explains it wonderfully (that image below).
The most used ones are:

created: The component is created but is not yet ready to render.

mounted: The component is ready to render, this is where we might register events like on window resize/scroll, listening to WebSocket events, etc.. in most cases Vue will handle it for us, or we will handle it in a store (we will get to it in the next article).

beforeDestroy: The component is about to be destroyed and we can do something before that happens, usually we will unregister events.

https://vuejs.org/v2/guide/instance.html

Data binding

We can bind an attribute by using either the : syntax like :src, or the v-bind: syntax like v-bind:src.
As you can see, Vue will run the javascript code inside, I do a ternary operation so every even post gets a gif and every odd gets an image, I also pass the post id as a query param, this does nothing for the cats API but it prevents the browser from caching and returning the same image every time.

<img :src="post.id % 2 === 0 ? `https://cataas.com/cat/gif?id=${post.id}`: `https://cataas.com/cat?id=${post.id}`"

width="100px" height="100px" alt="Cat">

We can also do the binding using a variable from the component, let’s say our component has a variable named “myImage” in his data, this would work:

<img :src="myImage">

We can also do string interpolation as we have seen earlier:

{{errorMessage}}

Or we can do two-way data binding, so we can bind a variable from data to an input using v-model, we will see a good example for this later when we will discuss forms.

<input type="text" v-model="message">

Conditional Rendering

Conditionals play a big role in any framework, for example in our template:

<div v-if="isLoading">
Loading...
</div>

<div v-else>
<div v-if="errorMessage">
{{errorMessage}}
</div>

<div v-else class="list">
...
</div>
</div>

We use v-if as an if statement: if we are currently loading (isLoading is true), render the loader.
And we use the v-else as an else statement: if we are not loading (isLoading is false), render the content.
We can also nest those inside one another: if we are not loading, check if we have an errorMessage, and if so, show it, else, show the list.
There is also v-else-if so we can also write it as:

<div v-if="isLoading">
Loading...
</div>


<div v-else-if="errorMessage">
{{errorMessage}}
</div>

<div v-else class="list">
...
</div>

v-if is used for conditional rendering, but we can do conditional display using v-show, the HTML will still exist in the show tree, but it will be invisible.

<div v-show="shouldShow">now you see me<div>
<div v-show="!shouldShow">now you don't<div>

Loops

Loops are pretty simple, think of them as a for each statement, we can loop over “post in posts” and we get post as a variable we can use, every loop in Vue requires a key attribute, this helps Vue optimize the virtual dom inside the loop, so I use post.id for it.

<div v-for="post in posts" :key="post.id" class="post">
<h4>{{post.title}}</h4>
<p>{{post.body}}</p>
</div>

Loops can also return an index:

<div v-for="(post, index) in posts">

And we can also loop over objects:

<div v-for="(value, key, index) in object">

Reusable components

Let’s clean up our code by separating it, we can separate some of it easily to a Post component, it will make our template simpler and more readable.
Create a new file in components, and call it Post.vue.

See that I replaced the big ternary I used in the image before, I turned it into a computed property, that way it is easier to read and it is more performant.
Separating the components into smaller building blocks makes them simpler to read, use and test, and that makes them less error-prone.

Props

Props are probably the most important tool for reusable components, as you can see in Post.vue, we can now pass a post object, and the component can use it, we defined post as an Object, and it is required — if no post is passed to the component, Vue will throw errors, and the validator function will make sure all the required properties exist on the post.

props: {
post: {
type: Object,
required: true,
validator: (post) => post.title && post.id && post.body
}
},

We can also use props as an array if we don’t want to specify their type:

props: ['post', 'id', 'someOtherproperty']

Or we can use props as simple types without specifying more than that, we can also give them a default value using a function.

props: {
title: {
type: String,
default: function () {
return 'hello';
}
},
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object
}

It is a good practice to be as verbose as you can when specifying props, props also work great with TypeScript interfaces as types, but I will not cover it here.

Component registration

Vue allows us to register components in two ways, we can either register a children components for each component, or register them globally, registering components globally is problematic for testing, but it’s ok when it’s done by plugins.

Let’s first take a look at how we can register and use a simple component, this is our new App.vue file.

As you can see we have imported the Post component and registered it by the name of ‘app-post’, you can register it under any name you like, but it’s considered a good practice to use some prefix like app-, you will also see most libraries using the v- prefix (for example, Vuetify uses it like so: </v-btn>).

import Post from './components/Post';

export default {
name: 'app',
components: {
'app-post': Post
},
...

And we can use it in our template, we simply pass the post prop as we did with any other attribute.

<div v-else class="list">

<app-post v-for="post in posts" :key="post.id" :post="post"></app-post>

</div>

Vue is very smart when it comes to registering components, we can pass a component as an object, or as a function that returns a Promise, this is very useful for lazy loading — it allows us to scale our Vue application almost infinitely without compromising performance and page load times, we will see how to do so later.
Registering a lazy component is as easy as changing our import statement to:

// a function that returns a promise
const
Post = () => import('./components/Post');

Webpack is the one that converts this import statement into a promise, it will create another file which we can download later, this allows our application to keep a smaller footprint when the client uses it, it’s usually a good practice to chunk either very big components (like a component that might use phaser or d3 internally), or every route component (we will cover it in the next article). we can also give our chunk file a name, it will make it much easier to debug:

const Post = () => import(/*webpackChunkName: 'my-component-name'*/ './components/Post');

We can also register the component globally at main.js, this is what most Vue libraries that create components do, and we can do so like this:

import Post from './components/Post.vue';
Vue.component('app-post', Post);
# OR as a lazy component
const Post = () => import('./components/Post');
Vue.component('app-post', Post);

Handling input

Let’s allow the user to add more posts, for that we will create a new component and call it PostForm, create a new file in components and name it PostForm.vue.
Let’s check out the code, I will explain it all under this gist:

As you can see I have some very strange lines on the form element:

<form @submit.prevent.stop="submit"
@keydown.enter.prevent.stop="submit">

These are called event modifiers, those are tools that allow us to apply extra logic to events, select specific keys when accepting keydown, or preventing default event behavior:

@submit.prevent.stop: We are listening to the submit event, we prevent the default behavior of it (which is submitting to a URL), and we stop the event from propagating.

@keydown.exact.enter.prevent.stop: We are listening to the keydown event, check that it’s exactly an Enter key event (shift+enter will allow you to drop a line), and prevent and stop it like with the submit.

For each of the events, we trigger the same method, so we can submit the form by clicking the submit button or pressing enter.

Our component has a data variable named post, it has a title and a body, we bind them to the input fields, so whenever the input fields change, our post is updated, it’s totally fine to bind to children of an object using the dot notation (obj.foo.bar.buzz).

<input v-model="post.title">
<textarea v-model="post.body">

And we can validate the form using HTML5 features, but we can also do this manually to get a nicer design, I created a variable named error that will hold the error if any exist, and we can validate the form before submitting, and if it is not valid we can just do nothing and let Vue’s reactivity model display the errors.

checkForm() {
const { post } = this;
    // resetting the error
this.error = { field: '', message: '' };
    if (!post.title) {
this.error = {
field: 'title',
message: 'This form requires a title'
};
}
    if (!post.body) {
this.error = {
field: 'body',
message: 'This form requires a body'
};
}
},
submit() {
this.checkForm();
if(this.error.field) {
return;
}
    this.$emit('post', {...this.post});
this.post.title = '';
this.post.body = '';
}

And then we can check it in our template and just show an error massage:

<div class="error-message" v-if="error.field === 'title'">{{error.message}}</div>

Custom events

As you might have seen, in our form component, in the method named “submit”, we have the following code:

this.$emit('post', {...this.post});
this.post.title = '';
this.post.body = '';

This code uses Vue’s $emit method, it emits an event to its parent component, we pass a name and we use the spread operator to copy our post object, and then we reset the form, here is a simpler example to help you understand:

this.$emit('my-event-name', 'Vue is awesome!');

In our App.vue, we need to add the PostForm component, and we can do it as we did with the Post component.

import Post from './components/Post';
import PostForm from './components/PostForm';

export default {
name: 'app',
components: {
'app-post': Post,
'app-post-form': PostForm
},
...

And we can use the component like this, we bind the post event that we emitted using the $emit method before, and call the addPost method whenever it happens.

<app-post-form @post="addPost"></app-post-form>

Now lets see the addPost method implementation, we accept the event, the event is exactly what we emitted, an object containing a title and a body, we give it an id using the length of the posts and we unshift it into the array (unshift is like push but to the start of the array).

addPost(event) {
event.id = this.posts.length + 1;
this.posts.unshift(event);
}

Styles and classes

The last subject I’m going to cover here is classes and styles, if we wish to conditionally give an element a class, You can bind classes with Vue and use regular classes at the same time, here is an example:

<div :class="{ 'my-class': myCondition }" class="my-other-class">
// OR with as an array
<div :class="['my-class']" class="my-other-class">
// OR combine them
<div :class="['my-class', { 'my-class-2': myCondition }]">
// OR from a data/computed variable
<div :class="myClasses">

Binding styles is very easy too, and has similar rules to binding classes:

// Pass a css object
<div :style="{ 'color': myColor}" style="font-size: 20px">
<div :style="{ 'color': '#BADA55'}">
<div :style="myStyle">
// OR as an array of css objects
<div :style="[ {'color': 'red'}, myStyle, { 'background': 'blue' } ]">

Summary

With that we are done, Vue is a very fun framework to work with and you should be able to build very large applications with ease, and we will build something bigger and nicer in the next article, we will also learn about different plugins and libraries.

If you want to join us, check out the open positions at https://clockwork.homerun.co/