在 beforeMount 之后做了什么?
updateComponent 函数,调用 vm._update(vm._render, hydrating);watcher, 监视vm, 发生变化调用 updateComponent, 在执行之前调用 beforeUpdatepreWatchersmounted在这里,我们必须知道 Vue2 watcher 是什么?
在 Vue 2.x 中,Watcher 的作用是建立数据的响应式依赖关系并在数据发生变化时更新相关的视图。
也就是说,会根据 vm 属性变化,调用 updateComponent,在 new watcher(...) 的时候,会立刻调用一次。
按照代码逻辑来说
new Wather(…) 第一次调用渲染组件, 调用
1 | updateComponent = () => { |
触发完成 updateComponent 然后顺序调用 mounted. 当 vm 触发更新,_isMouted = true,可以触发 beforeUpdate.
但是实际上,并不是这样,上面是我理解的代码逻辑,但是如果是这样顺序就有问题,而且实际测试不是这样。
所以要知道 mounted 怎么触发,就需要搞清楚 render 和 update 的详细逻辑
render 方法就是在 renderMixin 当中
1 | Vue.prototype._render = function (): VNode { //... |
就是调用通过你模板中解析出来的 render 函数, 解析模板为一个 vnode,设置了上下文环境,设置属性
1 | vm.$vnode = _parentVnode! |
总之就是返回一个 vnode. 并且设置了 vm & vnode 属性。
继续来看 _update, 他通过调用 createElm 来创建节点。重点在创建完成以后,他通过一个队列,来调用 vnode.data.hook.insert
1 | invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch) |
initial 是用来判断是否是第一次创建。
queue 是 insertedVnodeQueue。 insertedVnodeQueue 是已经插入了 Vnode 队列, 可以理解为创建完成 vnode,会 push 到里面.
然后这个组件所有的组件创建完成以后,就会开始调用这个队列 insertedVnodeQueue,然后调用 vnode.data.hook.insert
1 | insert(vnode: MountedComponentVNode) { |
当所有的子节点都调用 insert, 然后最后调用根节点
1 | if (vm.$vnode == null) { |
创建,并且渲染完成所有 vnode 以后, 依照次序调用 mounted.
所以会造成一种结果
我们从前面的文章可以知道,Vue3.x 如何注册和调用生命周期的, 地址在这里 Vue lifecycle 实现.
这里我们需要知道他在哪里调用,并且在调用之前做了什么?
在 componentUpdateFn 中调用
1 | const { bm, m, parent } = instance //取出需要的生命周期 |
queuePostRenderEffect 会调用 queuePostFlushCb,然后向 pendingPostFlushCbs.push(m).
然后会在 render 完成以后调用 pendingPostFlushCbs,循环触发事件。
1 | const render: RootRenderFunction = (vnode, container, isSVG) => { |
patch 就是创建或者更新 vnode 的方法。
根据上面的代码会得到的结果就是
1 | parent vnode beforeMount trigger |
和 Vue2.x 一样,这就是 onMounted 的调用, 那么继续看 beforeMount 到 Mounted 之间做了什么.
1 | if (bm) { |
从 beforeMount 开始, 直接 invokeArrayFns 是直接调用,不存在延迟.
如果不是 ssr 的话,直接调用 patch 创建组件, 将子树的 el 属性赋值给初始 VNode 的 el 属性
1 | patch( |
如果钩子存在加入队列
1 | if (m) { |
然后直接调用 vnode 内部的 mounted hook 和 Vue2.x 写法的兼容性
1 | if (!isAsyncWrapperVNode && (vnodeHook = props && props.onVnodeMounted)) { // 如果不是异步组件的包装 VNode,并且存在 onVnodeMounted 钩子 |
接下来又处理了 active 事件(这个后面再讲),并且设置 instance.isMounted = true.
再这个过程中你会发觉,其实就是执行了 patch 创建或者更新了真实 dom,然后触发.
所以过程,流程就是当刚开始 mount => render => patch => 然后根据 vnode 不停的判断循环,递归,不停的创建真实dom。
等真实创建完成执行后面的代码
1 | const render: RootRenderFunction = (vnode, container, isSVG) => { |
其实创建阶段的生命周期就走到这里了。
setup => onBeforeMount => onMounted
beforeCreate => created => beforeMount => mounted