如何将单元格模板传递给带有 b-table 的组件? [英] How to pass cell templates to a component with b-table?

查看:33
本文介绍了如何将单元格模板传递给带有 b-table 的组件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个组件,用于显示各个页面的表格数据.该组件在内部使用 b-table.现在对于几个页面,我想自定义某些列的呈现,而 Bootstrap Tables 允许使用具有特殊语法的作用域字段槽:

I created a component that shows table data for various pages. That component uses b-table inside. Now for a couple pages I want to customize rendering of some columns, and Bootstrap Tables allow that using scoped field slots with special syntax:

    <template #cell(field)="data">
            {{ data.item.value }}
    </template>

其中字段 - 列名,来自我的带有列的数组,以及 data.item - 要呈现的单元格项.

where field - column name, coming from my array with columns, and data.item - cell item to be rendered.

问题是我对不同的页面有不同的字段,所以这个自定义应该来自父组件,而这些模板应该是动态创建的.

The problem is that I have different fields for different pages, so this customization should come from parent component, and these templates should be created dynamically.

这是我尝试解决它的方法:

Here is how I tried to solve it:

通过属性向 MyTableComponent 传递一个具有可自定义字段和唯一插槽名称的数组在 MyTableComponent 中动态创建自定义模板,在内部动态创建命名槽

Pass via property to MyTableComponent an array with customizable fields and unique slot names In MyTableComponent dynamically create templates for customization, and inside dynamically create named slots

从父传递槽数据到命名槽

From parent pass slot data to named slots

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 中指定它,它会起作用:

Unfortunately, b-table component just ignores my custom slots like if they are not provided. It works if I specify in the MyTableComponent it directly:

    <b-table>
          <template #cell(field1)="data">
            {{ data.item.value }}
          </template>
    </b-table>

但我需要通过组件属性动态完成.请帮忙.

But I need it to be done dynamically via component properties. Please help.

推荐答案

您可以使用 动态插槽名称 Vue 2 的特性,将所有(或部分)插槽从父级传递到 子级内部,如下所示:

You can use Dynamic Slot Names feature of Vue 2 to pass all (or some) slots from parent to <b-table> inside child like this:

孩子:

<b-table>
  <template v-for="(_, slotName) of $scopedSlots" v-slot:[slotName]="scope">
    <slot :name="slotName" v-bind="scope"/>
  </template>
</b-table>

$scopedSlots 包含传递给您的组件的所有插槽.

$scopedSlots contains all slots passed to your component.

现在这将起作用:

    <MyTableComponent :items="items" :fields="fields">
          <template #cell(field1)="data">
            {{ data.item.value }}
          </template>
    </ MyTableComponent>

更新 2 - Vue 3

要使上述代码在 Vue 3 中工作,只需按照 迁移指南

To make above code work in Vue 3, just replace $scopedSlots with $slots as suggested by migration guide

更新 1

如果需要,您可以过滤 $scopedSlots(有一些特定于您的包装器组件的插槽,您不想传递给 <b-table>)通过创建计算

You can filter $scopedSlots if you want (have some slot specific to your wrapper component you don't want to pass down to <b-table>) by creating computed

我在最初的回答中提到了这种可能性,但它有点问题,因此值得更好的解释...

I mentioned this possibility in my original answer but it is a bit problematic so it deserves better explanation...

  1. 作用域插槽作为函数传递给组件(在调用时生成 VNode).目标组件只执行她知道的那些(按名称)并忽略其余的.因此,假设您的包装器内部有 b-table(或用于 Vuetify 的 v-data-table)和其他一些组件,比如说分页.您可以在它们两个内部使用上面的代码,将所有插槽传递给每个.除非有一些命名冲突(两个组件使用相同的插槽名称),否则它会正常工作并且不会引起任何额外成本(所有插槽函数在传递给您的包装器组件时已经编译/创建).目标组件将仅使用(执行)它通过名称知道的插槽.

  1. Scoped slots are passed to a component as a functions (generating VNode's when called). Target component just executes those she knows about (by name) and ignores the rest. So lets say your wrapper has b-table (or v-data-table for Vuetify) inside and some other component, let's say pagination. You can use code above inside both of them, passing all slots to each. Unless there is some naming conflict (both components using same slot name), it will work just fine and does not induce any additional cost (all slot functions are already compiled/created when passed to your wrapper component). Target component will use (execute) only the slots it knows by name.

如果可能存在命名冲突,可以通过使用一些命名约定来解决,例如为b-table添加前缀的插槽名称,例如table-- 并在内部进行过滤,但要注意 $scopedSlots 对象确实包含一些必须复制的 Vue 内部属性!!($stable$key$hasNormal 用于 Vue 2 - 请参阅 代码).所以下面的过滤代码即使非常好并且不会抛出任何错误不起作用(b-table不会识别和使用插槽)

If there is possible naming conflict, it can be solved by using some naming convention like prefixing slot names intended just for b-table with something like table-- and doing filtering inside but be aware that $scopedSlots object does contain some Vue internal properties which must be copied along !! ($stable, $key and $hasNormal for Vue 2 - see the code). So the filtering code below even it's perfectly fine and doesn't throw any error will not work (b-table will not recognize and use the slots)

<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...

This code can be fixed by including the properties mentioned above but this just too much dependency on Vue internal implementation for my taste and I do not recommend it. If it's possible, stick with the scenario 1...

这篇关于如何将单元格模板传递给带有 b-table 的组件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