DotNetCurry Logo

Introducing Vue.js

Posted by: Benjamin Jakobus , on 3/8/2017, in Category HTML5 & JavaScript
Views: 17688
Abstract: Vue.js an up-and-coming JavaScript library used to build web-interfaces. In this article, we will introduce you to the library, by building a small, single-page sample application. We will discuss how, why and when to use Vue.js, and introduce you to its elementary features. As such you will learn about templating, and how to develop components and directives to build interactive, performant user interfaces.

Vue.js, is an up-and-coming JavaScript library for developing web-interfaces. Released in 2013, Vue.js was inspired by AngularJS (AngularJS is one of the most popular JavaScript frameworks for developing modern web-applications), and as such borrows the framework’s templating syntax.

For those interested in how Vue js compares to Angular and React js, check VueJS vs Angular vs ReactJS with Demos.

Vue js – Getting started

Vue focuses on doing two things well: ease of use and rendering speed.

It excels in both: the library is extremely easy to learn and use, and beats both AngularJS and React when it comes to page rendering performance. As such, Vue.js feels almost like Angular’s fitter little brother as it shares the aspects done well, but at the same time is much lighter, more performant and less opinionated than AngularJS.

 

However being a library, as opposed to a framework, means that Vue.js does not offer the same amount of tools than AngularJS offers. For example, whilst Angular provides things such as a HTTP request service or router, Vue.js users will require to rely on third-party code if they wish to avail of such tools.

As Vue.js is gaining in popularity, it is becoming an important tool on any web developer’s toolbelt. Therefore this article sets out to explore Vue.js, introducing a Vue beginner to the library by building a sample demo application: SurfPics.

The hypothetical SurfPics website will allow surfers to display their various beach and surf videos and photographs.

In the first section of this article, we will outline the boilerplate code for this demo application. In the subsequent two sections we will then walk you through the development of the application, using Vue.js, introducing you to its various features.

vue-js-demo-app

Figure 1: Our demo page - built using Materialize.

Vue js Demo - Preparation

Before we can start diving into Vue.js, we must lay the groundwork for our demo application. To begin with, create a directory called src. This directory will contain our Vue.js application code. Inside this directory, create a folder called vue.

Inside the vue folder, create the following three, empty, files:

- index.html

- app.js

- app.css

Add the following styles to app.css:

#app {
    min-height: 460px;
}
.text-muted {
    color: lightgrey;
}
.search-box {
    margin-left: 1em;
    margin-top: -1em;
}

The above rules are fairly self-explanatory: they will set the colours, margins and minimum height for our application.

As this article does not concern itself with the intricacies of markup and CSS styles, you can safely ignore these boilerplate rules once you have added them to the application’s CSS file.

The index.html file contains the skeleton for our sample application:


<html>
    <head>
        <title>SurfPics</title>
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/css/materialize.min.css">
        <link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
        <link rel="stylesheet" href="app.css">
    </head>
    <body>
        <nav>
            <div class="nav-wrapper">
                <a href="#" class="brand-logo">SurfPics</a>
                <ul id="nav-mobile" class="right hide-on-med-and-down">
                    <li class="active"><a href="index.html">Home</a></li>
                    <li><a href="foo.html">Foo</a></li>
                    <li><a href="bar.html">Bar</a></li>
                </ul>
            </div>
        </nav>
        <div id="app">
            <!-- App content goes here -->
        </div>

        <footer class="page-footer">
            <div class="footer-copyright">
                <div class="container">
                    © 2017 Copyright SurfPics
                </div>
            </div>
        </footer>
        <a href="http://app.js">http://app.js</a>
        <a href="https://code.jquery.com/jquery-2.1.1.min.js">https://code.jquery.com/jquery-2.1.1.min.js</a>
        <a href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/js/materialize.min.js">https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/js/materialize.min.js</a>
    </body>
</html>

Again, the above markup is very straightforward and self-explanatory: We created a page containing a navbar and a footer, and included the relevant dependencies (jQuery and materialize). As per best-practices, JavaScript files are loaded at the bottom of the page (as opposed to the top, which hampers download parallelisation and may give the impression of poor page load times).

