Vue插槽内的BootstrapVue表模板

Posted

技术标签:

【中文标题】Vue插槽内的BootstrapVue表模板【英文标题】:BootstrapVue table-template inside Vue slot 【发布时间】:2018-12-05 00:30:41 【问题描述】:

我想为带有自定义数据呈现(模板)的 bootstrap-vue 表创建一个父组件。

现在,有点像这样:

<b-table
     :items="result"
     :fields="fields"
     :current-page="currentPage"
     :per-page="perPage">
    <template slot="Index" slot-scope="data">
         data.index + 1 
    </template>
    <!-- more templates for various columns here -->
</b-table>
<b-pagination 
     align="center" 
     :total-rows="result.length" 
     v-model="currentPage" 
     :per-page="perPage"
/>

我想将它包装在一个组件中的原因是因为我多次使用这个表格布局,包括分页及其所有属性(如条纹、边框等)。

唯一改变的是列模板。

我知道,Vue 的做法是创建一个类似&lt;slot name="x"&gt;&lt;/slot&gt; 的槽并用&lt;template slot="x"&gt;...&lt;/template&gt; 填充它。一方面,这与 bootstrap-vue template 一致,另一方面,bootstrap-vue 似乎只能正确呈现模板,前提是它们正好放置在 b-table 内。

基本上,我想要实现的是这样一个组件:

<b-table>
    <slot name="templates"/>
</b-table>
<b-pagination stuff.../>

并在这样的子组件中使用它:

<TemplateTable>
    <template slot="templates">
        <template slot="Index" slot-scope="data">
             data.index + 1 
        </template>
        <!-- more templates -->
    </template>
</TableTemplate>

有没有人做过类似的事情并想出了解决办法?

【问题讨论】:

【参考方案1】:

只需构建您的自定义组件并传递您需要的任何自定义道具,如下所示:

<template>
  <b-table v-bind="$attrs" v-on="$listeners" custom-prop="any">
    <slot v-for="(_, name) in $slots" :name="name" :slot="name" />
    <template
      v-for="(_, name) in $scopedSlots"
      :slot="name"
      slot-scope="slotData"
      ><slot :name="name" v-bind="slotData"
    /></template>
  </b-table>
</template>

<script>
export default 
  name: 'AppTable',

</script>

<style scoped></style>


这就像一个魅力!

【讨论】:

【参考方案2】:

感谢@nardnob,这是我在.vue 组件中使用的。所有b-table 组件都已加载到我的app.js 文件中。因此缺少导入语句。

首先是TableWrapper.vue。我添加了Object.assign(this.$attrs, this.$props) 以确保CustomTable 中的任何未定义props 仍将通过组合$attrs$props 继续传递到b-table

<script>
    export default 
        components: ,

        props: [
          'items',
          'fields'
        ],

        mixins: [],

        data: function () 
            return 
                //
            
        ,

        render(h) 
            return h('b-table', 
                props: Object.assign(this.$attrs, this.$props),
                slots: this.$parent.$slots,
                scopedSlots: this.$parent.$scopedSlots,
                on: 
                    // 'row-clicked': (item, index, event) => alert('clicked ' + index)
                
            );
        ,

        computed: 
            //
        ,

        created() 
            //
        ,

        mounted() 
            //
        ,

        methods: 
            //
        ,

        watch: 
            //
        
    
</script>

然后CustomTable.vue

<template>
    <table-wrapper
            :items="items"
            :fields="fields"
            :striped="true"
    ></table-wrapper>
</template>

<script>
    export default 
        components: ,

        props: [
          'fields',
          'items',
        ],

        mixins: [],

        data: function () 
            return 
                //
            
        ,

        computed: 
            //
        ,

        created() 
            //
        ,

        mounted() 
            //
        ,

        methods: 
            //
        ,

        watch: 
            //
        
    
</script>

最后:

