在bootstrap vue中将行细节拆分为多行



我目前正在编写我的第一个全栈应用程序。我正在使用引导程序<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>

示例

在附加的图像中,底部的一行已被单击。内容显示在一行中,但我希望它是单独的行,这样以后我可以进一步单击它们来显示更多嵌套的内容。

数据示例:

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

如果这是不可能的,是否还有其他Bootstrap元素可以更合理地实现我想要的目标?

要严格回答您的问题:不,BootstrapVue<b-table>row-details行不能扩展为多行。

row-details行有严重的限制:

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

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

通过在展开行时完全替换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,也没有使用它的高级<b-table>(,但它演示了原理。将其应用于<b-table>: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>

一种方法(我个人过去曾使用过(只是将嵌套的<b-table>放入子数据的子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>

最新更新