import BaseComponent from './base-component.vue' console.log(BaseComponent)
思考一下,这里的 BaseComponent 是什么?它是函数吗?不是,虽然单文件组件会被 vue-loader 处理,但处理后的结果,也就是我们这里的 BaseComponent 仍然还是一个普通的 JSON 对象,只不过当你把这个对象注册为组件( components 选项)之后, Vue 最终会以该对象为参数创建一个构造函数,该构造函数就是生产组件实例的构造函数,所以在 Vue 中组件确实是函数,只不过那是最终结果罢了,在这之前我们完全可以说在 Vue 中组件也可以是一个普通对象,就像单文件组件中所导出的对象一样。
基于此,我们知道在 Vue 中一个组件可以以纯对象的形式存在,所以 Vue 中的高阶组件可以这样定义: 接收一个纯对象,并返回一个新的纯对象 ,如下代码:
hoc.js
export default function WithConsole (WrappedComponent) {
 return {
 template: '<wrapped v-on="$listeners" v-bind="$attrs"/>',
 components: {
  wrapped: WrappedComponent
 },
 mounted () {
  console.log('I have already mounted')
 }
 }
}
WithConsole 就是一个高阶组件,它接收一个组件作为参数: WrappedComponent ,并返回一个新的组件。在新的组件定义中,我们将 WrappedComponent 注册为 wrapped 组件,并在 template 中将其渲染出来,同时添加 mounted 钩子,打印 I have already mounted 。
以上就完成了与 mixins 同样的功能,不过这一次我们采用的是高阶组件,所以是非侵入式的,我们没有修改原组件( WrappedComponent ),而是在新组件中渲染了原组件,并且没有对原组件做任何修改。并且这里大家要注意 $listeners 和 $attrs :
'<wrapped v-on="$listeners" v-bind="$attrs"/>'
这么做是必须的,这就等价于在 React 中透传 props :
<WrappedComponent {...this.props}/>
否则在使用高阶组件的时候,被包装组件( WrappedComponent )接收不到 props 和 事件 。
那这样真的就完美解决问题了吗?不是的,首先 template 选项只有在完整版的 Vue 中可以使用,在运行时版本中是不能使用的,所以最起码我们应该使用渲染函数( render )替代模板( template ),如下:
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,
  })
 }
 }
}
      内容版权声明:除非注明,否则皆为本站原创文章。
