v-的VueJs阵列替换-如何使其工作

时间:2018-08-14 03:22:46

标签: 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>

这是路由器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);
  }

1 个答案:

答案 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;
  },
}