我创建了一个组件,用于显示各个页面的表数据。该组件内部使用b-table。现在,对于几页,我想自定义一些列的呈现,Bootstrap Tables允许使用具有特殊语法的作用域字段槽:
<template #cell(field)="data">
{{ data.item.value }}
</template>
其中field-列名,来自我的带列数组,data.item-要呈现的单元格项。
问题是,我对不同的页面有不同的字段,所以这个自定义应该来自父组件,并且这些模板应该是动态创建的。
以下是我试图解决的方法:
将属性传递给MyTableComponent一个具有可自定义字段和唯一槽名的数组在MyTableComponent中动态创建自定义模板,在内部动态创建命名槽
从父通道槽数据到命名槽
MyTableComponent:
<b-table>
<template v-for="slot in myslots" v-bind="cellAttributes(slot)">
<slot :name="slot.name"></slot>
</template>
</b-table>
<script>
...
computed: {
cellAttributes(slot) {
return ['#cell(' + slot.field + ')="data"'];
}
}
...
</script>
父级:
<MyTableComponent :myslots="myslots" :items="items" :fields="fields">
<template slot="customSlot1">
Hello1
</template>
<template slot="customSlot1">
Hello2
</template>
</MyTableComponent>
<script>
...
items: [...my items...],
fields: [...my columns...],
myslots: [
{ field: "field1", name: "customSlot1" },
{ field: "field2", name: "customSlot2" }
]
...
</script>
不幸的是,b-table组件忽略了我的自定义插槽,就像没有提供一样。如果我在MyTableComponent中直接指定它,它就会工作:
<b-table>
<template #cell(field1)="data">
{{ data.item.value }}
</template>
</b-table>
但我需要通过组件属性动态地完成它。请帮忙。
您可以使用Vue 2的动态插槽名称功能将所有(或部分(插槽从父插槽传递到子插槽内的<b-table>
,如下所示:
儿童:
<b-table>
<template v-for="(_, slotName) of $scopedSlots" v-slot:[slotName]="scope">
<slot :name="slotName" v-bind="scope"/>
</template>
</b-table>
$scopedSlots包含传递给组件的所有插槽。
现在这将工作:
<MyTableComponent :items="items" :fields="fields">
<template #cell(field1)="data">
{{ data.item.value }}
</template>
</ MyTableComponent>
更新2-Vue 3
要使上面的代码在Vue 3中工作,只需按照迁移指南的建议,用$slots
替换$scopedSlots
更新1
如果需要,您可以通过创建
computed
来筛选$scopedSlots
(有一些特定于包装器组件的插槽,您不想传递给<b-table>
(
我在最初的回答中提到了这种可能性,但它有点问题,所以值得更好的解释。。。
作用域槽作为函数传递给组件(调用时生成VNode(。目标组件只执行她知道的(按名称(,而忽略其余部分。所以假设你的包装器内部有
b-table
(或Vuetify的v-data-table
(和其他组件,比如分页。您可以在这两个插槽中使用上面的代码,将所有插槽传递给每个插槽。除非存在命名冲突(两个组件都使用相同的槽名(,否则它将正常工作,不会产生任何额外的成本(所有槽函数在传递给包装组件时都已编译/创建(。目标组件将只使用(执行(其通过名称知道的插槽。如果可能存在命名冲突,可以通过使用一些命名约定来解决,例如在仅用于
b-table
的插槽名称前面加上table--
之类的前缀,并在内部进行筛选,但要注意$scopedSlots
对象确实包含一些Vue内部属性,这些属性必须一起复制(Vue 2的$stable
、$key
和$hasNormal
-请参阅代码(。因此,下面的过滤代码即使非常好,也不会抛出任何错误也不会工作(b-table
不会识别和使用插槽(
<b-table>
<template v-for="(_, slotName) of tableSlots" v-slot:[slotName]="scope">
<slot :name="slotName" v-bind="scope"/>
</template>
</b-table>
computed: {
tableSlots() {
const prefix = "table--";
const raw = this.$scopedSlots;
const filtered = Object.keys(raw)
.filter((key) => key.startsWith(prefix))
.reduce(
(obj, key) => ({
...obj,
[key.replace(prefix, "")]: raw[key],
}),
{}
);
return filtered;
},
},
这个代码可以通过包括上面提到的属性来修复,但这对Vue内部实现的依赖性太大了,我不建议这样做。如果可能的话,坚持场景1…