首页 > 解决方案 > 根据来自 API 的响应显示多个引导 VueJS 表

问题描述

我正在使用 bootstrap-vue 表。目前,我的整个数据都驻留在一张表中。假设该表中有 10 行,前 5 行包含A第一列中的值,而接下来的 5 行包含B第一列中的值。

我想要的是,我不是有一个包含完整数据的表,而是划分这个表,这样我的页面上就会出现两个表。第一个表将包含所有具有值A的行,第二个表将包含所有具有值的行B。实际上,我会有很多这些独特的值,所以假设我有 10 个这样的值,我想要基于这些值的 10 个这样的单独的表。这可能吗?

另一个想法可能是,如果以上不可能,我可以有可折叠的行吗?我不是在谈论More Details功能,而是当我单击 时A,所有具有值的行都A将出现在同一个表中,每个行都在表中显示为一行。

我最初考虑让行可以跨列(在引导 Vue 表中对行进行分组),但不幸的是,引导 vue-js 表还不支持。

标签: javascripttwitter-bootstrapvue.jsvuejs2

解决方案


您可以通过使用将数组拆分为组的计算属性来做到这一点。

此计算属性将返回一个对象,其中包含一个键,该键将是您要分组的值,该值将是一个包含该组中所有项目的数组。

/* Example structure that the computed property will return */
{
  A: [],
  B: [],
  C: []
}

然后,您可以使用 av-for查看groupedItems

<!-- 
  groupedItems is the computed property, containing the structure shown above.
  Will create a new table for each type/key in the `groupedItems` property.
-->
<div v-for="(group, type) in groupedItems">
  <b-table :fields="fields" :items="group"><b-table>
</div>

示例片段:

一个相当基本的示例,它只显示类型的标题和下面的表格。

/* Generate some random example data */
const types = ['A', 'B', 'C']
const items = [];
for(let i = 0; i < 15; i++) {
  items.push({
    type: types[i % 3],
    id: i + 1,
    random: Math.random()
  })
}

new Vue({
  el: '#app',
  computed: {
    groupedItems() {
      const groups = {};
      
      this.items.forEach(item => {
        if(groups[item.type]) {
          groups[item.type].push(item);
        } else {
          groups[item.type] = [item];
        }
      });

      return groups;
    }
  },
  data() {
    return {
      items: items,
      fields: ['type', 'id', 'random']
    }
  }
})
<link href="https://unpkg.com/bootstrap@4.5.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue@2.15.0/dist/bootstrap-vue.css" rel="stylesheet" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue@2.15.0/dist/bootstrap-vue.js"></script>


<div id="app">
  <div v-for="(items, type) in groupedItems">
    <h2>Type: {{ type }}</h2>
    <b-table :fields="fields" :items="items">
      <template #cell(type)="{ value }">
        Type: {{ value }}
      </template>
    </b-table>
  </div>
</div>


使用手风琴的例子

此示例使用手风琴,以允许打开/关闭每个组。Accoridon 只允许在一个类型中打开一个组。如果你不想要这个,你可以accordion="table-accordion"b-collapseso中移除多个可以同时打开。

/* Generate some random example data */
const types = ['A', 'B', 'C']
const items = [];
for(let i = 0; i < 15; i++) {
  items.push({
    type: types[i % 3],
    id: i + 1,
    random: Math.random()
  })
}

new Vue({
  el: '#app',
  computed: {
    groupedItems() {
      const groups = {};

      this.items.forEach(item => {
        if(groups[item.type]) {
          groups[item.type].push(item);
        } else {
          groups[item.type] = [item];
        }
      });

      return groups;
    }
  },
  data() {
    return {
      items: items,
      fields: ['type', 'id', 'random']
    }
  }
})
<link href="https://unpkg.com/bootstrap@4.5.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue@2.15.0/dist/bootstrap-vue.css" rel="stylesheet" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue@2.15.0/dist/bootstrap-vue.js"></script>


<div id="app">
  <b-card no-body class="mb-1" v-for="(group, type) in groupedItems">
    <b-card-header header-tag="header" class="p-0" role="tab">
      <b-button block v-b-toggle="`accordion-${type}`" variant="primary">
        Type {{ type }}
      </b-button>
    </b-card-header>
    <b-collapse :id="`accordion-${type}`" accordion="table-accordion" role="tabpanel">
      <b-table :fields="fields" :items="group"></b-table>
    </b-collapse>
  </b-card>
</div>


基于评论请求的附加示例。

您可以通过再次执行相同的操作轻松添加另一个级别,但将其嵌套更深一层。

/* Generate some random example data */
const types = ['A', 'B', 'C']
const items = [];
for(let i = 0; i < 30; i++) {
  items.push({
    type: types[i % 3],
    group: i % 9,
    id: i + 1,
    random: Math.random()
  })
}

new Vue({
  el: '#app',
  computed: {
    groupedItems() {
      const groups = {};

      this.items.forEach(item => {
        if(!groups[item.type]) groups[item.type] = {};

        if(groups[item.type][item.group]) {
          groups[item.type][item.group].push(item);
        } else {
          groups[item.type][item.group] = [item];
        }
      });

      return groups;
    }
  },
  data() {
    return {
      items: items,
      fields: ['type', 'id', 'random']
    }
  }
})
<link href="https://unpkg.com/bootstrap@4.5.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue@2.15.0/dist/bootstrap-vue.css" rel="stylesheet" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue@2.15.0/dist/bootstrap-vue.js"></script>


<div id="app">
  <b-card no-body class="mb-4" v-for="(groups, type) in groupedItems">
    <b-card-header header-tag="header" class="p-0" role="tab">
      <b-button block v-b-toggle="`accordion-${type}`" variant="primary">
        Type {{ type }}
      </b-button>
    </b-card-header>
    <b-collapse :id="`accordion-${type}`" visible role="tabpanel">
      <b-card no-body v-for="(items, group) in groups">
        <b-card-header header-tag="header" class="p-0" role="tab">
          <b-button block v-b-toggle="`accordion-group-${group}`" variant="secondary">
            Type {{ group }}
          </b-button>
        </b-card-header>
        <b-collapse :id="`accordion-group-${group}`"  :accordion="`table-accordion-${type}`" role="tabpanel">
          <b-table :fields="fields" :items="items"></b-table>
        </b-collapse>
      </b-card>
    </b-collapse>
  </b-card>
</div>


推荐阅读