<custom-table
    :fields="[
        
            key: 'code',
            label: 'Code',
        ,
        
            key: 'title',
            label: 'Titel',
        ,
        
            key: 'start_date',
            label: 'Start',
        ,
        
            key: 'end_date',
            label: 'End',
        ,
        
            key: 'log',
            label: 'Log'
        
    ]"
    :items="episodes"
>
    <template v-slot:cell(log)="data">
        <i class="fa-icon fa-search ml-1 is-hoverable" @click="test"></i>
    </template>

</custom-table>

【讨论】:

【参考方案3】:

You can use a component's render function 将 slot 和 scopedSlots 传递给另一个组件(如 b-table)。但是你不能使用模板。为了让您拥有一个模板(带有分页、搜索等),您可以将呈现组件包装到另一个确实具有模板的组件中。那么你将拥有一个包含分页的custom-table 组件和一个table-wrapper 组件,而table-wrapper 组件将呈现一个b-table

这是一个非常具体的例子..

const constItems = [
    index: 0,
    isActive: true,
    age: 40,
    first_name: 'Dickerson',
    last_name: 'Macdonald'
  ,
  
    index: 1,
    isActive: false,
    age: 21,
    first_name: 'Larsen',
    last_name: 'Shaw'
  ,
  
    index: 2,
    isActive: false,
    age: 89,
    first_name: 'Geneva',
    last_name: 'Wilson'
  ,
  
    index: 3,
    isActive: true,
    age: 38,
    first_name: 'Jami',
    last_name: 'Carney'
  
];

const bTableProps = 
  items: 
    type: [Array, Function],
    default: undefined
  ,
  fields: 
    type: [Object, Array],
    default: undefined
  
;

const constFields = [
  'index',
  'isActive',
  'age',
  'first_name',
  'last_name'
];

Vue.component('table-wrapper', 
  props: Object.assign(, bTableProps),
  render(h) 
    return h('b-table', 
      props: this.$props,
      slots: this.$parent.$slots,
      scopedSlots: this.$parent.$scopedSlots,
      on: 
        'row-clicked': (item, index, event) => alert('clicked ' + index)
      
    );
  
);

Vue.component('custom-table', 
  template: '<div><h3>hello table</h3><table-wrapper :items="items" :fields="fields"></table-wrapper></div>',
  props: Object.assign(, bTableProps)
);

new Vue(
  el: "#app",
  data: 
    items: constItems,
    fields: constFields
  
);
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link href="https://unpkg.com/bootstrap@4.1.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue@2.0.0-rc.11/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://unpkg.com/babel-polyfill@6.26.0/dist/polyfill.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue@2.0.0-rc.11/dist/bootstrap-vue.js"></script>

<div id="app">
  <custom-table :items="items" :fields="fields">
    <template slot="index" slot-scope="data">
			 data.index + 1 
		</template>
  </custom-table>
  <custom-table :items="items" :fields="fields">
    <template slot="index" slot-scope="data">
			 data.index + 2 
		</template>
  </custom-table>
  <custom-table :items="items" :fields="fields">
    <template slot="index" slot-scope="data">
			 data.index + 3 
		</template>
  </custom-table>
</div>

【讨论】:

感谢分享!它让我完全陷入困境,试图弄清楚。我也会发布我的.vue 解决方案以供将来参考:) 很高兴它可以提供帮助。我将其发布为我自己的未来参考和其他所有人一样=)

以上是关于Vue插槽内的BootstrapVue表模板的主要内容,如果未能解决你的问题,请参考以下文章

如何在 b-table 的 v-slot:cell() 模板中获取项目值 - BootstrapVue

BootstrapVue - 未定义属性或方法“数据”......使用范围插槽时

将 BootstrapVue 与 Vue.Draggable 一起使用?并将项目从列表中删除到 b 表?

Vue.js 将插槽传递给包装好的 Bootstrap-Vue 表组件

Vue 3 - 从插槽内的子组件发出事件

选中Vue中一个复选框上的所有复选框