Note the third party dependency aside from jQuery: Materialize.

Materialize is “a modern responsive front-end framework based on Material Design” (http://materializecss.com/), and we will be using it to style our demo application (“Material Design” refers to a set of visual design guidelines created by Google). The framework provides some slick styling, and is essentially the Bootstrap equivalent for Material Design lovers.

Building a page using Vue.js

The demo application that we will be building, is going to be very simple and will consist of one page, displaying a set of available photographs (see figure 1 above). Each photograph will be accompanied by a short description and a title. The photograph, title and description will be presented in the form of a card.

In addition to displaying a set of photographs, we will be providing a search bar above the photographs, which, in theory, will allow users to search for photographs whose title or description contains a certain string. Although we will not be implementing the search functionality itself, we will be implementing a “searching” message to indicate to the user that the search is in progress as the search term is being entered.

We begin building our demo app by including Vue.js as one of our dependencies. Open vue/index.html, and insert the following line above the script tag for app.js:

<a href="https://unpkg.com/vue/dist/vue.js">https://unpkg.com/vue/dist/vue.js</a>

Next, we define our Vue.js instance in app.js as follows:

var app = new Vue({
    el: '#app'
});

Note how only a few lines of code are required to create this instance, and we are not forced to use the concepts of modules and controllers; instead, we simply create a Vue object that targets our application div (i.e. the div with id=”app”). Targeting our application div means that this Vue instance is available anywhere within the application div.

To define our cards (or any other data), we must use the data property. In our case, we will simply be hard-coding the card data, as dealing with HTTP requests to fetch the data is beyond the default capabilities of Vue, and therefore beyond the scope of this article.

Editorial Note: Check the vue-resource plugin for making web requests and handle responses using a XMLHttpRequest or JSONP.

We will shortly see just how easily we can access the data contained by our Vue object. But for now, we will just focus on defining the data, by adding our own properties to the data property of our Vue object.

Aside from the card data, we will also initialise message to an empty string and search_term to null. These two properties will be used at a later stage when implementing our search functionality.

Having defined the data to be used by our application, our app.js should now look as follows:

var app = new Vue({
    el: '#app',
    data: {
        message: '',
        search_term: null,
        cards: [
            {
                title: 'Sunrise with palm trees',
                description: 'Lorem ipsum dolor sit amet, consectetur', 
                img_src: "img/1.jpg" 
            },
            { 
                title: 'Sunrise',
                description: 'Lorem ipsum dolor sit amet, consectetur',
                img_src: "img/2.jpg" 
            },
            { 
                title: 'Copacabana sunrise',
                description: 'Lorem ipsum dolor sit amet, consectetur',
                img_src: "img/3.jpg" 
            },
            { 
                title: 'Surfer',
                description: 'Lorem ipsum dolor sit amet, consectetur',
                img_src: "img/4.png" 
            }
        ]
    }
});

To display previously defined cards, we must update our template (index.html). Add the following markup inside this application div:

<div class="row">
    <div class="col s12 m3">
        <div class="card">
            <div class="card-image">
                <img>
                <span class="card-title">{{card.title}}</span>
                <a>
                <i>add</i>
                </a>
           </div>
           <div class="card-content">
               <p>{{card.description}}</p>
           </div>
       </div>
    </div>
</div>

The markup itself is fairly self-explanatory for the most part: we create one row, containing 4 columns. The various classes used in the sample code above are defined by materialize, and served as mere decoration.

However, three things stand out that may look strange or unfamiliar. The first is the attribute v-for="card in cards”. This is Vue’s way of allowing us to iterate over the cards contained in our Vue object. Specifically, this will mean that each column contains one card.

For each card, we interpolate its contents using the expression {{card.property}}, where property is the card property that we wish to access. Interpolation means that a certain placeholder expression (in this case {{card.property}}) will be replaced by the actual value of the given property. So, what will be rendered will be the title and description of each card contained within our Vue object.

Similar to v-for, v-bind will allow us to bind a value to a certain attribute - in our case, we will be setting the src attribute of the image to the img_src of the card: v-bind:src="card.img_src".

Next, we are going to define the search bar. Insert the following markup above the row containing the photographs:

<div class="row">
   
       <div class="row">
            <div class="input-field col s6">
                 <i class="material-icons prefix text-muted">search</i>
                 
                 Search term
           </div>
      </div>
      <div class="row text-muted">
        <i class="material-icons search">hourglass_empty</i> {{message}}
      </div>
   </form>
</div>

Again, the markup is self-explanatory: we essentially add a row containing an input box. By using v-on:change, we ensure that a function called search (which we will define below) is called whenever the input changes. Using v—if we conditionally display an hourglass icon along with a message (see figure 2 below), if a search term exists (i.e. if the controller’s search_term property is truthy). The search input is bound to search_term property of our controller using v-model.

Last but not least, we will define our search function by using the methods property:

methods: {
        search: function () {
            this.message = 'Searching for ' + this.search_term + '...';
        }
}

vue-js-search-box

Figure 2: An hour-glass icon along with a search message appears once the search input contains text.

And that’s it! Pronto! We now have a basic Vue.js app that:

- Dynamically generates rows using a loop and interpolates the relevant data

- Binds the data of an input using

- Conditionally displays a search message

Save your work and open index.html in your browser to view the result. Then move onto the next section, to better understand what exactly we just did.

Directives and Components in Vue

Vue.js offers components and directives. In essence, both directives and components are functions that can be referenced in the DOM as attributes on an element, are executed on a per-element basis as they are encountered. The difference between the two is that “directives are meant to encapsulate DOM manipulations […] while components are self-contained units that have their own view and data logic” (as per the official Vue.js documentation).

This allows for two very powerful abilities: componentization and language extension.

Let’s consider the latter first: Language extension means that the developer can extend the markup language with custom attributes. For example, consider that we may want to define a directive that colours an image description text, grey. In Vue.js, we would first define the directive:

Vue.directive(‘sp-grey', {
});

