Vue.js
Table of Contents
- Overview
- Project Structure
- Template Syntax
- API
- Special Attributes
- Lifecycle Hooks
- List Rendering
- Components
- How-to
- Topics
- Testing
- Links
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)
orvm.$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
The
v-
prefix serves as a visual cue for identifying Vue-specific attributes in your templates.- In templates, the context of
this
, which is the correspondingVue
object can be referred withoutthis
.
<!-- msg is data property of the Vue object-->
<span>Message: {{ msg }}</span>
<span v-once>This will never change: {{ msg }}</span>
<!-- 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
- Only accepts
- 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:
will render:
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
// register
Vue.component('my-component', {
template: '<div>A custom component!</div>'
})
// create a root instance
new Vue({
el: '#example'
})
Local Components
data
andel
should be functions, otherwise the state of components is all shared.
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
:
- Props allow the external environment to pass data into the component
- Events allow the component to trigger side effects in the external environment
- Slots allow the external environment to compose the component with extra content.
<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
- A
prop
is a field on a component’sdata
that is expected to be passed down from its parent component. - Since
this.data
is initialized once once, sodata
elements depending onprop
would not be updated even if theprop
changes. - So, a
prop
can be referenced asthis.<prop>
or{{ <prop> }}
- When you’re using in-DOM templates(See Name Casing above),
camelCased
prop names need to use theirkebab-cased
equivalents
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
You can refer the element above with following:
Events
- For compatability, just use a lower-cased event name all smashed together, like
mycustomevent
.sync
Modifier
is equivalent to:
Single File Components (.vue)
In many Vue projects, global components will be defined using
Vue.component
, followed bynew Vue({ el: '#container' })
to target a container element in the body of every page.
How-to
Configure different environment variables by stage
- Use
webpack.DefinePlugin
to configureprocess.env
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"'
})
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 whilev-show
has higher initial render costs. So preferv-show
if you need to toggle something very often, and preferv-if
if the condition is unlikely to change at runtime.
Testing
- Components
- vue-test-utils
- jest
- babel-jest (for ES2015+ features in tests)
- vue-jest (for handling
*.vue
files in tests) - jest-serializer-vue (for snapshot tests)
- Guides