在 bootstrap-vue 中将行详细信息拆分为多行

Posted

技术标签:

【中文标题】在 bootstrap-vue 中将行详细信息拆分为多行【英文标题】:Split row-details into multiple row in bootstrap-vue 【发布时间】:2021-04-16 21:04:51 【问题描述】:

我目前正在编写我的第一个全栈应用程序。我正在使用引导程序<b-table> 来显示内容。在row-click 上,我展开该行以显示嵌套数据。有没有办法遍历嵌套数据并将其显示在父 b 表中的嵌套行中?

目前,我可以显示数据,但它显示在一行中。

component.vue:

<template>
    <div id="report-table" class="report-table">
        <b-container>
            <b-table striped hover sticky-header="100%" 
            :items="reports" 
            :fields="fields"
            responsive="xl"
            @click="clearRowClick"
            @row-clicked="reports=>$set(reports, '_showDetails', !reports._showDetails)"
            >
                <template slot="row-details" slot-scope="row">
                    <template v-for="(proc, index) in row.item.Processes">
                        <b-tr :key=index>
                            <td> proc.Name </td>
                            <td> proc.Id </td>
                        </b-tr>
                    </template>
                </template>
            </b-table>
        </b-container>
    </div>
</template>

example

在所附图片中,底部一行已被点击。内容显示在一行中,但我希望它是单独的行,以便稍后我可以进一步单击它们以显示更多嵌套内容。

数据示例:

"_id": <id>, "Hostname": <hostname>, "Address": <address>, "Processes": ["Name": ApplicationHost, ..., "Name": svchost, ...]

如果这不可能,是否还有其他一些 Bootstrap 元素对实现我想要的更有意义?

【问题讨论】:

如果这是不可能的,是否还有一些其他的 boostrap 元素对实现我想要的更有意义? => Collapse. 【参考方案1】:

严格回答您的问题:不,BootstrapVue &lt;b-table&gt;row-details 行不能扩展到多行。

row-details 行有严格的限制:

只有一行 实际上只有一个单元格,通过使用colspan 扩展到行的全宽(这意味着您不能真正使用表格列来对齐row-details 行的内容)。

但是……这是网络。在网络中,因为它是虚拟的,所以几乎任何事情都是可能的。如果不是,您就做错了™。

您想要的可以通过在展开行时完全替换 rows、使用 computed 并在父行处于展开状态时将子行连接到其父行来实现。概念证明:

Vue.config.productionTip = false;
Vue.config.devtools = false;
new Vue(
  el: '#app',
  data: () => (
    rows: [
      id: '1', name: 'one', expanded: false, children: [
        id: '1.1', name: 'one-one',
        id: '1.2', name: 'one-two',
        id: '1.3', name: 'one-three'
      ],
      id: '2', name: 'two', expanded: false, children: [
        id: '2.1', name: 'two-one',
        id: '2.2', name: 'two-two',
        id: '2.3', name: 'two-three'
      ]
    ]
  ),
  computed: 
    renderedRows() 
      return [].concat([...this.rows.map(row => row.expanded 
        ? [row].concat(row.children)
        : [row]
       )]).flat()
    
  
)
tr.parent  cursor: pointer 
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <table>
    <tr v-for="row in renderedRows" :key="row.id"
        @click="row.children && (row.expanded = !row.expanded)"
        :class="parent: row.children">
      <td>row.id</td>
      <td>row.name</td>
    </tr>
  </table>
</div>

这个例子比较基础(我没有添加 BootstrapVue,也没有使用它的花哨&lt;b-table&gt;),但它演示了原理。将其应用于&lt;b-table&gt;:items


我们甚至可以更进一步,使其递归,将扩展逻辑移入一个方法中:

