我有一个非常简单的页面,包含两个选项卡,每个选项卡包含一个具有不同状态的报告列表。
我尝试做的方式是,我有两个不同的数据源数组,一个用于每个选项卡,第三个数组表示当前显示的数组项。
当用户单击选项卡时,我根据单击的选项卡将第三个数组替换为第一个或第二个数组。
但是,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>
这是router foler下的index.js。 ReportList是组件文件,位于components文件夹下:
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);
}
最佳答案
来自 List Rendering in the Vue docs :
When Vue is updating a list of elements rendered with
v-for
, by default it uses an “in-place patch” strategy. ...This default mode is efficient, but only suitable when your list render output does not rely on child component state or temporary DOM state (e.g. form input values).
To give Vue a hint so that it can track each node’s identity, and thus reuse and reorder existing elements, you need to provide a unique
key
attribute for each item. An ideal value forkey
would be the unique id of each item. This special attribute is a rough equivalent totrack-by
in 1.x, but it works like an attribute, so you need to usev-bind
to bind it to dynamic values (using shorthand here)
因此,您应该始终为列表中的每个元素添加一个唯一的 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;
},
}
关于javascript - VueJs 数组替换 v-for 如何使其工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51833265/