vue实例生命周期与生命周期钩子
每个 Vue 实例在被创建时都会经过一系列的初始化过程。例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。
为了让开发者在Vue实例生命周期的不同阶段有机会插入自己的代码逻辑,vue提供了一种叫做生命周期钩子的函数。主要的生命周期钩子如下:
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- activated
- deactivated
- beforeDestroy
- destroyed
官方提供的vue实例生命周期示意图很好地说明了整个过程。大家可以参考这张图来阅读本文。
初始化
执行new Vue()
后,将进入实例初始化阶段。这个阶段会触发两个钩子:
beforeCreate
和 created
。看下主要代码:
// Vue构造函数 function Vue (options) { // 实例初始化 this._init(options) } Vue.prototype._init = function (options?: Object) { const vm: Component = this // a uid 为每个vue实例分配一个唯一的id vm._uid = uid++ vm._isVue = true //...省略部分代码 if (options && options._isComponent) { // 合并组件选项对象 initInternalComponent(vm, options) } else { // 合并vue选项对象 vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor), options || {}, vm ) } vm._self = vm initLifecycle(vm) initEvents(vm) initRender(vm) callHook(vm, 'beforeCreate') initInjections(vm) // resolve injections before data/props initState(vm) initProvide(vm) // resolve provide after data/props // 初始化完成后,调用created钩子函数 callHook(vm, 'created') //...省略部分代码 // 如果指定了挂载元素,则执行挂载逻辑 if (vm.$options.el) { vm.$mount(vm.$options.el) } }
beforeCreate
从_init
方法中可以看到,vue会将用户所定义的选项对象与vue构造函数上所预先定义的静态选项对象进行合并。
调用initLifecycle
函数为实例初始化生命周期有关的属性。例如初始化vue实例_isMounted
、_isDestroyed
、_inactive
等属性的值。
调用 initEvents
函数为实例初始化事件相关的属性。例如初始化vue实例的_events
、_hasHookEvent
等属性的值。
调用initRender
函数为实例初始化渲染相关的属性。例如初始化vue实例的 _vnode
、_c()
、$slots
等属性的值。
由此可知,beforeCreate
钩子被调用时,已经初始化完成了lifecycle、render、event;但尚未处理data、props、methods、provide/inject、watch、computed等。
created
从代码中能看到,created
钩子被调用时,先后执行了initInjections
、initState
和 initProvide
。这几个函数主要是将data、props、inject、methods、computed、watch中所定义的属性使用defineProperty
代理到vue实例上。同时会把data、props、inject、computed、watch中的属性全部转换成响应式的。
经过这些处理,后面当我们在实例中修改属性值的时候,就会自动触发页面的重绘了。
由此可知,created
钩子被调用时,完成了实例的初始化,实例属性也具备了响应式的能力。但尚未开始DOM元素的挂载。一般在钩子里常见的操作是异步向后端获取数据。