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.
*the only requirements for this tutorial would be the basics of HTML, CSS, Javascript and basic usage of the terminal
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 the following way:
npm install -g @vue/cli
vue create my-converter
DAYUMN! You have just created the foundation for your app! And we’re just getting started…
Go to the newly created folder (my-converter in our case), 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:
The pre-generated stuff in your app. We will completely replace this with our own code later on.
Keep your browser open. We’re about to start coding, my friend!
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 folder where you’ll be coding is the src folder. Notice the files with the .vue extension. Those are Single-File-Components. Components are fragments of your app responsible for a single task. The philosophy behind it is _divide and conque_r — 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 CSSThat means, all three things are neatly bundled in a single .vue file. The starting point of your app is the App.vue component. 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.
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:
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.
Starting off with the <template>
part: create a
<template>
MUST have just onechild element. Now create three elements for length, time and temperature respectively.
<template>
<div id="nav">
<a> Length </a>
<a> Temperature </a>
<a> Time </a>
</div>
</template>
<script>
</script>
<style scoped>
</style>
Navbar.vue
Moving on to the script tag to write some javascript. Write this inside the script tag:
<script>
export default {
name:'Navbar',
data(){
return{
len : "Length",
temp : "Temperature",
time : "Time"
}
},
methods:{
/* no methods yet */
}
}
</script>
(script) Navbar.vue
data()
is a function which returns a plain javascript object where you declare your component’s variables. We have declared len, temp, time
and instead let’s replace the hardcoded text in the elements with the respective variables, like this:
<template>
<div id="nav">
<a> {{len}} </a>
<a> {{temp}} </a>
<a> {{time}} </a>
</div>
</template>
If we were to change the value of len
e.g by triggering a function which does it, the displayed text would live update accordingly. 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 3 separate tags, let’s declare an array of physical quantities and dynamically display tags accordingly. Inside data()
, create an array called quantities
. Also, we won’t use strings like “Length”. Instead, the array will contain objects. An object will represent a physical quantity and contain its name and units. 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? Remove those 3 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 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. The phenomenon of clicking the button would be an event and what we are doing here is called event handling . Here in our case: when the user clicks on one of the tags, we emit a custom event called'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 right 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.
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 store 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 e.g. 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:
<template>
<div id="app">
<Navbar @select-quantity="chosenQuantity=$event"/>
<Converter v-bind:physicalQuantity="chosenQuantity"/>
</div>
</template>
<script>
import Navbar from './components/Navbar.vue' /* import some other components */
import Converter from './components/Converter.vue'
export default {
name: 'app',
components: { /* list all other components which we use inside this component */
Converter,
Navbar
},
data: function(){
return{
chosenQuantity: {name:"Time",id:2, units:["s","min","h"]} /* the currently chosen quantity. Per default, the chosen quantity is TIME */
}
}
}
</script>
<!-- some CSS styling. There is no "scoped" attribute, so this styling applies to the whole app -->
<style>
body{
margin:0;
font-family:"Source Sans Pro";
}
#app{
display:flex;
}
</style>
App.vue
Before we move on to the last component, take a look at App.vue again. In Navbar.vue we click on an 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"/>
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 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:
<script>
export default {
name: 'Converter',
props: {
physicalQuantity: Object // props is basically just data passed from a parent to a child component. App.vue is our parent here and it passes an Object to this variable
},
data: function(){
return{
fromValue:1,
fromUnit:"",
resultUnit:""
}
},
}
</script>
Converter.vue
Alrighty, we have now sucessfully passed the currently chosen quantity to Navbar.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 the variables fromValue, fromUnit, resultUnit
which respectively stand for the value, the unit we are converting FROM and the unit we are converting TO.
We want to display the name of the currently selected physical quantity. We can do that using interpolation : {{physicalQuantity.name}}
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">
We want to create dropdown select 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
in the first case orresultUnit
in the second case. For that, we will create a basic HTML
<-- 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>
Now, let’s implement the actual logic for the computation of the result. In order to reduce complexity a little bit, 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.
Right after data()
, declare the functions (methods) for converting to intermediary units in our Converter.vue component:
<script>
...
data(){
...
},
methods:{
toMinutes: function(value,unit){ // converts a time value to its corresponding value in minutes
switch(unit){
case("s"):
return value/60;
case("min"):
return value;
case("h"):
return value*60;
default:
console.log("toMinutes conversion failed - unit incorrect")
return value;
}
},
toMeters: function(value,unit){
...
},
toCelsius: function(value,unit){
--.
}
}
...
</script>
(methods)Converter.vue
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:
<script>
...
computed: {
result: function(){
let value = parseFloat(this.fromValue); // convert input to a floating point number
if(isFinite(value)){ // check if the user really typed in a number (if not, then isFinite returns false)
switch(this.physicalQuantity.name){ // check in which physicalQuantity we are
case("Time"): {
/* ------------T I M E-------------*/
let valueInMinutes = this.toMinutes(value,this.fromUnit); // we use "minutes" as an intermediary unit
switch(this.resultUnit){
case("s"):
return parseFloat((valueInMinutes*60).toFixed(5)); // limit to 5 decimals and parseFloat() it to remove redundant 0s
case("min"):
return parseFloat((valueInMinutes).toFixed(5));
case("h"):
return parseFloat((valueInMinutes/60).toFixed(5));
default:
console.log("Error while converting time - resultUnit not detected!");
return "...";
}
}
case("Length"): {
...
}
case("Temperature"): {
...
}
}
}
return "..."; // if the user didn't type in a number
}
}
...
<script>
(computed)Converter.vue
Looking good! Whenever one of the dependency values (e.g. fromValue
) changes, the value of result
will be updated 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
<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!
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 manner understandable by almost anyone. 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!
Recommended Courses:
☞ Learn by Doing: Vue JS 2.0 the Right Way
☞ Vue.js 2 Essentials: Build Your First Vue App
☞ Getting started with Vuejs for development
☞ Horizontal Feed Component with Sass and VueJs 2
☞ Learn Vue 1 JS introduction to simple reactive JavaScript
☞ What To Learn To Become a Python Backend Developer
☞ Build a NOTES APP with Vue JS and Nhost using GraphQL & Tailwind CSS
☞ 40+ Online Tools & Resources For Web Developers & Designers
☞ Ecommerce Furniture App UI Design - Flutter UI - Speed Code