Vue3可复用表格组件:能否隐式传递slotProps替代显式传递?
实现Vue3表格组件slotProps隐式传递的方案
当然可以去掉显式传递slotProps的步骤,下面给你两种实用的实现思路:
方法一:利用Vue3的Provide/Inject API
这是最直接的方式,在FSTable组件内部把需要传递的slotProps通过provide暴露出去,然后在FSTableColumn组件里用inject接收,就能实现隐式传递了。
具体代码示例
- FSTable组件内部:
<script setup> import { provide } from 'vue' // 假设这是你原本要传给slotProps的内容 const tableSlotProps = { headerData: /* 表头数据 */, cellData: /* 单元格数据 */, // 其他需要传递的属性 } // 把slotProps提供给子组件 provide('tableSlotProps', tableSlotProps) </script> <template> <table> <thead> <tr> <!-- 这里不再需要显式传递slotProps,FSTableColumn会自己inject --> <slot name="header"></slot> </tr> </thead> <tbody> <tr v-for="item in data" :key="item.id"> <slot name="cell" :item="item"></slot> </tr> </tbody> </table> </template>
- FSTableColumn组件内部:
<script setup> import { inject } from 'vue' // 注入FSTable提供的slotProps const tableSlotProps = inject('tableSlotProps', {}) // 加默认值避免非FSTable环境报错 const props = defineProps({ prop: String, renderAs: String }) // 结合renderAs处理渲染逻辑 const renderContent = () => { if (props.renderAs === 'header') { return tableSlotProps.headerData?.[props.prop] } else { return tableSlotProps.cellData?.[props.prop] } } </script> <template> <td v-if="renderAs === 'cell'">{{ renderContent() }}</td> <th v-else>{{ renderContent() }}</th> </template>
使用时无需显式传递slotProps,直接写:
<FSTable :data="tableData"> <template #header> <FSTableColumn prop="name" renderAs="header" /> <FSTableColumn prop="age" renderAs="header" /> </template> <template #cell="{ item }"> <FSTableColumn prop="name" renderAs="cell" /> <FSTableColumn prop="age" renderAs="cell" /> </template> </FSTable>
方法二:封装作用域插槽的子组件逻辑
如果不想用provide/inject,也可以在FSTable里自动处理插槽内容,给所有FSTableColumn子组件绑定所需的slotProps。
具体代码示例
FSTable组件内部:
<script setup> import { h, useSlots } from 'vue' const slots = useSlots() const props = defineProps({ data: { type: Array, required: true }, headerData: { type: Object, required: true } }) // 处理表头插槽,自动给FSTableColumn传递slotProps const renderHeader = () => { const headerSlot = slots.header?.() || [] return headerSlot.map(vnode => { // 通过组件名称识别FSTableColumn if (vnode.type.name === 'FSTableColumn') { vnode.props = { ...vnode.props, slotProps: { headerData: props.headerData } } } return vnode }) } // 处理单元格插槽,同理 const renderCell = (item) => { const cellSlot = slots.cell?.({ item }) || [] return cellSlot.map(vnode => { if (vnode.type.name === 'FSTableColumn') { vnode.props = { ...vnode.props, slotProps: { cellData: item } } } return vnode }) } </script> <template> <table> <thead> <tr> <render-header /> </tr> </thead> <tbody> <tr v-for="item in data" :key="item.id"> <render-cell :item="item" /> </tr> </tbody> </table> </template>
这种方式下,使用组件的写法和第一种方法完全一致,无需手动传递slotProps。
注意事项
- 用provide/inject时,务必给inject设置默认值,避免FSTableColumn在非FSTable内部使用时出现报错。
- 第二种方法依赖组件名称识别,如果后续修改组件名称,要同步调整判断逻辑,也可以给FSTableColumn加一个自定义属性(比如
isTableColumn)来做更可靠的识别。
内容的提问来源于stack exchange,提问作者Daniel P.
相关产品推荐
相关产品推荐

