我有一个非常简单的页面,其中包含两个选项卡,每个选项卡都包含状态不同的报告列表。
我要尝试的方法是,我有两个不同的数据源数组,每个选项卡一个,第三个数组表示当前显示的数组项。
当用户单击选项卡时,我将根据单击的选项卡将第三个数组替换为第一个或第二个数组。
但是,v-for
部分未更新,但是v-show
部分已更新。我花了好几个小时来尝试解决问题,尝试过Vue.set(...)
,但仍然无法正常工作。
任何人都知道造成此问题的详细原因以及最佳解决方案是什么?
以下是代码,我使用OnSenUI for Vue
和Vue router
,这是完整的组件代码:
<template id="main-page">
<v-ons-page>
<v-ons-toolbar>
<div class="center">Reports</div>
</v-ons-toolbar>
<v-ons-bar>
<p style="text-align: right; margin-right: 20px">
<v-ons-button @click="$ons.notification.alert('TODO: implement this.')">
+ New Report
</v-ons-button>
</p>
</v-ons-bar>
<v-ons-card v-for="report in showingReports" :key="report.requestNo">
<div class="title">
{{report.requestNo}}
</div>
<div class="content">
Submitted Date: {{report.submittedDate}}<br>
Status: {{report.status}}<br>
Subject: {{report.subject}}<br>
</div>
</v-ons-card>
<v-ons-card v-show="!showingReports || showingReports.length == 0">
<div class="content">
<p class="center">
No records found
</p>
</div>
</v-ons-card>
<v-ons-tabbar>
<v-ons-tab label="Open" @click="selectTab(0)" :active="selectedTab == 0"></v-ons-tab>
<v-ons-tab label="Closed" @click="selectTab(1)" :active="selectedTab == 1"></v-ons-tab>
</v-ons-tabbar>
</v-ons-page>
</template>
<script>
export default {
data() {
return {
showingReports: [],
openedReports: [],
closedReports: [],
selectedTab: 0
}
},
created() {
this.getReports();
},
methods: {
getReports() {
this.allReports = [
{
requestNo: "REPORT18070102",
submittedDate: Date(),
status: "OPENED",
subject: "Test1"
},
{
requestNo: "REPORT18070103",
submittedDate: Date(),
status: "OPENED",
subject: "Test2"
}
];
this.openedReports = this.allReports.filter(report => report.status == "OPENED");
this.closedReports = this.allReports.filter(report => report.status != "OPENED");
this.selectTab(0);
},
selectTab(tab) {
this.selectedTab = tab;
if(tab == 0){
this.showingReports = this.openedReports;
}else{
this.showingReports = this.closedReports;
}
},
}
}
要包含更多详细信息,这是我通过阅读一些教程开始的一个简单的入门项目。这是main.js:
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
这是App.vue:
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
这是路由器foler下的index.js。 ReportList是组件文件,位于组件文件夹下:
import Router from 'vue-router'
import ReportList from '@/components/ReportList'
import 'onsenui/css/onsenui.css';
import 'onsenui/css/onsen-css-components.css';
import Vue from 'vue';
import VueOnsen from 'vue-onsenui';
Vue.use(Router)
Vue.use(VueOnsen)
export default new Router({
routes: [
{
path: '/',
name: 'ReportList',
component: ReportList
}
]
})
package.json中的依赖项:
"scripts": {
"prod": "webpack-dev-server --inline --progress --config build/webpack.prod.conf.js",
"start": "npm run prod",
"e2e": "node test/e2e/runner.js",
"test": "npm run unit && npm run e2e",
"lint": "eslint --ext .js,.vue src test/unit test/e2e/specs",
"build": "node build/build.js"
},
"dependencies": {
"onsenui": "^2.10.4",
"vue": "^2.5.2",
"vue-onsenui": "^2.6.1",
"vue-router": "^3.0.1"
},
-----删除了控制台日志,但无济于事---
已更新: 我通过另一种方式使其工作,呈现整个列表,但使用v-show控制是否显示它。我认为与v-show相比,“ v-for”的反应不是很活跃。
<v-ons-card v-for="report in allReports" :key="report.requestNo" v-show="shouldShow(report)">
<div class="title">
{{report.requestNo}}
</div>
<div class="content">
Submitted Date: {{report.submittedDate}}<br>
Status: {{report.status}}<br>
Subject: {{report.subject}}<br>
</div>
</v-ons-card>
shouldShow(report){
if(this.selectedTab == 0){
return report.status == 'OPENED';
}else{
return report.status != 'OPENED';
}
},
selectTab(tab) {
this.selectedTab = tab;
var hasItem = false;
this.allReports.forEach(r => hasItem = hasItem || this.shouldShow(r));
this.emptyList = !hasItem;
console.log(this.emptyList);
}
答案 0 :(得分:2)
来自List Rendering in the Vue docs:
当Vue更新用
v-for
渲染的元素列表时,默认情况下它使用“就地补丁”策略。 ...此默认模式是有效的,但仅当列表呈现输出不依赖于子组件状态或临时DOM状态(例如表单输入值)时才适用。
要给Vue一个提示,使其可以跟踪每个节点的身份,从而重用和重新排列现有元素,您需要为每个项目提供唯一的
key
属性。key
的理想值是每个项目的唯一ID。这个特殊属性大致相当于1.x中的track-by
,但它就像一个属性一样工作,因此您需要使用v-bind
将其绑定到动态值(此处使用简写方式)
因此,您应该始终为列表中的每个元素添加唯一的key
属性(带有v-bind
),以使Vue知道状态发生了变化。
例如,使用每个列表项的requestNo
属性:
<v-ons-card v-for="report in showingReports" :key="report.requestNo">
更新(在上面继续我的评论):
您可能要考虑使用Vue的computed properties。它们非常强大,并且在更新依赖项时会智能地更新属性。这也可能会解决您当前无法显示列表的问题。
例如:
HTML
<v-ons-card v-for="report in computedReports" :key="report.requestNo">
<!-- ... -->
</v-ons-card>
JS
data: {
selectedTab: 0
},
computed: {
computedReports() {
return this.allReports.filter(report => this.isOpenedReports ?report.status != "OPENED" : report.status == "OPENED");
}
}
methods: {
getReports() {
this.allReports = [
{
requestNo: "REPORT18070102",
submittedDate: Date(),
status: "OPENED",
subject: "Test1"
},
{
requestNo: "REPORT18070103",
submittedDate: Date(),
status: "OPENED",
subject: "Test2"
}
];
this.selectTab(0);
},
selectTab(tab) {
this.selectedTab = tab;
},
}