Vue:如何在 v-for 中执行响应式对象更改检测?

Posted

技术标签:

【中文标题】Vue:如何在 v-for 中执行响应式对象更改检测?【英文标题】:Vue: How to perform reactive object change detection in v-for? 【发布时间】:2019-05-02 13:59:06 【问题描述】:

我阅读了this 文档,但无法使用建议的解决方案。

我有一个v-for 循环对象。这些对象随时间动态变化,我需要这种变化在 v-for 循环中反应性地显示。

<b-row lg="12" v-for="data in objects" :key="data.id">
    <div v-if="data.loading">
      loading...
      data.loading
    </div>
    <div v-else>
      loaded, done
      data.loading
    </div>
</b-row>

在我的方法中,我有一个 for 循环,它为每个对象下载数据并像这样更改对象值:

for(var i = 0; i<response.ids.length; i++)
    var newId = response.ids[i].id
    this.objects.newId = "loading":true, "id": newId

    downloadSomething(newId).then(res => 
        this.objects.newId = res[0]         //<-- this change needs to be shown reactively.
    )

根据 Vue 文档,对象更改不是反应性的:

var vm = new Vue(
  data: 
    a: 1
  
)
// `vm.a` is now reactive

vm.b = 2
// `vm.b` is NOT reactive

Vue 提出了一些这样的解决方法:

Vue.set(vm.userProfile, 'age', 27)

更新

但对我来说,这只是在对象中创建一个具有相同 ID 的新参数,并创建重复键警告和其他问题。

我也在 Vue.set 之前尝试了Vue.delete,但它实际上并没有删除。

有没有办法不替换键/值对,而是向 ID 为 newID 的根的第一个子节点添加更多/更改参数

谢谢!

【问题讨论】:

【参考方案1】:

解决方案:this.objects.newId = res[0] 替换为this.$set(this.objects, 'newId', res[0]),它应该可以工作。

解释: this.$set 只是 Vue.set 的别名,可在任何 Vue 实例中使用。请记住,示例中的vm(代表视图模型)与this 相同,相当于Vue 组件实例。同样由于 ES5 JS 的限制,您必须通过 Vue.set/this.$set 显式设置对象的属性才能手动触发重新渲染。这个问题会在 Vue 3.0 发布后解决。

希望这会有所帮助,如果您需要任何说明,请随时提问。

【讨论】:

我没有明确提到我的“对象”是一个对象而不是数组。 Vue.set/vm.$set 在 'objects' 中创建一个具有相同 ID 的新参数,并且不会替换现有参数。这会产生重复键警告和其他问题。我也在 Vue.set 之前尝试了 Vue.delete,但 Vue.delete 不起作用。 想通了。我在没有 Vue.set 的情况下为子对象设置初始键值,然后期望它随着 Vue.set 改变。事实证明,还需要使用 Vue.set 设置初始值(加载值)。我还有助于提高可读性。【参考方案2】:

当您想为现有对象(而不是直接定义数据)定义 新属性 时,您需要Vue.set(),并且此函数会将新属性分配给内置观察程序,它会也变得被动。

这一切都在文档中进行了解释:https://vuejs.org/v2/guide/reactivity.html

在你的情况下,这似乎是你让它工作所需要的。在我的示例中:https://jsfiddle.net/efrat19/eywraw8t/484131/ 一个异步函数获取数据并定义一个新属性以包含响应。

new Vue(
  el: "#app",
  data: 
    objects:
    property1:12
    
  ,
  methods: 
    fetchDataAndAddProperty(response)
        fetch('https://free.currencyconverterapi.com/api/v6/countries').then(res =>
      res.json()).then(data => Vue.set(this.objects,'property2',data))
    
  
)

和模板:

<div id="app">
<div lg="12" v-for="(val,key,index) in objects" :key="index">
    key:val
</div>
<button @click="fetchDataAndAddProperty()">fetch</button>
</div>

正如您在小提琴中看到的那样,新属性变为反应性并被显示。

【讨论】:

【参考方案3】:

试试看:

downloadSomething(newId).then(res => 
    this.$set(this.objects, 'newId', res[0])
)

【讨论】:

以上是关于Vue:如何在 v-for 中执行响应式对象更改检测?的主要内容,如果未能解决你的问题,请参考以下文章

vue v-for 数组响应式方法

vue循环语句v-for中元素绑定值问题

vue循环语句v-for中元素绑定值问题

Vue.js v-for 循环绑定数组中的项目对象并在更改时更新

Vue 无法更改嵌套 v-for 中的属性

vue数组和对象的响应式实现