探索Vue高阶组件的使用

2020-06-16 06:24:45易采站长站整理

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
属性访问当实例本身,而不是直接使用