#vue.js #bootstrap-vue
#vue.js #bootstrap-vue
Вопрос:
В настоящее время я пишу свое первое приложение с полным стеком. Я использую bootstrap <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, ...}]
Если это невозможно, есть ли какой-нибудь другой элемент начальной загрузки, который имеет больше смысла для достижения того, чего я хочу?
Комментарии:
1. Если это невозможно, есть ли какой-нибудь другой элемент boostrap, который имеет больше смысла для достижения того, чего я хочу? => Свернуть .
Ответ №1:
Чтобы строго ответить на ваш вопрос: нет, <b-table>
row-details
строка BootstrapVue не может быть расширена более чем на одну строку.
row-details
Строка имеет серьезные ограничения:
- это только одна строка
- на самом деле это только одна ячейка, которая при использовании
colspan
расширяется на всю ширину строки (что означает, что вы не можете использовать столбцы таблицы для выравнивания содержимогоrow-details
строки).
Но … это веб. В web, поскольку он виртуальный, возможно практически все. Если это не так, вы делаете неправильно ™.
То, что вы хотите, достижимо путем rows
полной замены при расширении строки, использования a 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 amp;amp; (row.expanded = !row.expanded)"
:class="{parent: row.children}">
<td>{{row.id}}</td>
<td>{{row.name}}</td>
</tr>
</table>
</div>
Пример довольно простой (я не добавлял к нему BootstrapVue и не использовал его фантазии <b-table>
), но он демонстрирует принцип. Примените его к <b-table>
‘s :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 amp;amp; 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:
Один из подходов (который я лично использовал в прошлом) заключается в том, чтобы просто поместить вложенный <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>
Комментарии:
1. Если вы используете вложенные таблицы, вы теряете самую ценную способность таблицы: динамическое изменение размера столбца в зависимости от содержимого. Я имею в виду, именно по этой причине люди используют таблицы. Вы можете либо использовать столбцы одинакового размера (но если вы хотите, чтобы у вас были лучшие варианты, чем таблицы), либо вы можете динамически применять ширину столбцов дочерней таблицы из ширины столбцов родительской таблицы с включенным прослушивателем
resize
. Но я бы сказал, что простое добавление классов к строкам для отличия родителей от дочерних элементов — это значительно более чистый подход. Я использовал вложенные таблицы. Это становится слишком беспорядочным слишком быстро.2. Я согласен настолько, что если OP ищет несколько уровней вложенности, то это может быстро запутаться (и сжаться). Я не согласен с тем, что вы теряете динамическое изменение размера —
bootstrap-vue
таблицы обрабатывают изменение размера столбцов для каждой таблицы, поэтому я не вижу, как вложенная таблица вообще уменьшает это.3. Столбцы вложенной таблицы не выровнены с родительскими столбцами !? Вы теряете это с самого начала.
4. Полагаю, я вас неправильно понял, вы правы в этом. Я просто не вижу в этом полезного условия, если данные дочерней строки имеют поля, отличные от родительских, что верно в данном случае.
5. Таблицы должны использоваться для табличных данных. Не для макета. Итак, подумайте о таблице, показывающей продажи за разные периоды. И когда вы нажимаете на одну, должны отображаться все транзакции этого периода (или, возможно, меньшая единица периода, которую также можно расширить). Очевидно, вам нужно выровнять суммы и количества. Если у вас нет табличных данных, вам следует использовать даже не таблицу, а неупорядоченный список. Верно?