上篇文章中, 我们主要讲了 initProxy 相关的内容. 它主要是通过 https://developer.mozilla.org/zh-CN/docs/web/JavaScript/Reference/Global_Objects/Proxy 为 vm 对象代理一些自定义的行为. 今天我们回到 init 方法中, 继续为大家讲解 initLifecycle 方法. initLifeCycle 方法主要用来初始化生命周期相关的属性, 以及为 parent,child 属性赋值, 先来看源码.
- export function initLifecycle (vm: Component) {
- const options = vm.$options
- // locate first non-abstract parent
- let parent = options.parent
- if (parent && !options.abstract) {
- while (parent.$options.abstract && parent.$parent) {
- parent = parent.$parent
- }
- parent.$children.push(vm)
- }
- vm.$parent = parent
- vm.$root = parent ? parent.$root : vm
- vm.$children = []
- vm.$refs = {}
- vm._watcher = null
- vm._inactive = null
- vm._directInactive = false
- vm._isMounted = false
- vm._isDestroyed = false
- vm._isBeingDestroyed = false
- }
我们一行一行来分析
const options = vm.$options
把 mergeOptions 后的 options 赋值给 options 变量.
- // locate first non-abstract parent
- let parent = options.parent
- if (parent && !options.abstract) {
- while (parent.$options.abstract && parent.$parent) {
- parent = parent.$parent
- }
- parent.$children.push(vm)
- }
我们注意到, vue 作者对这段代码提供了一行注释
locate first non-abstract parent
定位第一个 "非抽象" 的父组件, 注意非抽象这三个字. 什么是非抽象呢? 最初自己也很疑惑, 最后在 vue 文档 https://cn.vuejs.org/v2/api/#keep-alive 中找到了答案.
抽象组件的定义如上图所示, 注意这句话, 不会出现在父组件链中. 明白了这点之后再去看上面的代码就不会那么迷惑了.
- let parent = options.parent
- if (parent && !options.abstract) {
- ...
- }
如果当前 vm 实例存在父实例, 则把父实例赋值给 parent 变量. 当父实例存在, 且该实例不是抽象组件, 则执行下面代码
- while (parent.$options.abstract && parent.$parent) {
- parent = parent.$parent
- }
- parent.$children.push(vm)
注意 while 循环内的条件
parent.$options.abstract && parent.$parent
, 如果父实例 parent 是抽象组件, 则继续找 parent 上的 parent, 直到找到非抽象组件为止.
之后把当前 vm 实例 push 到定位的第一个非抽象 parent 的 $children 属性上, 现在我们知道了怎么匹配 vm 实例上的 parent 属性. 之后回到 initLifecycle 继续往下看
- vm.$parent = parent
- vm.$root = parent ? parent.$root : vm
- vm.$children = []
- vm.$refs = {}
- vm._watcher = null
- vm._inactive = null
- vm._directInactive = false
- vm._isMounted = false
- vm._isDestroyed = false
- vm._isBeingDestroyed = false
这部分代码是为 vm 上的一些属性赋值, 这些属性的作用如下表.
名称 | 说明 |
---|---|
$parent https://cn.vuejs.org/v2/api/#parent | 指定已创建的实例之父实例,在两者之间建立父子关系。子实例可以用 this.children 数组中。 |
$root https://cn.vuejs.org/v2/api/#vm-root | 当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。 |
$children https://cn.vuejs.org/v2/api/#vm-children | 当前实例的直接子组件。需要注意 $children 并不保证顺序,也不是响应式的。 |
$refs https://cn.vuejs.org/v2/api/#vm-refs | 一个对象,持有已注册过 ref 的所有子组件。 |
_watcher https://cn.vuejs.org/v2/guide/reactivity.html | 组件实例相应的 watcher 实例对象。 |
_inactive | 表示 keep-alive 中组件状态,如被激活,该值为 false, 反之为 true。 |
_directInactive | 也是表示 keep-alive 中组件状态的属性。 |
_isMounted | 当前实例是否完成挂载 (对应 < a target="_blank" href="https://link.juejin.im?target=https://cn.vuejs.org/v2/guide/instance.html" rel="nofollow noopener noreferrer" ztid="161" ow="72" oh="17"> 生命周期图示 https://cn.vuejs.org/v2/guide/instance.html 中的 mounted)。 |
_isDestroyed | 当前实例是否已经被销毁 (对应 < a target="_blank" href="https://link.juejin.im?target=https://cn.vuejs.org/v2/guide/instance.html" rel="nofollow noopener noreferrer" ztid="165" ow="72" oh="17"> 生命周期图示 https://cn.vuejs.org/v2/guide/instance.html 中的 destroyed)。 |
_isBeingDestroyed | 当前实例是否正在被销毁, 还没有销毁完成 (介于 < a target="_blank" href="https://link.juejin.im?target=https://cn.vuejs.org/v2/guide/instance.html" rel="nofollow noopener noreferrer" ztid="169" ow="72" oh="17"> 生命周期图示 https://cn.vuejs.org/v2/guide/instance.html 中 deforeDestroy 和 destroyed 之间)。 |
initLifecycle 方法的逻辑比较简单, 主要对 vue 实例上一些属性进行赋值. 所以这里就不画流程图来进行说明了. 下篇文章我们主要讲 initEvents 方法, 敬请期待.
最后在这里说一句, 我们这套 vue 源码解读文章, 基本上可以说是全网讲的最详细的了, 基本做到了讲解每行代码的意义. 这也花费了作者大量的精力和业余时间, 如果大家喜欢我的文章, 请不要吝惜你们的点赞和关注.
来源: https://juejin.im/post/5b1b4acf6fb9a01e573c3fcf