前言
如题,Vue 一直想要有 React 一样的 forwardRef 的功能。奈何官方并未提供该 API。当你写了一个抽象组件时,可以透传 attrs、events、 slots,就是无法透传 ref。不得不通过丑陋的this.$refs.xx.xx,并且在抽象组件内再写一个 computed,renturn this.$refs.xx。Vue3 已经彻底放弃 this 了。可以稍微短一点,但是还是无法让开发者忽略这个抽象组件,每当需要 ref 时,都得知道组件暴露的 ref 字段。
如何 forwardRef
// createHoc.js
import { h, getCurrentInstance, defineComponent } from 'vue'
function createInnerComp(
comp,
{
vnode: { ref, props, children }
}
) {
const compVnode = h(comp, props, children)
// ref 透传
compVnode.ref = ref
return compVnode
}
function forwradRefComp(comp) {
const hoc = defineComponent({
name: 'Hoc',
/* 骗过上帝*/
__asyncLoader: Promise.resolve(),
setup() {
const instance = getCurrentInstance()
return () => {
const vnode = createInnerComp(comp, instance)
return vnode
}
}
})
return hoc
}
// ContentComp.vue
import { defineComponent, h } from 'vue'
import { forwradRefComp } from './createHoc'
const comp = defineComponent({
name: 'ContentComp',
setup (props, { expose }) {
expose({
a: 1
})
return () => {
return h('div', null, 'ContentComp')
}
}
})
export default forwradRefComp(comp)
vue3 关键源码
由于 vue3 的 defineAsyncComponent API 本身就是一个抽象高阶组件,并且已经实现了我们想要的高阶组件创建方法,我们就是做了下 copy paste。
复制 createInnerComp 方法用来实现高阶组件。github.com/vuejs/core/…
setRef 时,通过 __asyncLoader 字段判断来跳过该组件 ref 的设置。我们在 render 里把 ref 字段赋值> 给我们想要透传的组件的 vnode 即可完成 forWardRef github.com/vuejs/core/…