生命周期:
在Vue
中,每个Vue
实例从被创建出来到最终被销毁都会经历一个过程,就像人一样,从出生到死亡。在这一过程里会发生许许多多的事,例如设置数据监听,编译模板,组件挂载等。在Vue
中,把Vue
实例从被创建出来到最终被销毁的这一过程称为Vue
实例的生命周期,同时,在Vue
实例生命周期的不同阶段Vue
还提供了不同的钩子函数,以方便用户在不同的生命周期阶段做一些额外的事情。那么,接下来的几篇文章我们就从源码角度深入剖析一下一个Vue
实例在从生到死的生命周期里到底都经历了些什么,每个阶段都做了哪些事情。
生命周期流程图
下图是Vue
官网给出的Vue
实例的生命周期流程图,如下:
从图中我们可以看到,Vue
实例的生命周期大致可分为4个阶段:
- 初始化阶段:为
Vue
实例上初始化一些属性,事件以及响应式数据; - 模板编译阶段:将模板编译成渲染函数;
- 挂载阶段:将实例挂载到指定的
DOM
上,即将模板渲染到真实DOM
中; - 销毁阶段:将实例自身从父组件中删除,并取消依赖追踪及事件监听器;
总结::
本篇文章是生命周期篇的开篇综述,借用Vue
官网的生命周期流程图介绍了一个Vue
实例的生命周期大致可分为四个阶段,分别是初始化阶段、模板编译阶段、挂载阶段、销毁阶段。接下来的几篇文章我们就从这个流程图为基础,自上到下,从每个阶段入手,深入分析在每个阶段里都干了些什么。
2. new Vue()都干了什么
初始化阶段所做的第一件事就是new Vue()
创建一个Vue
实例,那么new Vue()
的内部都干了什么呢? 我们知道,new
关键字在 JS
中表示从一个类中实例化出一个对象来,由此可见, Vue
实际上是一个类。所以new Vue()
实际上是执行了Vue
类的构造函数,那么我们来看一下Vue
类是如何定义的,Vue
类的定义是在源码的src/core/instance/index.js
中,如下:
function Vue (options) {
if (process.env.NODE_ENV !== 'production' &&
!(this instanceof Vue)
) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
this._init(options)
}
可以看到,Vue
类的定义非常简单,其构造函数核心就一行代码:
this._init(options)
调用原型上的_init(options)
方法并把用户所写的选项options
传入。那这个_init
方法是从哪来的呢?在Vue
类定义的下面还有几行代码,其中之一就是:
|
这一行代码执行了initMixin
函数,那initMixin
函数又是从哪儿来的呢?该函数定义位于源码的src/core/instance/init.js
中,如下:
export function initMixin (Vue) {
Vue.prototype._init = function (options) {
const vm = this
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
callHook(vm, 'created')
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
}
可以看到,在initMixin
函数内部就只干了一件事,那就是给Vue
类的原型上绑定_init
方法,同时_init
方法的定义也在该函数内部。现在我们知道了,new Vue()
会执行Vue
类的构造函数,构造函数内部会执行_init
方法,所以new Vue()
所干的事情其实就是_init
方法所干的事情,那么我们着重来分析下_init
方法都干了哪些事情。
首先,把Vue
实例赋值给变量vm
,并且把用户传递的options
选项与当前构造函数的options
属性及其父级构造函数的options
属性进行合并(关于属性如何合并的问题下面会介绍),得到一个新的options
选项赋值给$options
属性,并将$options
属性挂载到Vue
实例上,如下:
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
接着,通过调用一些初始化函数来为Vue
实例初始
nitLifecycle(vm) // 初始化生命周期
initEvents(vm) // 初始化事件
initRender(vm) // 初始化渲染
callHook(vm, 'beforeCreate') // 调用生命周期钩子函数
initInjections(vm) //初始化injections
initState(vm) // 初始化props,methods,data,computed,watch
initProvide(vm) // 初始化 provide
callHook(vm, 'created') // 调用生命周期钩子函数
化一些属性,事件,响应式数据等,如下: