而
Vue 内部做了一件很重要的事儿,即上面那个表达式必须成立,才能够正确处理具名
slot ,否则即使
slot 具名也不会被考虑,而是被作为默认插槽。这就是高阶组件中不能正确渲染
slot 的原因。那么为什么高阶组件中上面的表达式就不成立了呢?那是因为由于高阶组件的引入,在原本的父组件与子组件之间插入了一个组件(
也就是高阶组件 ),这导致在子组件中访问的
this.$vnode 已经不是原来的父组件中的
VNode 片段了,而是高阶组件的
VNode 片段,所以此时
this.$vnode.context 引用的是高阶组件,但是我们却将
slot 透传,
slot 中的
VNode 的
context 引用的还是原来的父组件实例,所以这就造成了以下表达式为假:
console.log(this.$vnode.context === this.$vnode.componentOptions.children[0].context) // false
最终导致具名插槽被作为默认插槽,从而渲染不正确。
而解决办法也很简单,只需要手动设置一下
slot 中
VNode 的
context 值为高阶组件实例即可,修改高阶组件如下:hoc.js
function WithConsole (WrappedComponent) {
return {
mounted () {
console.log('I have already mounted')
},
props: WrappedComponent.props,
render (h) {
const slots = Object.keys(this.$slots)
.reduce((arr, key) => arr.concat(this.$slots[key]), [])
// 手动更正 context
.map(vnode => {
vnode.context = this._self
return vnode
}) return h(WrappedComponent, {
on: this.$listeners,
props: this.$props,
attrs: this.$attrs
}, slots)
}
}
}
现在,都能够正常渲染啦,如下图:

这里的关键点除了你需要了解
Vue 处理
slot 的方式之外,你还要知道通过当前实例
_self 属性访问当实例本身,而不是直接使用










