Vue 源码 if parent is an HOC, update its $el as well

265 阅读1分钟

1、// 高阶组件HOC

Vue.prototype._update = function (vnode, hydrating) {
      var vm = this;
      ...
      // if parent is an HOC, update its $el as well
      // 高阶组件HOC
      if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
        vm.$parent.$el = vm.$el;
      }
 }

解析:

  <root>
     <child1></child1>
     <child2>
       <child21></child21>
     </child2>
 </root>

已child1、child2、child21为例

  • $el 当前组件实例对应的DOM
  • _vnode 当前组件实例对应的vnode
  • $parent 当前组件的父组件实例 child21.parent = child2、child1.\parent = root
  • $vnode 子组件在父组件引用节点(组件标签) 所以_vnode.parent = $vnode(源码 Vue.prototype._render 函数赋值),$vnode 和 _vnode 的 $el相同,指向同个DOM

解析:高阶组件HOC HOC: (component) => ({ template: <component></components> }) 所以component 这个组件 的父节点是HOC,vm(component).$vnode(包括组件标签) = vm(component).$parent(HOC)._vnode(不包含HOC标签),所以需要控制component的HOC组件引用同一个$el

2、$slots、$scopedSlots 差别

  • $slots: 子组件的插槽集合,包括具名插槽和默认插槽,$slots内容会直接解析成 vnode 集合给子组件解析获取,所以 $slots中 vnode的上下文context是父组件(调用子组件的组件,不是嵌套子组件的上一级组件)。 因此在 HOC高阶组件 不能直接传递 slots,需要修改slots中的 vnode的context为 HOC组件实例。(child21中的$slots vnode 的context 是 root)
  • $scopedSlots: scope-slot会以render函数传递给子组件解析渲染,所使用的上下文context就是 子组件, 因此在 HOC高阶组件 可以直传(透传) $scopedSlots 给子组件。