where sp-grey is our directive name. We then simply change the colour of the bound element as soon as it is inserted into the DOM:

Vue.directive('sp-grey', {
    inserted: function (el) {
        el.style.color = 'lightgrey';
    }
});

The directive can then be used by prepending to v- prefix:

{{card.description}}

Notice how we have encountered “attributes” with the v-prefix in the previous section: v-if, v-for, v-model, etc. We had just vaguely referred to them as Vue's “way of providing for a specific ability”. Now that we have learned about directives, it should be clearer what exactly these attributes refer to: in-built Vue directives for providing a basic set of functionality. For a complete summary of the most important Vue directives, see table 1 below.

vue-js-directives

Table 1: A summary of the most important Vue directives.

Aside from extending HTML, the concept of components allows one to componentize the markup.

Instead of now having one large template containing all the markup, one can create a small set of re-usable components, thus i) avoiding repetition and ii) increasing readability by reducing the overall amount of markup in a single template.

To define a component in Vue, we simply specify a name and a set of options:

Vue.component('my-name', {
  template: ‘’,
  // Other options
})

where template should contain the component’s markup. An obvious use case for components in our demo application might be our card for displaying a photo along with its title and description. As such, the component template would contain the markup of the card div:

Vue.component('sp-card', {
  template: `
    <div class="card">
        <div class="card-image">
            <img>
            <span class="card-title">{{card.title}}</span>
            <a class="btn-floating halfway-fab waves-effect waves-light red"><i class="material-icons">add</i></a>
        </div>
        <div class="card-content">
            <p>{{card.description}}</p>
        </div>
    </div>`,
});

For this component to function as intended, we would need to be able to pass the card instance as a parameter. This we achieve through the props property:

Vue.component('sp-card', {
  template: ‘…’,
  props: [‘card’]
});

To then use this component in our markup, we simply replace the card div with:

<sp-card v-bind:card="card"></sp-card>

