Vue.js组件中如何传递动态插槽至内部的Vuetify数据表格
Vue.js组件中如何传递动态插槽至内部的Vuetify数据表格
嘿,这个需求其实很常见,核心就是要实现插槽透传——把外部传给你的FancyTable的插槽,原封不动地传递给内部的VDataTableServer组件。Vue给我们提供了非常简洁的方式来搞定这个,完全不用写一堆硬编码的模板。
核心思路
我们可以通过遍历FancyTable接收到的所有插槽,动态地把它们绑定到内部的VDataTableServer上。在Vue 3中,所有插槽(包括作用域插槽)都统一在$slots对象里,直接遍历它的键就可以覆盖所有情况。
修改你的FancyTable组件
首先把原来硬编码的item.address_type插槽删掉,然后在VDataTableServer内部添加一个动态遍历插槽的模板:
<template> <v-data-table-server :items="items" :items-length="totalItems" @update:options="fetchData" item-key="id" > <!-- 动态透传所有外部传入的插槽给VDataTableServer --> <template v-for="(_, slotName) in $slots" #[slotName]="slotProps" > <slot :name="slotName" v-bind="slotProps"></slot> </template> </v-data-table-server> </template>
然后修改script部分,因为现在BuildingIcon是外部使用时传入的,所以FancyTable不需要再引入它了:
<script> import { VDataTableServer } from 'vuetify/components' export default { name: 'FancyTable', components: { VDataTableServer }, // 移除BuildingIcon的注册 data: () => ({ totalItems: 0, items: [], options: {} }), props: { endpoint: { type: String, required: true } }, watch: { options: { handler() { this.fetchData() }, deep: true } }, methods: { fetchData: function () { const { sortBy, sortDesc, page, itemsPerPage } = this.options console.log('fetching / faking results from: ', this.endpoint) let fake_backend_results = [] let fake_backend_count = 0 if (this.endpoint === '/api/buildings') { fake_backend_results = [ { id: 0, address_type: 'building', address: 'Berliner Tor 13' }, { id: 1, address_type: 'building', address: 'Berliner Tor 15' }, { id: 2, address_type: 'cabinet', address: 'Berliner Tor 17' }, { id: 3, address_type: 'cabinet', address: 'Berliner Tor 19' }, { id: 4, address_type: 'booth', address: 'Berliner Tor 21' } ] fake_backend_count = 27 } else if (this.endpoint === '/api/persons') { fake_backend_results = [ { id: 35, first_name: 'Jane', last_name: 'Doe' }, { id: 36, first_name: 'John', last_name: 'Doe' } ] fake_backend_count = 2 } this.items = fake_backend_results this.totalItems = Number(fake_backend_count) } } } </script>
现在可以按你想要的方式使用组件了
修改后的FancyTable完全支持外部传入任意动态插槽,就像你预想的那样:
<!-- 用于建筑数据的表格,自定义address_type列 --> <FancyTable endpoint="/api/buildings"> <template #[`item.address_type`]="{ item }"> <building-icon :icon="item.address_type"></building-icon> </template> </FancyTable> <!-- 用于人员数据的表格,甚至可以给不同列加自定义插槽 --> <FancyTable endpoint="/api/persons"> <template #[`item.first_name`]="{ item }"> <span style="color: #2196F3; font-weight: bold;">{{ item.first_name }}</span> </template> <template #[`item.last_name`]="{ item }"> <span style="color: #4CAF50;">{{ item.last_name }}</span> </template> </FancyTable>
补充:Vue 2的兼容写法
如果你的项目还是Vue 2,需要区分普通插槽和作用域插槽,分别遍历$slots和$scopedSlots:
<template v-for="(_, slotName) in $slots" :slot="slotName"> <slot :name="slotName"></slot> </template> <template v-for="(_, slotName) in $scopedSlots" :slot="slotName" slot-scope="slotProps"> <slot :name="slotName" v-bind="slotProps"></slot> </template>
原理说明
这种方式本质上是利用Vue的插槽系统,把中间组件(FancyTable)变成一个“插槽转发器”——它不关心外部传入什么插槽,只是把所有接收到的插槽原封不动地传递给内部的目标组件(VDataTableServer),这样你就可以完全从外部控制内部数据表格的列自定义逻辑,让组件的通用性大大提升。
备注:内容来源于stack exchange,提问作者Mark Asbach
相关产品推荐
相关产品推荐

