VueJs 数组替换 v-了解如何使其工作



>我有一个非常简单的页面,其中包含两个选项卡,每个选项卡都包含具有不同状态的报告列表。

我尝试做的方法是,我有两个不同的数据源数组,每个选项卡一个,第三个数组表示当前显示的数组项。

当用户单击选项卡时,我根据单击的选项卡将第三个数组替换为第一个或第二个数组。

但是,v-for部分不会更新,但v-show部分会更新。我花了几个小时来尝试解决它,已经尝试了Vue.set(...)但仍然不起作用。

任何人都知道问题的详细原因以及最佳解决方案是什么?

以下是代码,我用OnSenUI for VueVue 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;
}
},
}
}

为了包含更多详细信息,这是我通过阅读一些教程开始的简单启动项目。这是主要的.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 下的索引.js。报告列表是组件文件,位于组件文件夹下:

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);
}

来自 Vue 文档中的列表渲染:

当 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 的计算属性。它们非常强大,可以在更新依赖项时智能地更新属性。这也可能会解决列表未呈现的当前问题。

例如:

.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;
},
}

最新更新