为什么 createElm在 是组件渲染vnode时构建整个组件树的时候,是先子后父,而且需要创建父节点占位符? 如果是普通文本节点,是直接插入吗?

来源:3-5 patch(下)

慕码人4144975

2020-02-19

老黄问题有点多,非常抱歉!

function createElm (
  vnode,
  insertedVnodeQueue,
  parentElm,
  refElm,
  nested,
  ownerArray,
  index
) {
  // ...
  if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {
    return
  }

  const data = vnode.data
  const children = vnode.children
  const tag = vnode.tag
  if (isDef(tag)) {
    // ...

    vnode.elm = vnode.ns
      ? nodeOps.createElementNS(vnode.ns, tag)
      : nodeOps.createElement(tag, vnode)
    setScope(vnode)

    /* istanbul ignore if */
    if (__WEEX__) {
      // ...
    } else {
      createChildren(vnode, children, insertedVnodeQueue)
      if (isDef(data)) {
        invokeCreateHooks(vnode, insertedVnodeQueue)
      }
      insert(parentElm, vnode.elm, refElm)
    }
    
    // ...
  } else if (isTrue(vnode.isComment)) {
    vnode.elm = nodeOps.createComment(vnode.text)
    insert(parentElm, vnode.elm, refElm)
  } else {
    vnode.elm = nodeOps.createTextNode(vnode.text)
    insert(parentElm, vnode.elm, refElm)
  }
}
写回答

1回答

ustbhuangyi

2020-02-19

因为 createElm 整个过程就是一个树的深度递归过程,这个递归过程中,会把组件的 vnode 转成真实的 DOM 并插入到父元素 DOM 节点,对于组件 vnode,它的 DOM 对应的父元素节点就是它的占位符节点对应的父 DOM节点。
//img.mukewang.com/szimg/5e4cf6860916d52c22301156.jpg
举个例子吧,
<div>
   <comp-a></comp-a>
  <span></span>
</div>

在 div 对应的 vnode 执行 createChildren 的时候,组件 CompA  在渲染过程中会生成 vnode,那么它对应的 DOM 最终会挂载到 div 上,而 span 对应的 vnode 就直接挂载到 div 上。

递归过程结束,最终整个组件树渲染生成的 DOM 会挂载到最外层 Vue 实例 $mount 挂载的那个根节点上。

0
2
ustbhuangyi
回复
慕码人4144975
确实有点抽象,所以希望你在学习的时候也自己手写一些小例子来配合理解。
2020-02-20
共2条回复

Vue.js 源码深入解析 深入理解Vue实现原理

全方位讲解 Vue.js 源码,进阶高级工程师

4984 学习 · 1037 问题

查看课程