Vue.js

Table of Contents

Overview

Getting Started

# install vue-cli
$ npm install --global vue-cli
# create a new project using the "webpack" template
$ vue init webpack my-project
# install dependencies and go!
$ cd my-project
$ npm run dev

Data and Methods

When a Vue instance is created, it adds all the properties found in its data object to Vue’s reactivity system.

Vue instances expose a number of useful instance properties and methods. These properties and methods are prefixed with $ to differentiate from proxied data properties. For example:

var data = { a: 1 }
var vm = new Vue({
  el: '#example',
  data: data
})
vm.$data === data // -> true
vm.$el === document.getElementById('example') // -> true
// $watch is an instance method
vm.$watch('a', function (newVal, oldVal) {
  // this callback will be called when `vm.a` changes
})

Lifecycle

Don’t use arrow functions on an options property or callback, such as created: () => console.log(this.a) or vm.$watch('a', newValue => this.myMethod()). Since arrow functions are bound to the parent context, this will not be the Vue instance as you’d expect, often resulting in errors

mounted

computed and watch

computed
  • caches the value when first calculated
  • updates automatically when its dependent variables changed
watch
  • call back of data field's change event

Project Structure

.
├── build/                      # webpack config files
│   └── ...
├── config/
│   ├── index.js                # main project config
│   └── ...
├── src/
│   ├── main.js                 # app entry file
│   ├── App.vue                 # main app component
│   ├── components/             # ui components
│   │   └── ...
│   └── assets/                 # module assets (processed by webpack)
│       └── ...
├── static/                     # pure static assets (directly copied)
├── test/
│   └── unit/                   # unit tests
│   │   ├── specs/              # test spec files
│   │   ├── eslintrc            # config file for eslint with extra settings only for unit tests
│   │   ├── index.js            # test build entry file
│   │   ├── jest.conf.js        # Config file when using Jest for unit tests
│   │   └── karma.conf.js       # test runner config file when using Karma for unit tests
│   │   ├── setup.js            # file that runs before Jest runs your unit tests
│   └── e2e/                    # e2e tests
│   │   ├── specs/              # test spec files
│   │   ├── custom-assertions/  # custom assertions for e2e tests
│   │   ├── runner.js           # test runner script
│   │   └── nightwatch.conf.js  # test runner config file
├── .babelrc                    # babel config
├── .editorconfig               # indentation, spaces/tabs and similar settings for your editor
├── .eslintrc.js                # eslint config
├── .eslintignore               # eslint ignore rules
├── .gitignore                  # sensible defaults for gitignore
├── .postcssrc.js               # postcss config
├── index.html                  # index.html template
├── package.json                # build scripts and dependencies
└── README.md                   # Default README file

Template Syntax

<!-- msg is data property of the Vue object-->
<span>Message: {{ msg }}</span>
<span v-once>This will never change: {{ msg }}</span>
<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>

<!-- remove/insert the <p> element based on whether or not 'seen' is true. -->
<p v-if="seen">Now you see me</p>
<!-- .prevent modifier tells the v-on directive to call event.preventDefault() on the triggered event: -->
<form v-on:submit.prevent="onSubmit"> ... </form>
<!-- full syntax -->
<a v-bind:href="url"> ... </a>
<!-- shorthand -->
<a :href="url"> ... </a>

<!-- full syntax -->
<a v-on:click="doSomething"> ... </a>
<!-- shorthand -->
<a @click="doSomething"> ... </a>

API

Vue(options)

name
  • Only respected when used as a component option.
  • Allow the component to recursively invoke itself in its template.
  • When a component is registered globally with Vue.component(), the global ID is automatically set as its name.
data
  • Only accepts Function when used in a component definition.
  • The object must be plain
el
  • Only respected in instance creation via new.
  • Provide the Vue instance an existing DOM element to mount on.
    • It can be a CSS selector string or an actual HTMLElement.
    • It doesn't need to specify when using .vue files.

v-bind

Dynamically bind one or more attributes, or a component prop to an expression.

<!-- bind an attribute -->
<img v-bind:src="imageSrc">

<!-- shorthand -->
<img :src="imageSrc">

<!-- with inline string concatenation -->
<img :src="'/path/to/images/' + fileName">

<!-- class binding -->
<div :class="{ red: isRed }"></div>
<div :class="[classA, classB]"></div>

<!-- class binding ('key' is included if 'value' is true -->
<div :class="[classA, { classB: isB, classC: isC }]">

<!-- style binding -->
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObjectA, styleObjectB]"></div>

<!-- binding an object of attributes -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>

<!-- prop binding. "prop" must be declared in my-component. -->
<my-component :prop="someThing"></my-component>

<!-- pass down parent props in common with a child component -->
<child-component v-bind="$props"></child-component>

Static elements and dynamic bind elements are merged. So following code:

<div class="static"
     v-bind:class="{ active: true }">
</div>

will render:

<div class="static active"></div>

v-for

:key
Specify this to give an ordering hint.
<ul>
    <li v-for="(item, index) in items" :key="index"></li>
</ul>
<div v-for="item in items" :key="item.id">
  {{ item.text }}
</div>

mixins


Special Attributes

key
  • can be used as a hint for Vue's virtual DOM algorithm
  • can be used to force replacement of an element/component instead of reusing it.
