Vue面试系列之组件为什么只能有一个根元素

159 阅读1分钟

这题现在有些落伍,vue3已经不用一个根了。因此这题目很有说头!


体验一下

vue2直接报错,test-v2.html

new Vue({
  components: {
    comp: {
      template: `
        <div>root1</div>
        <div>root2</div>
      `
    }
  }
}).$mount('#app')

vue3中没有问题,test-v3.html

Vue.createApp({
  components: {
    comp: {
      template: `
        <div>root1</div>
        <div>root2</div>
      `
    }
  }
}).mount('#app')

回答思路

  • 给一条自己的结论
  • 解释为什么会这样
  • vue3解决方法原理

范例

  • vue2中组件确实只能有一个根,但vue3中组件已经可以多根节点了。
  • 之所以需要这样是因为vdom是一颗单根树形结构,patch方法在遍历的时候从根节点开始遍历,它要求只有一个根节点。组件也会转换为一个vdom,自然应该满足这个要求。
  • vue3中之所以可以写多个根节点,是因为引入了Fragment的概念,这是一个抽象的节点,如果发现组件是多根的,就创建一个Fragment节点,把多个根节点作为它的children。将来patch的时候,如果发现是一个Fragment节点,则直接遍历children创建或更新。

知其所以然

  • patch方法接收单根vdom:

    github1s.com/vuejs/core/…

    // 直接获取type等,没有考虑数组的可能性
    const { type, ref, shapeFlag } = n2
    
  • patch方法对Fragment的处理:

    github1s.com/vuejs/core/…

    // a fragment can only have array children
    // since they are either generated by the compiler, or implicitly created
    // from arrays.
    mountChildren(n2.children as VNodeArrayChildren, container, ...)