探索Vue高阶组件的使用(5)
上面的代码中,我们将模板改写成了渲染函数,看上去没什么问题,实则不然,上面的代码中 WrappedComponent 组件依然收不到 props ,有的同学可能会问了,我们不是已经在 h 函数的第二个参数中将 attrs 传递过去了吗,怎么还收不到?当然收不到, attrs 指的是那些没有被声明为 props 的属性,所以在渲染函数中还需要添加 props 参数:
hoc.js
export default function WithConsole (WrappedComponent) {
return {
mounted () {
console.log('I have already mounted')
},
render (h) {
return h(WrappedComponent, {
on: this.$listeners,
attrs: this.$attrs,
props: this.$props
})
}
}
}
那这样是不是可以了呢?依然不行,因为 this.$props 始终是空对象,这是因为这里的 this.$props 指的是高阶组件接收到的 props ,而高阶组件没有声明任何 props ,所以 this.$props 自然是空对象啦,那怎么办呢?很简单只需要将高阶组件的 props 设置与被包装组件的 props 相同即可了:
hoc.js
export default function WithConsole (WrappedComponent) {
return {
mounted () {
console.log('I have already mounted')
},
props: WrappedComponent.props,
render (h) {
return h(WrappedComponent, {
on: this.$listeners,
attrs: this.$attrs,
props: this.$props
})
}
}
}
现在才是一个稍微完整可用的高阶组件。大家注意用词: 稍微 ,纳尼?都修改成这样了还不行吗?当然,上面的高阶组件能完成以下工作:
1、透传 props
2、透传没有被声明为 props 的属性
3、透传事件
大家不觉得缺少点儿什么吗?我们前面说过,一个 Vue 组件的三个重要因素: props 、 事件 以及 slots ,前两个都搞定了,但 slots 还不行。我们修改 BaseComponent 组件为其添加一个具名插槽和默认插槽,如下:
base-component.vue
<template>
<div>
<span @click="handleClick">props: {{test}}</span>
<slot name="slot1"/> <!-- 具名插槽 -->
<p>===========</p>
<slot/> <!-- 默认插槽 -->
</div>
</template>
<script>
export default {
...
}
</script>
然后我们写下如下测试代码:
<template>
<div>
<base-component>
<h2 slot="slot1">BaseComponent slot</h2>
<p>default slot</p>
</base-component>
<enhanced-com>
<h2 slot="slot1">EnhancedComponent slot</h2>
<p>default slot</p>
</enhanced-com>
</div>
</template>
<script>
import BaseComponent from './base-component.vue'
import hoc from './hoc.js'
const EnhancedCom = hoc(BaseComponent)
export default {
components: {
BaseComponent,
EnhancedCom
}
}
</script>
内容版权声明:除非注明,否则皆为本站原创文章。
