1 vue.js vuejs2 bootstrap-vue vuejs-slots
我创建了一个显示各个页面的表格数据的组件。该组件内部使用b-table。现在,对于几个页面,我想自定义某些列的呈现,Bootstrap Tables 允许使用具有特殊语法的作用域字段槽:
<template #cell(field)="data">
{{ data.item.value }}
</template>
Run Code Online (Sandbox Code Playgroud)
其中 field - 列名称,来自我的包含列的数组,以及 data.item - 要呈现的单元格项目。
问题是我对不同的页面有不同的字段,因此这种自定义应该来自父组件,并且这些模板应该动态创建。
这是我尝试解决它的方法:
通过属性将具有可自定义字段和唯一插槽名称的数组传递给 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>
Run Code Online (Sandbox Code Playgroud)
家长:
<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>
Run Code Online (Sandbox Code Playgroud)
不幸的是,b-table组件只是忽略我的自定义插槽,就像未提供它们一样。如果我直接在 MyTableComponent 中指定它,它就可以工作:
<b-table>
<template #cell(field1)="data">
{{ data.item.value }}
</template>
</b-table>
Run Code Online (Sandbox Code Playgroud)
但我需要它通过组件属性动态完成。请帮忙。
您可以使用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>
Run Code Online (Sandbox Code Playgroud)
$scopedSlots包含传递给组件的所有插槽。
现在这将起作用:
<MyTableComponent :items="items" :fields="fields">
<template #cell(field1)="data">
{{ data.item.value }}
</template>
</ MyTableComponent>
Run Code Online (Sandbox Code Playgroud)
更新 2 - Vue 3
要使上述代码在 Vue 3 中工作,只需按照迁移指南$scopedSlots的建议替换为$slots
更新1
如果需要,您可以通过创建来过滤
$scopedSlots(有一些特定于您不想传递给的包装组件的插槽<b-table>)computed
我在原来的答案中提到了这种可能性,但它有点问题,所以值得更好的解释......
作用域槽作为函数传递给组件(调用时生成 VNode)。目标组件只执行她知道的那些(按名称)并忽略其余的。假设您的包装器内部有b-table(或v-data-table对于 Vuetify)和一些其他组件,比如分页。您可以在它们两个内部使用上面的代码,将所有插槽传递给每个。除非存在一些命名冲突(两个组件都使用相同的插槽名称),否则它将正常工作并且不会产生任何额外的成本(所有插槽函数在传递给包装器组件时都已编译/创建)。目标组件将仅使用(执行)它通过名称知道的插槽。
如果可能存在命名冲突,可以通过使用一些命名约定来解决,例如为插槽名称添加b-table前缀table--以及在内部进行过滤,但要注意$scopedSlots对象确实包含一些必须一起复制的 Vue 内部属性!($stable以及Vue 2 - 请参阅$key代码)。因此,下面的过滤代码即使完全正常并且不会抛出任何错误也将不起作用(将无法识别和使用插槽)$hasNormalb-table
<b-table>
<template v-for="(_, slotName) of tableSlots" v-slot:[slotName]="scope">
<slot :name="slotName" v-bind="scope"/>
</template>
</b-table>
Run Code Online (Sandbox Code Playgroud)
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;
},
},
Run Code Online (Sandbox Code Playgroud)
可以通过包含上面提到的属性来修复此代码,但根据我的口味,这对 Vue 内部实现有太多依赖,因此我不推荐它。如果可能的话,坚持场景1...
| 归档时间: |
|
| 查看次数: |
8467 次 |
| 最近记录: |