对于 Vue 的生命周期,官网给了一张图:
image这张图完整描述了 Vue 的生命周期,以及生命周期中涉及到的钩子函数。
本篇文章并不会重复官网讲解的内容,而是会专注于影响实际开发的生命周期细节。
初始化
在初始化流程中,会初始化以下比较重要的东西:
- 组件属性( props )
- 组件内部状态数据( data )
- provide/inject
- 侦听器( watch )
- 计算属性( computed )
官网文档里面对这几块的初始化顺序讲的比较少,而且非常分散,含糊其辞。而实际开发中,我们经常会产生如下疑问:
- 在 data 方法中能访问 props 数据吗?
- 在 data 方法和在 props 的
validator/default
方法中是否能访问 inject 数据吗? - 在 inject 中是否能访问 computed 数据?
要准确回答这些问题,必须知道 Vue 组件的初始化顺序是怎么样的:
- 初始化生命周期需要用到的状态变量,比如
isMounted
、isDestroyed
等等。
- 初始化生命周期需要用到的状态变量,比如
- 初始化事件。
- 从父级 VNode 中继承 context 对象。
- 解析传入的插槽。
- 初始化作用域插槽为空对象。
- 给当前 vm 实例加上 $createElement 方法,该方法绑定了当前 vm 的上下文对象。
- 调用
beforeCreate
钩子函数。
- 调用
- 初始化
inject
数据。
- 初始化
- 初始化组件 options 中定义的 prop 。
- 初始化组件 options 中定义的 methods 。
- 初始化
data
,并将其转换成响应式的。
- 初始化
- 初始化计算属性。
- 初始化
options
中配置的 watch 。
- 初始化
- 初始化当前 vm 的 provide 配置。
- 调用
created
钩子函数。
- 调用
- 如果
options
中配置了el
,则调用vm.$mount()
。
- 如果
从上述初始化顺序中可以很清晰地解答之前的疑问。
其中强调一些比较容易忽略的点:
-
provide
方法中能访问props
和data
中的数据。 -
inject
注入的数据,能在props
和data
中访问。 -
inject
只能感知到祖先组件provide
的内容,不能感知到自身的provide
。
render
在 vm.$mount()
调用之后,就会执行 render
流程了。
如果组件定义的时候没有指定 template
和 render
,就会触发异常。
如果同时指定了 template
和 render
,则使用 render
。
render
方法很“神奇”:模板中使用到的数据发生变化之后,会自动运行该方法。那么这种“神奇”功能的背后原理究竟是怎么样的呢?
此处可以先回顾一下之前的两篇文章:《 Vue 响应式原理》、《 computed 原理解析》。
首先,render
方法只能感应到 vm 上响应式数据的变化。其次 render
方法中的依赖是通过类似于 computed 依赖搜集的方式找到的,既然知道了依赖,那么在依赖数据发生变化的时候,自然能够重新运行 render
方法了。
updated
官网对 updated
钩子函数的描述可以在这里找到,其中一句关于执行时机的描述非常非常重要:
注意 updated 不会承诺所有的子组件也都一起被重绘。如果你希望等到整个视图都重绘完毕,可以用 vm.$nextTick 替换掉 updated 。
换句话说, updated 仅在当前组件的各种响应式数据体现到当前组件模板中所直接书写的 DOM 节点上之后触发,并不会保证等到子孙组件中的数据同步到 DOM 上才触发,如果要确保某段代码要在子孙组件中的数据同步到 DOM 中去之后才执行,就要借助于 vm.$nextTick
实现:
updated: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been re-rendered
})
}
nextTick
主要注意 vm.$nextTick
中的回调函数注入的 this
是 vm
。
mounted
mounted
被调用时,如果挂载到的父 DOM 元素在文档里面,那么此时当前组件的 el
元素也会存在于文档内。
同时注意官网描述:
注意 mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick 替换掉 mounted 。
网友评论