【问题标题】:How to update DOM when changes occurs within an object rendered by v-for?当 v-for 渲染的对象发生变化时如何更新 DOM?
【发布时间】:2017-09-29 00:37:05
【问题描述】:

我正在使用v-for 来呈现基于对象数组的列表。

<ul>
  <li v-for="category, i in categories"
  :class="{active: category.active}"
  @click="changeCategory(i)">
    <a>{{ category.service_type_name }}</a>
  </li>
</ul>

当你点击列表项changeCategory(index)运行时:

changeCategory(index) {
    this.categories.forEach((c, i) => {
        c.active = (i != index)? false : true
    })
}

所以被点击的列表项active 属性被设置为true 而所有其他设置为false,并且列表项获得了一个.active 类添加到它(因为:class="{active: category.active}" 行在模板中。

但是,DOM 并未更新以显示此更改。

是否有在发生这种变化时自动更新 DOM,而不在 changeCategory(index) 函数中使用 this.$forceUpdate()

编辑:将map 更改为forEach,DOM 仍然没有更新。

编辑:我正在使用带有打字稿的 vue-class-components

import Vue from 'app/vueExt'
import { Component } from 'vue-property-decorator'
import * as Template from './services.vue'

@Component({
    mixins: [Template]
})
export default class Services extends Vue {
    categories = []

    created() {
        this.api.getServiceSetupCatagories().then((res) => {
            this.categories = res.categories
            this.categories.forEach((c, i) => {
                // adding active property to the object
                // active = true if i = 0, false otherwise
                c.active = (i)? false : true
            })
        })
    }

    changeCategory(index) {
        this.categories.forEach((c, i) => {
            c.active = (i != index)? false : true
        })
    }
}

【问题讨论】:

  • map 不会修改您的数组,它会返回一个新数组。因此 vue 没有检测到任何更改,并且您的 dom 没有更新。尝试改用forEach
  • @EricGuan 是真的,好点。我尝试了forEach 并且事件达到了使用for 循环更改active 属性的程度,但它没有效果。当我 console.log 项目时,它显示正确的 active 值,但 DOM 没有得到更新。
  • 似乎对我有用。 codepen.io/Kradek/pen/MmmZLN
  • @BertEvans 是的,我不确定发生了什么。我用map 函数而不是forEach 尝试了你的代码,这也按预期工作。我不确定为什么在我的情况下 DOM 没有更新。
  • 如果在调用changeCategory 方法之前category 上不存在active 属性,那么您在Vue 中遇到了一个警告,应该使用Vue.set(c, "active", i != index ? false : true)vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats

标签: vue.js vuejs2 vue-component v-for


【解决方案1】:

这按预期工作。您的问题不在您在此处发布的代码中。 (即使使用 map:在 map 中,对象也是引用,因此修改其成员会修改原始对象。)

new Vue({
  el: '#app',
  data: {
    categories: [{
        service_type_name: 'one',
        active: false
      },
      {
        service_type_name: 'two',
        active: false
      }
    ]
  },
  methods: {
    changeCategory(index) {
      this.categories.map((c, i) => {
        c.active = (i != index) ? false : true
      })
    }
  }
});
.active {
  background-color: lightgray;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.min.js"></script>
<ul id="app">
  <li v-for="category, i in categories" :class="{active: category.active}" @click="changeCategory(i)">
    <a>{{ category.service_type_name }}</a>
  </li>
</ul>

【讨论】:

    【解决方案2】:

    在讨论了这个问题后,我建议了以下替代方法。

    activeIndex 添加到data 并将模板更改为以下内容。

    <ul>
      <li v-for="category, i in categories"
          :class="{active: activeIndex === i}"
          @click="activeIndex = i">
        <a>{{ category.service_type_name }}</a>
      </li>
    </ul>
    

    这似乎适用于@wrahim。

    我认为原始代码的根本问题是 active 属性被添加到 category 落入 Vue 的 change detection caveats 之一。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-04
      • 2022-06-30
      • 2020-10-16
      • 1970-01-01
      • 2018-09-10
      • 1970-01-01
      • 2020-04-29
      • 2020-03-19
      相关资源
      最近更新 更多