五 Vue 原理解析之 虚拟Dom 到真实Dom的转换过程( 四 )


return function patch(oldVnode, vnode) {...if (isUndef(oldVnode)) {createElm(vnode, insertedVnodeQueue)}...}
这次执行 是没有传入第三个参数父节点的,那组件创建好的Dom放哪生效了? 没有父节点页要生成Dom不是,这个时候执行的是组件的 patch , 所以参数vnode 就是组件内元素节点的vnode了:
// app组件内模板app text-------------------------{// app内元素vnodetag: 'div',children: [{text: app text}],parent: {// 子组件_init时执行initLifecycle建立的关系tag: 'vue-component-1-app',componentOptions: {...}}}
很明显这个时候不是组件了,即使是组件也没关系,大不了还是执行一遍 创建组件的逻辑,因为总会有组件是由元素节点组成的 。这个时候我们执行一遍创建元素节点的逻辑,因为没有第三个参数父节点,所以组件的Dom虽然创建好了,并不会在这里插入 。请注意这个时候组件的init 已经完成,但是组件的 方法并没有完成,我们补全它的逻辑:
function createComponent(vnode, insertedVnodeQueue, parentElm, refElm) {let i = vnode.data;if (isDef(i)) {if (isDef(i = i.hook) && isDef(i = i.init)) {i(vnode)// init已经完成}if (isDef(vnode.componentInstance)) {// 执行组件init时被赋值initComponent(vnode)// 赋值真实dom给vnode.elminsert(parentElm, vnode.elm, refElm)// 组件Dom在这里插入...return true// 所以会直接return}}}-----------------------------------------------------------------------function initComponent(vnode) {...vnode.elm = vnode.componentInstance.$el// __patch__返回的真实dom...}
无论是嵌套多么深的组件,遇到组件后就执行 init, 在init 的 patch 过程中又遇到嵌套组件,那就再执行嵌套组件的init, 嵌套组件完成 后将真是的Dom插入到它的父节点内,接着执行完外层组件的 patch 又插入到它的父几点内,最后插入到body 内,完成嵌套组件的创建过程,总之还是一个由里及外的过程 。
在回过头看这张图,相信会很好理解了:
再将本章最初的 之后的逻辑补全:
export function mountComponent(vm, el) {...const updateComponent = () => {vm._update(vm._render())}new Watcher(vm, updateComponent, noop, {before() {if(vm._isMounted) {callHook(vm, 'beforeUpdate')}}}, true)...callHook(vm, 'mounted')return vm}
接下来会将传入到一个 的类中,这个类是干嘛的,我们下一章在介绍 。接下来执行 钩子方法 。至此new vue 的整个流程就全部走完了 。我们回顾下从new Vue 开始执行的顺序:
new Vue ==> vm._init() ==> vm.$mount(el) ==> vm._render()==> vm.update(vnode)
最后我们以一个问题来结束本章的内容:
解答:
parent beforeCreateparent createdparent beforeMountechild beforeCreatechild createdchild beforeMountechild mountedparent mounted
【五Vue 原理解析之 虚拟Dom 到真实Dom的转换过程】下一篇:vue 原理解析(六): 理解响应式原理(上): 对象