探索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>
      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/467.html