new Vue(
  el: '#app',
  data: () => (
    fields: ['id',   key: 'expanded', label: '', 'name'],
    rows: [
        id: '1',
        name: 'one',
        expanded: false,
        children: [
           id: '1.1', name: 'one-one' ,
           id: '1.2', name: 'one-two' ,
          
            id: '1.3',
            name: 'one-three',
            expanded: false,
            children: [
               id: '1.3.1', name: 'one-three-one' ,
               id: '1.3.2', name: 'one-three-two' 
            ]
          
        ]
      ,
      
        id: '2',
        name: 'two',
        expanded: false,
        children: [
           id: '2.1', name: 'two-one' ,
           id: '2.2', name: 'two-two' ,
           id: '2.3', name: 'two-three' 
        ]
      
    ]
  ),
  computed: 
    items() 
      return [].concat(this.rows.map(row => this.unwrapRow(row))).flat()
    
  ,
  methods: 
    unwrapRow(row) 
      return row.children && row.expanded
        ? [row].concat(...row.children.map(child => this.unwrapRow(child)))
        : [row]
    ,
    tbodyTrClass(row) 
      return  parent: row.children?.length, child: row.id.includes('.') 
    
  
)
.table td:not(:last-child)  width: 80px; 
.table .bi  cursor: pointer 
tr.child 
  background-color: #f5f5f5;
  font-style: italic;
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.css" />
<script src="//cdn.jsdelivr.net/npm/vue@2.6.14"></script>
<script src="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script>
<script src="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue-icons.min.js"></script>

<div id="app">
  <b-table :items="items"
           :fields="fields"
           :tbody-tr-class="tbodyTrClass">
    <template #cell(expanded)="item">
      <b-icon v-if="item.children"
              :icon="item.expanded ? 'chevron-up' : 'chevron-down'"
              @click="item.expanded = !item.expanded" />
    </template>
  </b-table>
</div>

【讨论】:

【参考方案2】:

一种方法(我个人过去曾使用过)是简单地将嵌套的&lt;b-table&gt; 放在您的孩子row-details 中用于子数据,而不是尝试将它们添加到外部表中。

还值得注意的是,如果将子数据行添加到外部表中,如果它们看起来与父数据的区别不够大,可能会在视觉上造成混乱。

例子:

new Vue(
  el: '#app',
  data() 
    return 
      reports: [_id: 'ID#1', Hostname: 'Host1', Address: 'Addr1', Processes: [Name: 'ApplicationHost', Id: '1', Name: 'svchost', Id: '2'],
        _id: 'ID#2', Hostname: 'Host2', Address: 'Addr2', Processes: [Name: 'ApplicationHost', Id: '3', Name: 'svchost', Id: '4'],],
      fields: ['Hostname', 'Address'],
    
  ,
);
<!-- Import Vue and Bootstrap-Vue -->
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap@4/dist/css/bootstrap.min.css" /><link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.css" /><script src="//unpkg.com/vue@latest/dist/vue.min.js"></script><script src="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script>

<div id="app">
    <b-table
      bordered
      striped
      hover
      :items="reports" 
      :fields="fields" 
      @row-clicked="reports=>$set(reports, '_showDetails', !reports._showDetails)"
    >
      <!-- <b-table> nested inside 'row-details' slot: -->
      <template #row-details="row">
        <b-table
          bordered
          :items="row.item.Processes"
          :fields="['Name', 'Id']"
        ></b-table>
      </template>
    </b-table>
</div>

【讨论】:

如果您使用嵌套表格,您将失去表格最有价值的能力:根据内容动态调整列大小。我的意思是,这就是人们使用表格的原因。您可以使用大小相等的列(但如果您希望有比表格更好的选项),也可以使用resize 上的侦听器动态地从父表列宽度强制执行子表列宽度。但我想说简单地向行添加类以区分父母和孩子是一种非常干净的方法。我用过嵌套表。它变得太混乱太快了。 我同意如果 OP 正在寻找多个嵌套级别,那么它可能会很快变得混乱(并且被压扁)。我不同意你失去动态调整大小-bootstrap-vue 表处理每个表的列大小调整,所以我看不出嵌套表如何减少这一点。 嵌套表的列未与父列对齐!?你从一开始就放弃了。 我想我误解了你,你说得对。如果子行数据具有与父行不同的字段,我只是不认为这是一个有用的条件,在这种情况下是正确的。 表格应该用于表格数据。不是为了布局。因此,请考虑一张显示不同时期销售额的表格。当您单击一个时,应显示该时期的所有交易(或者可能是一个较小的时期单位,也可以展开)。您显然希望总和和数量保持一致。如果您没有表格数据,您甚至不应该使用表格,而是使用无序列表。对吗?

以上是关于在 bootstrap-vue 中将行详细信息拆分为多行的主要内容,如果未能解决你的问题,请参考以下文章

bootstrap-vue 表上显示详细信息的问题

如何在拆分视图iOS中将不同的视图加载到详细视图

如何在 Spark DataFrame/DataSet 中将行拆分为不同的列?

如何在Oracle中将表行拆分为固定大小的块

在 SQL 中将分隔的行拆分为列

基于发票行项目检查的 SSIS SQL 拆分文件