Vue 实例

创建一个实例

每一个Vue 应用都是通过 Vue 函数创建一个新的Vue 实例开始的:

var vm = new Vue({
    //选项
});

Vue 虽然未完全按照MVVM 模型,但是Vue 的设计也受到了它的启发。因此文档中经常会使用vm(viewModel 的缩写)这个变量名表示Vue实例。
当创建一个Vue 实例时,你可以传入一个选项对象

一个Vue应用由一个通过 new Vue 创建的 根Vue实例, 以及可选的嵌套的、可复用的组件树组成。eg.

根实例–TodoList

TodoItem

DeleteTodoButton
EditTodoButton

TodoListFooter

ClearTodosButton
TodoListStatistics

⚠️ 所有的Vue组件都是Vue实例,并且接受相同的选项对象(一些根实例特有的选项除外)

数据与方法

当一个 Vue 实例被创建时,它向Vue的响应式系统中加入了其data对象中所能找到的所有的属性。当这些属性的值发生改时,视图将会产生响应,即匹配更新为新的值。

//数据对象
var data = {
    a: 1
};
//该对象加入到Vue实例之中
var vm = new Vue({
    data: data
});
//对象引用是否一致
vm.a === data.a; //true

//设置属性也会影响到原始值
vm.a = 2;
data.a // =>2

//反之亦然
data.a = 3;
vm.a // =>3

当这些数据改变时,视图会重新进行渲染。 值得注意的是只有当实例被创建时 data 中存在的属性才是响应式的。也就是说新添加的属性,eg.

vm.b = 'hi';

那么对 b 的改动将不会触发任何视图的更新。如果预知晚些时候会用到一个新的属性,但是一开始的时候它为空或者不存在,那么你仅需要设置一些初始值。 eg.

data: {
    newTodoText:'',
    visitCount: 0,
    hideCompletedTodos:false,
    todos:[],
    error:null
}

这里唯一的例外是使用 Object.freeze(),这会组织修改现有属性,也意味着响应式系统无法再追踪变化
vue.js:3271 Uncaught TypeError: Cannot assign to read only property ‘init’ of object ‘#‘。
除了数据属性,Vue 实例还暴露了一些有用的实力属性与方法。它们都有前缀 $,以便与用户定义的属性区分开来。

var exampleData = {
    a: 1
};
var example = new Vue({
    el:'.example',
    data: {
        a: 1
    },
    methods: {
        changeA: function () {
            this.a = 2;
            console.log(this.a);
        }
    }
});

console.log(example.$data === exampleData);
console.log(example.$el === document.getElementsByClassName('example')[0]);

example.$watch('a',function (newVal,oldVal) {
    console.log('新值:'+newVal);
    console.log('旧值:'+oldVal);
});

实例生命周期钩子

每个Vue 实例在被创建时都要经过一系列的初始化过程–例如,需要设置数据监听、编译模板、将实例挂载到DOM 并在数据变化时更新DOM等。 同时在这个过程中也会运行一些叫做生命周期钩子 的函数,这给了用户在不同阶段添加自己的代码的机会。

比如created 钩子可以用来在一个实例被创建之后执行代码:

new Vue({
    data:{
        a: 1
    },
    created: function(){
        // 'this' 指向 vm 实例
        console.log('a is:' + this.a);
    }
});

也有其它的一些生命周期钩子, 在实例生命周期的不同阶段被调用,如 mounted、updated 和 destoryed。 声明周期钩子 this 上下文指向调用它的 Vue实例。
⚠️ 不要在选项属性或回调上使用箭头函数,比如created:() => console.log(this.a); 或 vm.$watch(‘a’,newValue => this.myMethod());。 因为箭头函数是和父级上下文绑定在一起的, this 不会是预估的Vue实例,经常会导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。

生命周期示意图

st=>start: new Vue( )
e=>end: Destroyed
opInitBeforeCreate=>operation: Init(Events & Lifecycle)
opInitCreated=>operation: Init ( Injections & Reactivity)
opX=>operation: ?

condHasEl=>condition: Has "el" option ?
condHasTemp=>condition: Has "template" option ?
opVm.$mountedCall=>operation: vm.$mounted(el)

st->opInitBeforeCreate->opInitCreated->condHasEl
condHasEl(yes)->condHasTemp
condHasEl(no)->opVm.$mountedCall->condHasTemp
opCompileTempIntoRender=>operation: Compile template into render function*
opCompileElOutHtmlAsTemp=>operation: Compile el's outerHTML as template*
opCreateVm.$elAndReplace=>operation: Create vm.$el and replace 'el' with it
opMounted=>operation: Mounted
condDataChange=>condition: when data changes
opUpdate=>operation: Virtual DOM re-render and patch
condDestroy=>condition: when vm.$destroy() is called
opDestroy=>operation: Teardown watchers,child components and event listeners
condHasTemp(yes)->opCompileTempIntoRender->opCreateVm.$elAndReplace
condHasTemp(no)->opCompileElOutHtmlAsTemp->opCreateVm.$elAndReplace
opCreateVm.$elAndReplace->opMounted->condDestroy
condDestroy(yes)->opDestroy->e
condDestroy(no)->condDataChange
condDataChange(yes)->opUpdate
condDataChange(no)->opMounted