javascript - VueJs 数组替换 v-for 如何使其工作

标签 javascript vue.js v-for

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

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

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

但是,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;
      }
    },
  }
}

要包含更多详细信息,这是一个简单的入门项目,我是通过阅读一些教程开始的。这是 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 for key would be the unique id of each item. This special attribute is a rough equivalent to track-by in 1.x, but it works like an attribute, so you need to use v-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/

相关文章:

javascript - 函数参数对象解构导致 undefined variable

vue.js - 将 v-model 添加到嵌套 v-for 循环中的输入

javascript - 模态弹出重复数据

javascript - 如何从 Active Class 获取类别 ID 并传递给 Post 查询

Laravel 5.4 和 Vue 2.0.1 无法读取未定义的属性 'get'

vue.js - 在 VueJS 中总是得到 "Trailing Spaces not Allowed"的错误

javascript - 如何切换类以显示哪个选项卡在 VueJS 中处于事件状态?

javascript - 使用 v-if Vue 在 v-for 中添加一些逻辑

javascript - React/Redux 组件重新渲染

javascript - 如何在 vuetify 的浅色主题中启用自定义颜色的深色模式?