这里的关键点除了你需要了解 Vue
处理 slot
的方式之外,你还要知道通过当前实例 _self
属性访问当实例本身,而不是直接使用 this
,因为 this
是一个代理对象。
现在貌似看上去没什么问题了,不过我们还忘记了一件事儿,即 scopedSlots
,不过 scopedSlots
与 slot
的实现机制不一样,本质上 scopedSlots
就是一个接收数据作为参数并渲染 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]), []) .map(vnode => { vnode.context = this._self return vnode }) return h(WrappedComponent, { on: this.$listeners, props: this.$props, // 透传 scopedSlots scopedSlots: this.$scopedSlots, attrs: this.$attrs }, slots) } } }
到现在为止,一个高阶组件应该具备的基本功能算是实现了,但这仅仅是个开始,要实现一个完整健壮的 Vue
高阶组件,还要考虑很多内容,比如:
函数式组件中要使用 render
函数的第二个参数代替 this
。
以上我们只讨论了以纯对象形式存在的 Vue
组件,然而除了纯对象外还可以函数。
创建 render
函数的很多步骤都可以进行封装。
处理更多高阶函数组件本身的选项( 而不仅仅是上面例子中的一个简单的生命周期钩子
)
我觉得需要放上两个关于高阶组件的参考链接,供参考交流:
Discussion: Best way to create a HOC
https://github.com/jackmellis/vue-hoc
为什么在 Vue 中实现高阶组件比较难
前面说过要分析一下为什么在 Vue
中实现高阶组件比较复杂而 React
比较简单。这主要是二者的设计思想和设计目标不同,在 React
中写组件就是在写函数,函数拥有的功能组件都有。而 Vue
更像是高度封装的函数,在更高的层面 Vue
能够让你轻松的完成一些事情,但与高度的封装相对的就是损失一定的灵活,你需要按照一定规则才能使系统更好的运行。
有句话说的好:
会了不难,难了不会
复杂还是简单都是相对而言的,最后希望大家玩的转 Vue
也欣赏的了 React
。放上两张我比较认同的图片供各位看官讨论: