bootstrap-vue b-table:在 table 重新加载时保持展开的行展开
bootstrap-vue b-table: keep expanded rows expanded on table reload
其中的 expand/collapse 部分工作得很好。
现在我正在使用 javascript startInterval() 每 2 秒重新加载一次 table。最终这将转移到网络套接字。
一般来说,作为 table load/reload 的一部分,系统通过检查 [=39] 来检查是否应该在详细信息栏中显示图标“^”或“v” =], 这很好用。
getChevron(row, index) {
if (row.detailsShowing == true) {
return "chevronDown";
}
return "chevronUp";
}
当用户选择关系列中的“^”图标时,将调用 @click=row.toggleDetails
来展开该行,然后调用函数 v-on:click="toggleRow(row)"
来跟踪用户选择的行.这使用服务器端系统生成的 guid 来跟踪。
在 2 秒内,table 将重新加载并且该行会折叠。在 load/reload 上,在它加载的第一列关系中,我调用函数 checkChild(row),根据我本地存储的数组检查行 guid,以确定这是否是应在加载时扩展的行。
<template #cell(relationship)="row"> {{checkChild(row)}} <\template>
如果行 guid 与数组中的一个匹配,我会尝试设置
checkChild(row){
var idx = this.showRows.indexOf( row.item.id);
if(idx > -1){
row.item.detailsShowing = true;
row.rowSelected = true;
row.detailsShowing == true
row._showDetails = true;
}
}
并且我能够看到我找到了匹配项,但是 none 设置为 true 的那些变量使展开的行保持打开状态,该行总是在重新加载时折叠
有人对我如何使行在 table 重新加载时保持打开状态有任何想法吗?
您的代码出现问题是因为 Vue 2 警告。在将属性添加到 data
之后向对象添加属性将 而不是 是反应性的。要解决这个问题,您必须使用 Vue.set
.
您可以阅读更多相关内容 here。
但是,像您在模板中所做的那样调用函数似乎是一种不好的做法。
您应该在获取数据后执行此操作,或者使用诸如计算 属性 之类的东西来进行映射。
这里有两个简化的例子。
API调用后映射
{
data() {
return {
items: [],
showRows: []
}
},
methods: {
async fetchData() {
const { data } = await axios.get('https://example.api')
foreach(item of data) {
const isRowExpanded = this.showRows.includes(item.id);
item._showDetails = isRowExpanded;
}
this.items = data;
}
}
}
使用计算
{
computed: {
// Use `computedItems` in `<b-table :items="computedItems">`
computedItems() {
const { items, showRows } = this;
return items.map(item => ({
...item,
_showDetails: .showRows.includes(item.id)
}))
}
},
data() {
return {
items: [],
showRows: []
}
},
methods: {
async fetchData() {
const { data } = await axios.get('https://example.api')
this.items = data;
}
}
}
有关更完整的示例,请查看下面的代码段。
const {
name,
datatype,
image
} = faker;
const getUser = () => ({
uuid: datatype.uuid(),
personal_info: {
first_name: name.firstName(),
last_name: name.lastName(),
gender: name.gender(),
age: Math.ceil(Math.random() * 75) + 15
},
avatar: image.avatar()
});
const users = new Array(10).fill().map(getUser);
new Vue({
el: "#app",
computed: {
computed_users() {
const {
expanded_rows,
users
} = this;
return users.map((user) => ({
...user,
_showDetails: expanded_rows[user.uuid]
}));
},
total_rows() {
const {
computed_users
} = this;
return computed_users.length;
}
},
created() {
this.users = users;
setInterval(() => {
users.push(getUser());
this.users = [...users];
}, 5000);
},
data() {
return {
per_page: 5,
current_page: 1,
users: [],
fields: [{
key: "avatar",
class: "text-center"
},
{
key: "name",
thClass: "text-center"
},
{
key: "personal_info.gender",
label: "Gender",
thClass: "text-center"
},
{
key: "personal_info.age",
label: "Age",
class: "text-center"
}
],
expanded_rows: {}
};
},
methods: {
onRowClicked(item) {
const {
expanded_rows
} = this;
const {
uuid
} = item;
this.$set(expanded_rows, uuid, !expanded_rows[uuid]);
}
}
});
<link href="https://unpkg.com/bootstrap@4.5.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue@2.21.2/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://unpkg.com/vue@2.6.12/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue@2.21.2/dist/bootstrap-vue.js"></script>
<script src="https://unpkg.com/faker@5.5.3/dist/faker.min.js"></script>
<div id="app" class="p-3">
<b-pagination v-model="current_page" :per-page="per_page" :total-rows="total_rows">
</b-pagination>
<h4>Table is refresh with a new item every 5 seconds.</h4>
<h6>Click on a row to expand the row</h6>
<b-table :items="computed_users" :fields="fields" bordered hover striped :current-page="current_page" :per-page="per_page" @row-clicked="onRowClicked">
<template #cell(avatar)="{ value }">
<b-avatar :src="value"></b-avatar>
</template>
<template #cell(name)="{ item: { personal_info: { first_name, last_name } }}">
{{ first_name }} {{ last_name }}
</template>
<template #row-details="{ item }">
<pre>{{ item }}</pre>
</template>
</b-table>
</div>
其中的 expand/collapse 部分工作得很好。
现在我正在使用 javascript startInterval() 每 2 秒重新加载一次 table。最终这将转移到网络套接字。
一般来说,作为 table load/reload 的一部分,系统通过检查 [=39] 来检查是否应该在详细信息栏中显示图标“^”或“v” =], 这很好用。
getChevron(row, index) {
if (row.detailsShowing == true) {
return "chevronDown";
}
return "chevronUp";
}
当用户选择关系列中的“^”图标时,将调用 @click=row.toggleDetails
来展开该行,然后调用函数 v-on:click="toggleRow(row)"
来跟踪用户选择的行.这使用服务器端系统生成的 guid 来跟踪。
在 2 秒内,table 将重新加载并且该行会折叠。在 load/reload 上,在它加载的第一列关系中,我调用函数 checkChild(row),根据我本地存储的数组检查行 guid,以确定这是否是应在加载时扩展的行。
<template #cell(relationship)="row"> {{checkChild(row)}} <\template>
如果行 guid 与数组中的一个匹配,我会尝试设置
checkChild(row){
var idx = this.showRows.indexOf( row.item.id);
if(idx > -1){
row.item.detailsShowing = true;
row.rowSelected = true;
row.detailsShowing == true
row._showDetails = true;
}
}
并且我能够看到我找到了匹配项,但是 none 设置为 true 的那些变量使展开的行保持打开状态,该行总是在重新加载时折叠
有人对我如何使行在 table 重新加载时保持打开状态有任何想法吗?
您的代码出现问题是因为 Vue 2 警告。在将属性添加到 data
之后向对象添加属性将 而不是 是反应性的。要解决这个问题,您必须使用 Vue.set
.
您可以阅读更多相关内容 here。
但是,像您在模板中所做的那样调用函数似乎是一种不好的做法。 您应该在获取数据后执行此操作,或者使用诸如计算 属性 之类的东西来进行映射。
这里有两个简化的例子。
API调用后映射
{
data() {
return {
items: [],
showRows: []
}
},
methods: {
async fetchData() {
const { data } = await axios.get('https://example.api')
foreach(item of data) {
const isRowExpanded = this.showRows.includes(item.id);
item._showDetails = isRowExpanded;
}
this.items = data;
}
}
}
使用计算
{
computed: {
// Use `computedItems` in `<b-table :items="computedItems">`
computedItems() {
const { items, showRows } = this;
return items.map(item => ({
...item,
_showDetails: .showRows.includes(item.id)
}))
}
},
data() {
return {
items: [],
showRows: []
}
},
methods: {
async fetchData() {
const { data } = await axios.get('https://example.api')
this.items = data;
}
}
}
有关更完整的示例,请查看下面的代码段。
const {
name,
datatype,
image
} = faker;
const getUser = () => ({
uuid: datatype.uuid(),
personal_info: {
first_name: name.firstName(),
last_name: name.lastName(),
gender: name.gender(),
age: Math.ceil(Math.random() * 75) + 15
},
avatar: image.avatar()
});
const users = new Array(10).fill().map(getUser);
new Vue({
el: "#app",
computed: {
computed_users() {
const {
expanded_rows,
users
} = this;
return users.map((user) => ({
...user,
_showDetails: expanded_rows[user.uuid]
}));
},
total_rows() {
const {
computed_users
} = this;
return computed_users.length;
}
},
created() {
this.users = users;
setInterval(() => {
users.push(getUser());
this.users = [...users];
}, 5000);
},
data() {
return {
per_page: 5,
current_page: 1,
users: [],
fields: [{
key: "avatar",
class: "text-center"
},
{
key: "name",
thClass: "text-center"
},
{
key: "personal_info.gender",
label: "Gender",
thClass: "text-center"
},
{
key: "personal_info.age",
label: "Age",
class: "text-center"
}
],
expanded_rows: {}
};
},
methods: {
onRowClicked(item) {
const {
expanded_rows
} = this;
const {
uuid
} = item;
this.$set(expanded_rows, uuid, !expanded_rows[uuid]);
}
}
});
<link href="https://unpkg.com/bootstrap@4.5.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue@2.21.2/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://unpkg.com/vue@2.6.12/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue@2.21.2/dist/bootstrap-vue.js"></script>
<script src="https://unpkg.com/faker@5.5.3/dist/faker.min.js"></script>
<div id="app" class="p-3">
<b-pagination v-model="current_page" :per-page="per_page" :total-rows="total_rows">
</b-pagination>
<h4>Table is refresh with a new item every 5 seconds.</h4>
<h6>Click on a row to expand the row</h6>
<b-table :items="computed_users" :fields="fields" bordered hover striped :current-page="current_page" :per-page="per_page" @row-clicked="onRowClicked">
<template #cell(avatar)="{ value }">
<b-avatar :src="value"></b-avatar>
</template>
<template #cell(name)="{ item: { personal_info: { first_name, last_name } }}">
{{ first_name }} {{ last_name }}
</template>
<template #row-details="{ item }">
<pre>{{ item }}</pre>
</template>
</b-table>
</div>