You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 19:59:49