Introduction
In this article, I would like to talk about a marvelous front-end framework called Vue.js. My goal here is to specify all the advantages and disadvantages of this framework; and, if you still haven’t joined the ranks of Vue.js ninjas, I will make sure that you do.
Frameworks are developed to make our hard lives easier by liberating us from writing tons of similar and boring lines of code. However, as the code core of some of the most popular frameworks is getting increasingly large, project development processes are getting more complex. Thus, whenever we need to create a development plan for our project, it’s necessary to focus on two factors:
- Application complexity
- Framework complexity
Abstractly speaking, we have to deal with two types of complexities: 1) inner complexity, which we can’t “cut” from the development process; 2) instrument complexity, which deals will specific tools and programs we are going to rely on to develop our application. As inner complexity is innate, all we can do is choose efficient and easy-to-use instruments to simplify the development process.
It’s immediately apparent from the foregoing that we have only two options to select instruments:
- Tool Insufficiency. Features that the instrument (or framework) has aren’t sufficient to make the development process easy, efficient, and cost-effective. Instruments like these are incapable of compensating for the app’s inner complexity, and as a result, developers have to custom develop necessary features.
- Tool Redundancy. Instrument features are too abundant. Developers can use only a limited part of this tool’s (or framework’s) features in the development process. Instruments like these are your project’s dead weight and can potentially cause multiple issues like development constraints, slow app load time, etc.
So, what can and should you do? I don’t want to sound like "Captain Obvious", but, basically, you should act under a principle “Every goal must have its own instrument to reach it.” What I also mean is that you need to strike the right balance between the app’s complexity and its features. These two should always be your priority.
About Vue.js and its Developer
First of all, let’s talk a bit about the history of Vue.js. And only then, I’m going to proceed to the actual development part. So, if you know the basic stuff about Vue.js, just skip this part.
Vue.js is created by Evan You, a former employee at Google and Meteor Dev Group. He started working on the framework in 2013. In 2014, the framework was officially released to the public. Since then, Vue.js has been actively used by many Chinese companies like Alibaba, Baidu, Xiaomi, Sina Weibo. It is included in the core of Laravel and PageKit. Recently, Gitlab, a free-for-all repository management system, has also began using Vue.js.
In September, 2016, Vue.js 2.0 was officially released. This Vue.js on steroids with greatly improved performance and stability relies on virtual DOM, supports server rendering, provides JSX capabilities, and much more. Though it is supported only by its own community, Vue.js performs nicely and can easily match products of such giants like Google and Facebook (Angular 2 and React 15). On top of that, Vue.js is getting as popular as those two (which is great).
Vue.js. How It Looks Like
To help you get a closer look at Vue.js from the start, consider a basic example below.
app.js
- var demo = new Vue({
- el: '#demo',
- data: {
- message: 'Hello, Singree!'
- }
- })
- Create a new instance view using a new Vue.
- Specify, which view tracks element in el.
- Keep state object in data.
app.html
- <div id="demo">
- <p>{{message ? message : "no content"}}</p>
- <input v-model="message">
- </div>
- Put an element with the necessary selector into html.
- Display data from the state using mustache syntax. Here, we have a simple ternary expression.
- Bound input with message state object using v-model.
Vue.js Concepts
The major concepts of Vue.js are,
- Constructor
- Components
- Directives
- Transitions
The first version of Vue.js also featured Filters, but, as far as I know, they got deprecated in Vue.js 2.0.
Constructor
app.js
- new Vue({
- el: '<jQueryStyleSelector>',
- template: '<id || inline template>',
- data: {
- props: 'As showed in templates',
- first_name: "John",
- last_name: "Smith"
- },
- computed: {
- full_name: function(){
- return this.first_name + this.last_name;
- }
- },
- methods: {
-
- beforeCreate: function(){},
- created: function(){},
- beforeMount: function(){},
- mounted: function(){},
- beforeUpdate: function(){},
- updated: function(){},
- beforeDestroy: function(){},
- destroyed: function(){},
-
- customMethodsAlso: function(){
-
- }
- }
- })
Every Vue.js app begins with creating a new instance called new Vue. In el, we put the element that Vue tracks. In template, we select (or inline specify) the element, which will be used for rendering purposes. In data, we store the actual state of the instance, and where computed provides us with properties.
In the example above, full_name tracks first_name and last_name as dependencies and automatically synchronizes them.
In methods, it is possible to specify the following custom and lifecycle methods of Vue. Here are these:
- beforeCreate checks data and initializes events
- created checks if el or template are present. If the answer is yes, it renders in them. If the answer is no, it searches render
- beforeMount creates $el and replaces it with el
- mounted used when the element has been rendered
When the state has changed,
- beforeUpdate renders VDOM again and compares it with the real DOM, applies the changes
- updated used when the changes have been rendered
- beforeDestroy tears down the watchers, child components, and event listeners
- destroyed used when the process at hand has been aborted.
The image below demonstrates the process well.
Directives are specific attributes that are used to add additional features to HTML elements. Let’s have a look at certain built-in directives. (Developers who have worked with Angular will find them quite similar.)
- v-bind dynamically calls one or several attributes
- v-cloak hides mustache expressions until the data isn’t mounted and patched
- v-if specifies the conditions for element rendering
- v-else specifies “else” for v-if
- v-for checks arrays of objects one by one, in cycles
- v-model bounds the state with input element
- v-on bounds event listener with the element
- v-once renders the element in the beginning and then stops tracking it
- v-pre doesn’t compile the element and its child components
- v-show switches the element’s visibility by changing CSS display property
- v-text updates the text in textContent element
All Vue-directives come with “v-” prefix. Directives get the state’s values and use HTML attributes and events as arguments. Like this -
HTML
- <div v-my-directive="someValue"></div>
JavaScript
- Vue.directive('my-directive', {
- bind: function () {
-
-
-
- },
- update: function (newValue, oldValue) {
-
- },
- unbind: function () {
-
-
- }
- })
Components
Components are helpful when you need to "expand" the main HTML elements and embed reusable code. Basically, components are reusable UI parts. On the app’s design state, we break down the app on several separate parts and create a hierarchy of components. Like this,
In Vue.js, you don’t have to deal with any specific requirements to name your components; however, I’d recommend following the W3C guidelines for custom components (use lowercase letters and prefixes).
app.js
- Vue.component('simple-counter', {
-
- template: '<button v-on:click="counter += 1">{{ counter }}</button>',
-
- data: function () {
- return {
- counter: 0
- }
- }
-
- })
- new Vue({
- el: '#demo'
- })
A new component is declared as Vue.component, and we pass this new tag’s name into the first argument (in our case, simple-counter).
The communication between Vue-components is based on the “Props in, Events out” principle. Basically, this means that data is passed from a parent element to a child element via props. Otherwise, the data is passed with emit an event.
Also, Vue.js includes the so-called single-file components. We create a file with .vue extension and pass styles, patterns, and inner logic into it. You can do it using such pre=processor as SASS, Stylus, PostCSS, and Jade, or any JS-compilable language (CoffeeScript, TypeScript).
app.js
-
- <style lang="sass">
- button {
- border: 1px solid gray;
- &.blue { border-color: blue; }
- }
- </style>
-
- <template lang="jade">
- avatar(:user='user')
- input(type='text', v-model='content')
- button.blue(@click='submitComment')
- </template>
-
- <script>
- import Comment from '../models'
- import avatar from './components/avatar.vue'
-
- export default {
- props: ['user'],
- components: {
- avatar
- },
- data () {
- return {
- content: ''
- }
- },
- methods: {
- submitComment (e) {
- e.preventDefault();
- var comment = new Comment(this.content)
- comment.save().then(() => {
- alert('o_O')
- this.content = ''
- })
- }
- }
- }
- </script>
Transitions
Vue.js has several options of animation effect used when elements are created, updated, or deleted from DOM. These effects feature the following instruments for:
- Automatic application of classes for CSS transitions and animations
- Integration of third-party libraries for CSS animations, such as Animate.css
- Use of JavaScript for DOM manipulation
- Integration of third-party JavaScript libraries for animations, such as Velocity.js.
Let’s look at a simple example below,
html
- <div id="demo">
- <button @click="show = !show">Toggle show</button>
- <transition name="bounce">
- <p v-if="show">Look at me!</p>
- </transition>
- </div>
js
- new Vue({
- el: '#demo',
- data: {
- show: true
- }
- })
Framework Ecosystem
Routing
A separate package called vue-router is responsible for routing in Vue.js. It supports nested routes to nested components; provides a simplified API for navigation hooks, controlled scrolling, and advanced transition checks. The example below demonstrates this well.
app.js
- import Vue from 'vue'
- import VueRouter from 'vue-router'
- import App from './app.vue'
- import ViewA from './view-a.vue'
- import ViewB from './view-b.vue'
-
- Vue.use(VueRouter)
-
- const router = new VueRouter()
-
- router.map({
- '/a': { component: ViewA },
- '/b': { component: ViewB }
- })
-
- router.start(App, '#app')
app.vue
- <div>
- <h1>this template will not change</h1>
- <router-view><!-- selected components are rendered here --></router-view>
- </div>
Ajax Requests
To use Ajax requests, you need to rely on the vue-resource plugin. It allows you to create web requests and handle responses with XMLHttpRequest or JSONP. Also, the plugin supports Promise API and URI templates.
js
- {
-
- this.$http.get('/someUrl').then((response) => {
-
- }, (response) => {
-
- });
- }
State management
Vuex is a state management pattern/template and library for applications on Vue.js. It provides developers with a centralized store for all of the app’s components and rules that ensure that this or that state can be mutated in a predictable fashion.
The image below demonstrates the app that is developed with Vue+Vuex. It includes the following conceptual parts:
- It acts as a single source of data for components.
- Vue-components. These are basically a declarative state display.
- These are used to “catch” completed events, collect data from external API and activate necessary mutations.
- These are used to mutate state. When they receive data from Actions, it applies them into a specific state.
Assembly System and Developer Tools
To complete debugging, you can use
Vue-devtools (unfortunately, there’s only a Chrome version). This instrument allows you to check which components are present in your app, and their state.
Also, it can be used with Vuex for time-travel debugging. Basically, you can check state history and toggle between multiple states.
Why Should I Use Vue.js?
Vue.js is just amazing! It is really great that I can activate it directly on the page without having to tweak the assembly system or CLI. Vue.js is very easy to use, even if you have never worked with JavaScript frameworks. It strikes the right balance between convenience and efficiency. Here are several additional benefits of Vue.js:
- It doesn’t weigh much. Runtime builds Vue.js 2.0 weighs only 16kb; 26kb with vue-router and vuex (quite similar to the first version of Vue.js).
- It is fast. Impeccable performance has always been at the core of Vue.js. Rendering middleware has been re-developed to accelerate virtual DOM’s performance (Snabbdom fork).
- JS 2.0 supports server rendering. For that end, it relies on the Vue-server-renderer module and supports other instruments from Vue ecosystem (vue-router and vuex). Isomorphic app development has become much easier.
- Alibaba guys are now actively developing Weex, a cross-platform native mobile UI (similar to ReactNative and NativeScript). This means that we will be able to use Vue components for Web, Android, and iOS soon.
Summary
Vue.js has risen from a simple, custom-developed project to a widely used framework with a huge community. I hope, if you have been a Vue.js doubter before reading this article, you have changed your mind. This framework is what every developer needs to give a try. Thanks for your time!