组件传递泛型(vue3.3+)
官方提供了函数签名,但实际使用非常不方便,仍然需要手动声明运行时的 props(虽然官方计划提供一个 Babel 插件,自动推断并注入运行时 props ,以便省略运行时 props 的声明,截至目前还没有提供),不如直接用defineComponent
定义组件
const Comp = defineComponent( <T extends string | number>(props: { msg: T; list: T[] }) => { // 就像在 <script setup> 中一样使用组合式 API const count = ref(0) return () => { // 渲染函数或 JSX return <div>{count.value}</div> } }, // 目前仍然需要手动声明运行时的 props { props: ['msg', 'list'] } )
但是直接用defineComponent
定义组件的话,组件之间如何传递泛型就是一个非常头疼的问题,总不能在父组件在子组件emits的方法中再声明一次返回体类型,这样很繁琐,我们希望的是,使用子组件时,只需声明一次需要支持的泛型类型即可,这里可以使用函数封装一下
export default function defineGenericComponent<T>() { return defineComponent(...) //defineComponent是实际子组件内容 }
下面用一个实际的例子来说明
// Parent.tsx import { defineComponent, ref, Ref, onMounted } from 'vue' import Child from './Child' interface DataItem { name: string } const ChildCom = Child<DataItem>() export default defineComponent({ setup() { onMounted(() => { console.log('onMounted') //生命周期 }) return () => ( <ChildCom onSelectionChange={(res) => { console.log(res) }} /> ) }, }) // Child.tsx import { defineComponent, onMounted } from 'vue' export default function defineGenericComponent<T>() { //defineComponent是实际子组件内容 return defineComponent({ props: { data: { type: Array as PropType<T[]>, default: () => [], }, }, emits: { selectionChange: (val: T[]) => true, }, setup(props, { emit }) { onMounted(() => { console.log('onMounted') //生命周期 }) return () => ( <div onClick={() => { emit('selectionChange', props.data) }} > child </div> ) }, }) }
通过如上方式引用子组件后,父组件在使用Child组件时,就有emit方法的提示,且能正常显示onSelectionChange
的返回体类型声明