A note of caution regarding the parameter names as per the Vue.js documentation: “HTML attributes are case-insensitive, so when using non-string templates, camelCased prop names need to use their kebab-case (hyphen-delimited) equivalents” (https://vuejs.org/v2/guide/components.html, 02/2017).

This means that if you wanted to use multi-word parameter names they would be separated by a dash (e.g. my-card), whilst declared in props using camel case (e.g. props: [‘myCard’]).

It is important to note that: “all props form a one-way-down binding between the child property and the parent one: when the parent property updates, it will flow down to the child, but not the other way around. This prevents child components from accidentally mutating the parent’s state, which can make your app’s data flow harder to reason about.” (https://vuejs.org/v2/guide/components.html, 02/2017)

As previously noted, unlike directives, components can contain its own data. However, this data must be returned by a function (it cannot be a data object, as is the case with the Vue instance that we created earlier):

Vue.component('sp-card', {
  template: ‘…’,
  props: [‘card’],
  data: function () { 
    // Return some data object
    return {  }; 
  };
});

Comparing Vue.js with other JavaScript frameworks

There are many advantages of using Vue.js over older libraries or frameworks such as AngularJS. Specifically, these advantages lie with performance, ease-of-use, design flexibility, size and functionality. In this section, we will cover each of these advantages in turn.

Performance

When it comes to rendering performance, Vue.js outperforms many existing popular frameworks such as AngularJS or React. In fact, Vue.js is one of the fastest frameworks to date.

For example, the AngularJS 1 equivalent of our demo application, containing one row of data, took almost 14.7 milliseconds longer to render. The significance of this performance difference becomes more evident when increasing our dataset from 1 row to 100 rows of data: Vue.js now renders the page in 488.7 milliseconds, whilst AngularJS requires 534.3 milliseconds. Figure 3 below by Stefan Krause (http://stefankrause.net) gives a more in-depth summary of the various frameworks and performance differences.

js-library-perf-benchmark

Figure 3: Performance benchmark of various JS libraries and frameworks, taken from http://stefankrause.net/js-frameworks-benchmark4/webdriver-ts/table.html.

Design flexibility

Vue.js, is not a very “opinionated” framework. This means that it does not dictate how it should be used, and how applications using it should be designed. This means that, whilst other frameworks may force the developer to follow a certain pattern, Vue does not.

For example, unlike Ember or Angular, Vue.js does not force you to use modules or define a controller: instead, one just creates a Vue.js object that is configured with the data and methods needed in the template.

Using an opinionated framework can be both advantageous and disadvantageous: it may save developers time by already having something that made design choices for them; or it can become a hurdle as the framework “locks” developers into doing things a specific way.

Functionality

As already noted, Vue.js is a library for developing web-interfaces. Therefore, it does just that, and nothing more. Vue.js does not come with additional tools and features. Anything outside Vue’s sole purpose must be achieved by either writing the code yourself, or using third-party libraries.

As such, competitors to Vue, such as AngularJS, which is a complete framework, offer a full sets of additional functionality, such as services for performing HTTP requests, promise handling, filters for formatting data, routing, a service for cookie handling, a service wrapper for handling timeouts, etc.

Therefore, it is important to note that, whilst Vue.js does a great job at allowing developers to develop web-interfaces, Vue does just that, and nothing more.

Size

The codebase of Vue.js is much smaller and simpler than that of its competitors, such as AngularJS. Vue.js 2.1.10 consists of a mere 8569 lines of code. This makes a large difference in terms of actual file size: minified Vue.js 2.1.10 is a mere 74KB in size, compared to 168KB for AngularJS 1.6.1.

Conclusion

In this tutorial, we introduced beginners to Vue.js by means of building a simple demo application. As such, we covered the library’s most important features, demonstrating how we can use Vue to quickly create a powerful and flexible web-interface.

Specifically, we introduced the reader to i) templating and interpolation, ii) directives and iii) components. By writing custom directives, we saw how we can extend the default capabilities of HTML, and through the use of components we were able to componentize the HTML we wrote into ease-to-understand, re-usable units of code.

Download the entire source code of this article (Github)

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+
Further Reading - Articles You May Like!
Author
Benjamin Jakobus graduated with a BSc in Computer Science from University College Cork and obtained an MSc in Advanced Computing from Imperial College London. As a software engineer, he has worked on various web-development projects across Europe and Brazil.


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!