Vue is this cool, popular and easy to learn UI framework. All you need to know to get started is HTML, CSS, and Javascript. So let's dig in and get started with learning how Vue works and building an application with VueJS. If you already know Vue and want to jump straight to the exercises, here is the link
An introduction
Vue is a progressive framework for building user interfaces. Progressive in this cases meaning that Vue both can exist in an existing solution as well as powering the whole website thanks to its rich ecosystem. Vue is focused on UI updates and leaves parts like routing and global state management out of the framework, but is easy to include if necessary.
When building an app in Vue, each page is split up into small reusable components that can be shared between components and pages.
When splitting up logic into smaller components, the code base becomes more manageable and also more testable. Each component has its own state, so if we would reuse a component in several places, changes to one component would not affect the others.
Vue utilizes a virtual DOM and can thereby decide when to best update the DOM and also perform asynchronous DOM updates. Which gives fast and optimized UI updates.
At the core of Vue.js, it's a system that enables us to declaratively render data to the DOM using straightforward template syntax. Consider the following example.
<div id="app">
{{ message }}
</div>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue'
}
})
Hello Vue
Now we have created our first app, even though its a very simple app. Vue does, however, do a lot under the hood and have now linked the DOM with our component data. Hence when changing our data, the view will also change, making Vue components reactive.
HTML, CSS and Javascript
The only requirements for learning Vue is HTML, CSS, and Javascript. This is also what each component consists of, split up into different parts. Each Vue component consists of:
script tag, defining Javascript
template tag, defining HTML
style tag, defining CSS
For example, this is a component that prints Hello Vue!, and as we can see nothing more than HTML, CSS, and Javascript.
<script>
export default {
name: 'app',
data: () => ({ message: 'Hello Vue!' }),
}
</script>
<template>
<div class="app" >
{{ message }}
</div>
</template>
<style scoped>
.app {
color: greeen;
}
</style>
This is an exportable component that can be used by any other component. Note the <style scoped>
, this is something that is included in Vue and makes the style scoped to the current component, leaving no other classes affected.
Vue instances
Every Vue application starts by creating a Vue instance with the function Vue
new Vue({
render: h => h(App),
}).$mount('#app')
This usually looks something like this in the main.js
file. Here we create our Vue instance and tell Vue that the root component is App, which is imported in main.js
. Then Vue will create a component tree of the App component and all its subcomponents and so on. When Vue has created the component tree and calculated its initial state, it will insert the component tree on the #app
element, usually a div element somewhere in the root HTML file.
Data
If we consider the root Vue instance, this instance needs to know when to perform an update on components in the component tree. This is where the data property comes in. The data property tells Vue which attributes that should trigger a rerender of that component.
How that works is that when Vue creates the component tree, it checks all the attributes in all the components data properties and creates getters and setters for each attribute. When one of these data attributes change, Vue will receive an event and can thereby trigger a rerender.
data: function() {
return { message: '' };
}
So in the above example, when the message changes, Vue will trigger a rerender of this component. Attributes in the data property are accessed directly under this, so in this case, message
could be altered with this.message
Methods
Methods are where we usually put logic regarding state changes of a component. Consider the following
<script>
export default {
name: 'app',
data: () => ({
clicks: 0,
}),
methods: {
onClick() {
this.clicks = this.clicks + 1;
},
},
}
</script>
<template>
<div>
<button @click="onClick">click me</button>
<div>
You clicked {{ clicks }} times!!
</div>
</div>
</template>
This simple component counts each click. When we click, we call the onClick method that updates the clicks data attribute of this component. When the clicks data variable updates, Vue will notice and perform a rerender of this component, then displaying the correct value of the state of this component.
Template syntax
Vue uses an HTML like templating syntax, which is powerful and removes most of the need for writing Javascript in the template. In the template, we write HTML, with some additional Vue directives and declaratively bind the rendered DOM elements with the Vue instance data.
The most basic type of data binding is the double brackets, to print data to the DOM
<div>
{{ message }}
</div>
Data binding
When we want to bind a certain piece of data to a component or element declaration in the template, we use the v-on directive.
<h1 v-on:title="title">
{{ message }}
</h1>
v-on
tells that title
is a javascript element, which should be located in the script tag of the component. The v-on
has a shorthand that is mostly used, :
<h1 :title="title">
{{ message }}
</h1>
Events
When we want to listen to a DOM event, like click, we listen to this with the v-on
vue directive as well. Vue has a different shorthand for events, @
<button v-on:click="actionOnClick">
click me
</button>
<!-- shorthand -->
<button @click="actionOnClick">
click me
</button>
v-if vs v-show
v-if
and v-show
are 2 different ways of deciding if elements should be shown in the UI. They have a key difference in that v-if
removes the element from the DOM when false, while v-show
set display:none
.
<div v-if="show" />
<div v-show="show" />
v-for
v-for
is used when iterating over elements in the template. Keys "must" be given, since its the key the Vue binds to the DOM to the element. Keys must be unique for that element and providing a nonunique key will result in faulty updates.
<div v-for="item in items" :key="item.id">
{{ item.name }}
</div>
Dont do this
<div v-for="(item, index) in items" :key="index">
{{ item.name }}
</div>
Since the index is not specific for the item but for the iteration, if the elements in the items are would change place, like when sorting or filtering, wrong elements would update.
Component communication
A page in a Vue application is built up of many small components in a component tree as we saw in the components section. Quite often we want to communicate between components in the component tree. There are 2 ways of communication, up and down. When we communicate down we send data down to the child components, this will in the child component be visible as props. When a child component wants to communicate to the parent component they emit an event.
Let's also explain by example
<script>
export default {
name: 'animals',
data: () => ({
animalList: ['dog', 'cat', 'horse']
selectedAnimal: '',
}),
methods: {
onSelect(animal) {
this.selectedAnimal = animal;
},
},
}
</script>
<template>
<div>
<dropdown :list="animalList" @selected="onSelect">
<div v-if="selectedAnimal">
You selected {{ selectedAnimal }}
</div>
</div>
</template>
First, we have an animal component, this component displays a dropdown and the selected value of that dropdown. We send the list we want the dropdown to display to that component and we also listen for the event selected
, for which we set the selectedAnimal data
property.
<script>
export default {
name: 'dropdown',
props: ['list'],
methods: {
onSelect(event) {
this.$emit('selected', event.target.value);
}
}
}
</script>
<template>
<select @change="onSelect">
<option v-for="item in list" :value="item" :key="item">{{item}}</option>
<select>
</template>
The dropdown component renders the list given to it by props and emits an event when a value in the dropdown is selected. This shows how data flows down to child components by props and how events can be emitted and listened to by parent components.
Computed property
Computed are getters in a component. The result of the getters are cached and will only be recalculated if the values that they depend on in the data property change. Computeds can be used both in the script tag and in the template tag.
computed: {
getMessage() {
return this.message.firstname + '' + this.message.lastname;
}
}
So first time this computed is used, the result will be cached and only be reevaluated if the message data attribute changes.
Computeds are also a good place to put Javascript code that would otherwise be placed in the template and something that the vue template directives don't cover. For example when we only want to iterate in the template over on part of an array.
computed: {
getFilteredArray() {
return this.array.filter(item => item.message === this.message);
}
}
Then we could just filter over the getFilteredArray
computed in the template instead of involving Javascript directly in the template.
Watch property
In the watch property, we can listen for changes in data, computed or props and when they change have a callback that triggers. Like
watch: {
message(value) {
this.doStuff();
}
}
When message changes, in this case, we will call doStuff.
Lifecycle events
Each instance of a component in the component tree has a life span, in short:
its created when its inserted into the DOM
it gets updated during the time it's in the DOM if the props or data changes
it gets destroyed when it should be removed from the DOM.
In a Vue component, we can listen to these events and when they occur hook on to those events and perform actions. For example, one lifecycle event is called mounted, it's triggered when the component instance is mounted in the DOM. This event will happen one time during the life span of each component instance and when this event happens, we can decide what to do when our component has mounted. For example:
mounted() {
this.fetchFromApi().then(res => this.resultFromApi = res);
}
The most commonly used lifecycle events are:
created, when the component is created and before it's inserted into the DOM
mounted, when the component is inserted into the DOM
updated, when the component will re-render
destroyed, when the component is destroyed
For a full example of when each lifecycle event is triggered, see the lifecycle diagram on vues docs.
Exercises
After reading this article, I hope you have got a good introduction to VueJS. I have created a series of exercises to try out VueJs and building a weather application. Please check out the exercises on my github.
Top comments (0)