Let’s just get straight to the point, without philosophizing about Vue.js and making vague statements about its concepts, powers, scalability and blah blah blah. The fact is: you want to learn Vue.js now and you want to see it in action. Understanding the underlying philosophy of a development tool is a necessity for every wise software developer, but starting off by reading a bunch of theory doesn’t really ignite a fire of motivation. Obtaining some intuition beforehand does though. The idea of this article is to help beginners quickly grasp the basic Vue.js concepts “on-the-go” while building an actual app, while experienced developers may use it as a cheat-sheet or to revise their knowledge.
Objectives of this tutorial:
- build a simple converter app
- learn how to start a new project using vue-cli
- provide a step-by-step explanation while minimizing relying on prerequired knowledge*
- explain all basic vue concepts such as components, directives, computed properties, props and see how to use them in our converter app
*the only requirements for this tutorial would be the basics of HTML, CSS, Javascript and basic usage of the terminal
1. Initializing a new project
First of all, install Node.js on your device. Node.js is a server-side platform on which your app will run, but you don’t need to know much about it for this tutorial. What we actually need is NPM, which gets installed alongside Node.js. NPM is a package manager — in other words, a program for downloading and managing modules (module = basically, a bundle of code files, a fragment of software ). We will use NPM to install vue-cli, a command-line interface for scaffolding and managing Vue.js apps. Now, open up your terminal and proceed with the following instructions:
- having installed Node.js, install vue-cli by running the following command:
npm install -g @vue/cli
- now, go the folder where you’d like to create your project and run the following command:
vue create my-converter
- for the sake of simplicity, choose the default preset
DAYUMN! You have just created the foundation for your app! And we’re just getting started…
Switch to the newly created folder in your terminal (cd vue-converter
on Windows), run the command npm run serve
and finally (don’t close the terminal), open http://localhost:8080/ in your favorite web browser. What you should see is the following:
Keep your browser open. We’re about to start coding, my friend!
2. Vue Components
Grab your favorite text editor (mine is Visual Studio Code) and open the folder of your newly created project. Check out the project strucutre.
The only relevant folder for this tutorial is the src folder and it’s generally the folder where you will be doing something 90% of the time. Notice the components folder and the files with the .vue extension. Those are Single-File-Components. Components are decoupled fragments of your app responsible for a single task. Every component may have its own variables, template, styling etc. In other words - components are the building bricks of your app. They are relatively isolated from each other, but Vue offers certain means of communication between them. There can be a hierarchy between them, too (one component may include some other).The philosophy behind it is divide and conquer — splitting your app into separate components enhances readability, maintanance and reusability.
The skeleton of every vue components consists of the following:
<template>
: it’s where you write your HTML<script>
: where you write your javascript<style>
: where you write your CSS
That means, all three things are neatly bundled in a single .vue file. The starting point of your app is the App.vue component. It will include and display all the other components. Let’s delete everything inside of it except the <template>
, <script>
and <style>
opening and closing tags.
Finally, we will start coding. A little hint before that : check out your browser again — the app has been updated (it’s blank) even though you didn’t refresh the page! DAYUMN! This happens thanks to something called hot-reloading.
3. Creating our components — navbar and converter
Take a look at the screenshot of our app (at the beginning of this article). In what logical components could we split up our app? It makes sense to have the following 3 components:
- Navbar — a component for the vertical navigation bar, where the user can pick his desired physical quantity (length, time, temperature)
- Converter — a component where the user can choose units and do the actual conversion
- App.vue — this one we already have and it’s pretty much obligatory. This will be the “boss” component, containing and synchronising the other two.
Let’s start! In the components folder, create two files: Navbar.vue and Converter.vue and write the empty <template>
, <script>
and <style>
tags inside them. We will start with coding the navbar.
3.1 Navbar.vue
Starting off with the <template>
part: create a <div> element which will be the parent element wrapping all of the other elements. To be more exact, every <template>
MUST have just one direct child element. Now create three <a> elements for length, time and temperature:
Moving on to the script tag to write some javascript. Write this inside the script tag:
data()
is a function which returns a plain javascript object where you declare your component’s variables. We have declared len, temp, time
. Replace the hardcoded text in the <a> elements with the respective variables: replace <a>Length</a>
with <a>{{len}}</a>
and so on. Your template-tag should now look like this:
<template>
<div id="nav">
<a> {{len}} </a>
<a> {{temp}} </a>
<a> {{time}} </a>
</div>
</template>
Take a look at your app in the browser: at first it seems as if nothing changed at all. You might wonder what advantage we got from doing. The crucial difference is, that the text values Length, Time and Temperature are not statically displayed anymore. They are dynamic — if we were to change the value of len
e.g. by triggering some function, the displayed text would be updated immediately! That’s called data binding or interpolation and that syntax with the curly braces is called “Mustache” syntax. DAYUMN!
Now we will make the code even more elegant: instead of having three separate<a> tags, let’s declare an array of physical quantities and dynamically display <a> tags accordingly. Inside data()
, create an array called quantities
. Also, we won’t directly use strings like “Length”. Instead, the array will contain objects. An object will represent a physical quantity and contain its name and units. The name will be the actual string which we will display. Proceed with making those changes. data()
should now look like this:
data(){
return{
quantities: [
{name:"Length", units:["mm","cm","m"]}, {name:"Temperature", units:["C","K","F"]}, {name:"Time", units:["s","min","h"]} ]
}
},
How are we going to display these? Of course, we could make three separate <a> tags again, but there is a more elegant generic solution. Remove those three <a> tags and replace them with the following:
<a v-for="quantity in quantities"
v-bind:key="quantity.name"
@click="$emit('select-quantity',quantity)" > {{quantity.name}}</a>
What’s new? The v-for
you see is called a directive. Directives are something like vue-specific attributes of HTML elements. Our v-for
iterates the quantities
array and generates an <a> tag for every element inside the array , displaying its name attribute : {{quantity.name}}
The elements need to be uniquely identifiable. That’s what v-bind:key
is for.
What about @click="$emit('select-quantity', quantity)"
? Obviously, when the user clicks on e.g. Length, we need to let the other components know what the user has clicked on. We will do that using custom events — one of the basic means of communication between vue components. Here in our case: when the user clicks on one of the <a> tags, we emit a custom event which we named 'select-quantity'
and pass the corresponding physical quantity object. That event will be caught and reacted to in the App.vue component later on. But for now, spice the Navbar.vue component up with some CSS and you’re done.
Full code of the Navbar.vue component can be found HERE.
App.vue
We have created the Navbar.vue component. Now we will import it to App.vue and actually display it. We will also import and display the yet-to-be-implemented Converter.vue component. Also, App.vue will contain a variable called chosenQuantity
which will represent the currently chosen physical quantity. That variable should change every time the user clicks a different button in the navbar — that means, every time the previously created custom event 'select-quantity'
is emitted by the Navbar.vue component. Here’s how the code for all of that looks like:
3.2 Converter.vue
Before we move on to the last component, take a look at App.vue again. In Navbar.vue we click on an <a> tag and that click changes the chosenQuantity
variable in App.vue. Now we need to pass that variable from App.vue to Converter.vue . This line does the job:
<Converter v-bind:physicalQuantity="chosenQuantity"/>
In that line, we have added the Converter.vue component to our app and passed it the variable physicalQuantity
. This is something called props. We pass the chosenQuantity
variable to a props variable called physicalQuantity
(yet to be defined in Converter.vue) from the parent to the child component. That’s the basic mechanism of parent-child communication. The other way around (child parent) is done using custom events, and we have already seen an example of that when we were emitting that 'select-quantity'
event from Navbar.vue to App.vue. Moving on to Converter.vue:
Alrighty, we have now sucessfully passed the currently chosen quantity to Converter.vue and recieved it as a props called physicalQuantity
. The expected type of physicalQuantity
is Object
because, if you recall, in Navbar.vue we represented a physical quantity as a javascript object, containing the name and its units.
What else is new? We have declared the variables fromValue, fromUnit, resultUnit
which respectively stand for the value, the unit we are converting FROM and the unit we are converting TO.
Display name of currently selected physical quantity
We want to display the name of the currently selected physical quantity. We can do that using a <h1> element and interpolation :
<h1> {{physicalQuantity.name}} </h1>
Value to be converted
We want to create an input box, where the user can type in the desired value. This will determine the value of the fromValue
variable. We can do that using the v-model
directive, which will bind the fromValue
variable to whatever the user types in and update its value accordingly:
<input type="text" v-model="fromValue">
Choosing between units
We want to create drop-down menus for picking the from-unit and the to-unit. When the user selects a unit, we need to bind the selection to the fromUnit
variable in the first case or resultUnit
in the second case. For that, we will create a basic HTML <select> element and using the v-for
directive, we will generate possible selection options (<option> elements ) from the units
array from physicalQuantity
:
<-- UNIT TO CONVERT FORM -->
<select v-model="fromUnit">
<option v-for="unit in physicalQuantity.units" v-bind:key="unit"> {{unit}}
</option>
</select><-- UNIT TO CONVERT TO -->
<select v-model="resultUnit">
<option v-for="unit in physicalQuantity.units" v-bind:key="unit"> {{unit}}
</option>
</select>
Display the result
Now, let’s implement the actual logic for the computation of the result. In order to reduce logic complexity, I have decided on the following: For each physical quantity, let there be an “intermediary” unit. All values will be converted to that intermediary unit and then converted from the intermediary unit to the desired result unit. For example, if our intermediary unit for time is minutes(min), then, when converting seconds to hours, we convert seconds to minutes, then minutes to hours. This applies to every other possible case as well.
Right after data()
, declare the functions (methods) for converting to intermediary units in our Converter.vue component:
And finally, we are going to calculate the actual result. Let’s store the result in a variable called result
. Notice that this isn’t an ordinary value — it’s a value which depends on other values. In our case, result
depends on the fromValue
the user types in, the chosen fromUnit
and resultUnit
. In other words, result
is a variable which will be the result of a computation. That’s why we will declare result
as a computed property and we will implement the logic for the computation right away:
Looking good! Whenever one of the dependency values (e.g. fromValue
) changes, the value of result
will be updated accordingly right away! The only thing that remains is to actually display result
in our template-part of the component. Let’s put it between the <select> elements:
<p id="result">
{{result}}
</p>
Spice it all up with some nice CSS (which you can check out HERE in the whole Converter.vue file) and you have finally successfully implemented your own Vue.js converter app! DAYUMN!
Objective (hopefully) accomplished!
Thank you for taking the time to read this tutorial. My objective was to fill a gap in teh interwebz by publishing a straightforward hands-on Vue.js tutorial and provide an explanation of some basic Vue concepts in a straightforward manner. The idea of this article was to give you a quick and efficient head start — for advanced Vue.js concepts and more in-detail explanations, the official documentation would definetly be the best learning source!
If you feel like this tutorial has helped you, I will appreciate thankfulness from your side, too, which you can express by giving this article a “clap” or by leaving some feedback in the comments!