理解 Vue 的生命周期是尤为重要的,不仅是在于对 Vue 的理解,或者是实际项目中,对 Vue 的使用,都离不开 Vue 的生命周期。
Vue 生命周期
首先,先来看看Vue官网这张图( Vue 2.x 生命周期)
一切都是从创建 Vue 的实例开始的,实例创建完成后,进行数据响应、模板编译、指令绑定、数据渲染等操作。
主要有这些钩子函数:beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestory、destoryed
来看下简单的 demo,看下 Vue 生命周期的这些钩子函数到底做了哪些事
|
|
执行上述的 demo,输出如下:
|
|
在浏览器控制台输入
|
|
在浏览器控制台输入
|
|
小结
通过上述代码,我们可以对 Vue 的生命周期有了大概的了解,
beforeCreate 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用,此时 el 和 data 还未被赋值
created 在实例创建完成后被立即调用,会进行数据观测 (data observer),属性和方法的运算,watch/event 事件回调。
beforeMount 对 el 赋值,但数据还未装载
mounted 数据已装载,el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子
beforeUpdate 发生在虚拟 DOM 打补丁之前
updated 当这个钩子被调用时,组件 DOM 已经更新,并不是所有子组件都会更新
beforeDestroy 实例被销毁之前调用,此时,实例仍可用
destroyed 实例被销毁之后调用,此时,实例不可用,但生成的 DOM 仍然存在,只是无法更改 DOM 中的数据
进一步深入
仅仅了解是不够,接下来我们通过源码来深入了解下 Vue 的生命周期
|
|
initMixin
先来看看 initMixin(Vue) 方法
|
|
- 在 调用 beforeCreate 之前,Vue 进行了生命周期、事件、渲染 render 的初始化
- 在 beforeCreate 与 created 调用之间,进行了 injections 、state 、provide 的初始化
injections 和 provide,主要为高阶插件/组件库提供用例,成对出现,用于父级组件向下传递数据。这里不展开详述,重点看 initState() 方法。
|
|
initState() 主要是对 data/props/computed/watch 等进行初始化,主要调用了以下方法
initProps(),通过遍历 props 的值,验证传入的 props 类型是否正确,然后通过 defineReactive() (内部使用的是 object.defineProperty()) 将 props 转化为当前实例的响应式属性
initMethods(), 遍历 methods 属性,将 methods 绑定到 Vue 实例
initData(),遍历 data 属性,调用 proxy() (内部使用的是 object.defineProperty())对 data 进行数据劫持,然后调用 observe() 对 data 进行监听
initComputed(),建立一个新的watcher,遍历 computed ,通过 getter 对数据进行监听,如果 computed 中的属性,并不存在于 Vue 实例(data),那么会调用 defineComputed()(内部使用的是 object.defineProperty())将数据转换为响应式属性
initWatch(),遍历调用 createWatcher() 创建 watcher,createWatcher() 内部调用 vm.$watch() 方法进行注册监听事件。
mount
接下来是 mount 过程
|
|
vm.$mount() 的作用是手动地挂载一个未挂载的实例
$mount 方法主要在两个地方:
- vue/src/platforms/web/runtime/index.js
|
|
作用是通过 el 获取相应的DOM元素,然后调用 lifecycle.js 文件中的 mountComponent 方法
- vue/src/platforms/web/entry-runtime-with-compiler.js
|
|
作用主要就是根据 template 或者 el ,生成 render 函数,然后将 render 挂载到 vue 实例中,最后调用 lifecycle.js 文件中的 mountComponent 方法
那么 mountComponent 具体做了什么呢?
|
|
Vue compile 过程
直接进入 Vue complier 的源码
|
|
这个函数就是导出一个可以创建 complier 的方法
parse
接下来看看 Vue 的 complier 是如何根据 template ,解析出 AST
|
|
|
|
主要就是调用了 parseHTML() 方法对 template 进行解析的,其内部主要是使用了一个 while 循环,对传入的 template 字符串进行遍历,根据 HTML 标签进行拆分,然后创建 AST
generate
根据生成的 AST,又是如何编译成可执行代码串的呢?
|
|
|
|
AST 经过 generate得到 render 函数,render 的返回值是 VNode ,VNode 是 Vue 的虚拟 DOM 节点
编译完成之后,就进行构成 Virtual DOM,然后进行相关 diff 过程,最后更新实际的 DOM 节点
关于 Virtual DOM 和 Vue Diff 过程,请看另一篇博文 Vue 底层原理
参考 Vue 技术内幕