<!-- When text changes, the <span> will always be replaced instead of patched,
     so a transition will be triggered. -->
<transition>
  <span :key="text">{{ text }}</span>
</transition>

Lifecycle Hooks

created
  • The instance has finished processing options
  • data, computed, methods, watch, event are now accessible

List Rendering

<ul id="example-1">
  <li v-for="item in items">
    {{ item.message }}
  </li>
</ul>

<div v-for="(value, key) in object">
  {{ key }}: {{ value }}
</div>

<!-- It is recommended to provide a key with v-for whenever possible -->
<div v-for="item in items" :key="item.id">
  <!-- content -->
</div>

Components

Name Casing

According to ./style-guide, PascalCase naming is preferred when it is possible.

When defining a component with PascalCase, you can use either case when referencing its custom element. That means both <my-component-name> and <MyComponentName> are acceptable. Note, however, that only kebab-case names are valid directly in the DOM (i.e. non-string templates).

Non-string templates are things when you use Vue.js within actual .html files, consider following code:

<body>
  <div id="app"> <!-- your App is runnning in this div --->
    <my-component></my-component>
  </div>

  <template id="template-for-my-component">
    {{ message }}
  </template>
</body>

This HTML will be controlled by the browser before Vue can work with it, and therefore Vue is limited by the caveats explained in the linked documentation

Global Components

<div id="example">
  <my-component></my-component>
</div>
// register
Vue.component('my-component', {
  template: '<div>A custom component!</div>'
})

// create a root instance
new Vue({
  el: '#example'
})

Local Components

var Child = {
  template: '<div>A custom component!</div>'
}

new Vue({
  // ...
  components: {
    // <my-component> will only be available in parent's template
    'my-component': Child,
    //  Using it as <Child/>
    Child,

  }
})

Composing Components

The API for a Vue component comes in three parts - props, events, and slots:

<my-component
  :foo="baz"
  :bar="qux"
  @event-a="doThis"
  @event-b="doThat"
>
  <img slot="icon" src="...">
  <p slot="main-text">Hello!</p>
</my-component>

Props

Vue.component('blog-post', {
  // camelCase in JavaScript
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})
<!-- Vue (string templates) -->
<blog-post postTitle="hello!"></blog-post>

<!-- Vue with dynamic props (string templates) -->
<blog-post :postTitle="hello!"></blog-post>

<!-- HTML (non-string templates) -->
<blog-post post-title="hello!"></blog-post>
Vue.component('my-component', {
  props: {
    // Basic type check (`null` matches any type)
    propA: Number,
    // Multiple possible types
    propB: [String, Number],
    // Required string
    propC: {
      type: String,
      required: true
    },
    // Number with a default value
    propD: {
      type: Number,
      default: 100
    },
    // Object with a default value
    propE: {
      type: Object,
      // Object or array defaults must be returned from
      // a factory function
      default: function () {
        return { message: 'hello' }
      }
    },
    // Custom validator function
    propF: {
      validator: function (value) {
        // The value must match one of these strings
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

Slots

The content between child component tags is passed to where <slot> tags placed within the child component.

<child>DATA</child>
  • DATA is put into the single existing <slot></slot>.
<template slot="name">DATA</template>
  • DATA is put into the named slot <slot name="name"></slot>
<template slot="name" slot-scope="data">{{ data.DATA }}</template>
  • Access to data from the child
<div>
  <h1>This is my component!</h1>
  <slot>
    This will only be displayed if there is no content
    to be distributed.
  </slot>
</div>
<my-component>
  <p>This is some original content</p>
  <p>This is some more original content</p>
</my-component>

Rendered as:

<div>
  <h1>This is my component!</h1>
  <p>This is some original content</p>
  <p>This is some more original content</p>
</div>

ref

<input ref="hello">

You can refer the element above with following:

this.$refs.hello

Events

.sync Modifier

<text-document
  v-bind:title="doc.title"
  v-on:update:title="doc.title = $event"
></text-document>

is equivalent to:

<text-document v-bind:title.sync="doc.title"></text-document>

Single File Components (.vue)

In many Vue projects, global components will be defined using Vue.component, followed by new Vue({ el: '#container' }) to target a container element in the body of every page.

How-to

Configure different environment variables by stage

If you use vue template is easier to configure:

// config/prod.env.js
module.exports = {
  NODE_ENV: '"production"',
  DEBUG_MODE: false,
  API_KEY: '"..."' // this is shared between all environments
}

// config/dev.env.js
module.exports = merge(prodEnv, {
  NODE_ENV: '"development"',
  DEBUG_MODE: true // this overrides the DEBUG_MODE value of prod.env
})

// config/test.env.js
module.exports = merge(devEnv, {
  NODE_ENV: '"testing"'
})
Vue.config.productionTip = process.env.NODE_ENV === 'production'

Use axios with Vue.js

import Vue from 'vue'
import App from './App'
import axios from 'axios'

// Use axios globally
Vue.prototype.$http = axios

// Or, just import axios in each component

Topics

v-if vs v-show

Generally speaking, v-if has higher toggle costs while v-show has higher initial render costs. So prefer v-show if you need to toggle something very often, and prefer v-if if the condition is unlikely to change at runtime.

Testing

Components
Guides

Links