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