Vue的高阶组件在官方文档中并未提及,这个是一个舶来品,是React生态才有的一个概念。
但不妨碍我们使用它。
实际上Vue组件就是一个对象。根据高阶函数的概念
在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:
- 接受一个或多个函数作为输入。
- 输出一个函数
高阶组件也就是返回一个组件(对象数据)。
我们知道在使用Vue过程中,书写模板的方式有三种:
- 使用render
- 使用template属性
- 使用使用template模板
上述三种方式同时存在时,render的优先级是最高的。这在源码上是Vue首先对render这个参数做个判断,一旦有就直接使用了。
高阶组件有什么用呢?之前遇到一个问题,怎么对某些组件进行全局有效性拦截?我给出的方案是用mixins混入的方案,实际还可以用高阶组件。
比如我有一个Base.vue组件,一旦这个组件使用需要打印一些内容。
// Base.vue组件 <template> <div> <span @click="handleClick">props: {{test}}</span> <slot></slot> </div> </template> <script> export default { name: 'Base', props: { test: Number }, methods: { handleClick () { this.$emit('Base-click',{ msg:'子组件emit' }) } } } </script>
我们可以使用template构建一个高阶组件,然后包裹Base
//template版本 export default function HOC (Base) { return { template: '<base v-on="$listeners" v-bind="$attrs"/>', components: { base: Base }, mounted () { console.log('我是HOC mounted log') } } }
但是这个方案要求使用的vue是完整版而不是运行时版本。
使用render构建的高阶组件
export default function Console (Base) { return { mounted () { console.log('我是HOC mounted log') }, props: Base.props, // 继承pros render (h) { const slots = Object.keys(this.$slots) .reduce((acc, cur) => acc.concat(this.$slots[cur]), []) // 手动更正 context .map(vnode => { vnode.context = this._self //绑定到高阶组件上 return vnode }) // 继承slots return h(Base, { on: this.$listeners, props: this.$props, attrs: this.$attrs }, slots) } } }
使用高阶组件
<template> <div> <wrapBase @Base-click="click1" :test="100"> <p>default slot</p> </wrapBase> </div> </template> <script> //Parent.vue import Base from "./Base.vue"; // 使用hoc替代minxin import HOC from "./hoc"; // 这里可以是template版本也可以是render版本 const wrapBase = HOC(Base); export default { components: { Base, wrapBase, }, methods: { click1(msg){ console.log(msg, 'msg') } } //... }; </script>
以上案例高阶组件用来进行日志输出。当然也可以用来做权限校验。
也可以参考文章:https://zhuanlan.zhihu.com/p/181673485