vue.js $watch 对象数组

Posted

技术标签:

【中文标题】vue.js $watch 对象数组【英文标题】:vue.js $watch array of objects 【发布时间】:2016-03-20 22:17:32 【问题描述】:
mounted: function() 
  this.$watch('things', function()console.log('a thing changed'), true);

things 是一个对象数组[foo:1, foo:2]

$watch 检测何时添加或删除对象,但不会检测对象上的值何时更改。我该怎么做?

【问题讨论】:

我个人认为最好的答案在这里:reactgo.com/vue-watch-array-of-objects 【参考方案1】:

您可以使用$watch('arr.0', () => )$watch('dict.keyName', () => ) 独立观察数组或字典中的每个元素的变化

来自https://vuejs.org/v2/api/#vm-watch:

注意:当改变(而不是替换)一个对象或数组时, 旧值将与新值相同,因为它们引用 相同的对象/数组。 Vue 不保留预突变值的副本。

但是,您可以独立地迭代 dict/array 和 $watch 每个项目。 IE。 $watch('foo.bar') - 这会监视对象 'foo' 的属性 'bar' 的变化。

在这个例子中,我们观察 arr_of_numbers 中的所有项目,以及 arr_of_objects 中所有项目的 'foo' 属性:

mounted() 
        this.arr_of_numbers.forEach( (index, val) => 
            this.$watch(['arr_of_numbers', index].join('.'), (newVal, oldVal) => 
                console.info("arr_of_numbers", newVal, oldVal);
            );
        );

        for (let index in this.arr_of_objects) 
            this.$watch(['arr_of_objects', index, 'foo'].join('.'), (newVal, oldVal) => 
                console.info("arr_of_objects", this.arr_of_objects[index], newVal, oldVal);
            );
        

    ,
    data() 
        return 
            arr_of_numbers: [0, 1, 2, 3],
            arr_of_objects: [foo: 'foo', foo:'bar']
        
    

【讨论】:

【参考方案2】:

如果有人需要获取数组中已更改的项目,请检查:

JSFiddle Example

帖子示例代码:

new Vue(
  ...
  watch: 
    things: 
      handler: function (val, oldVal) 
        var vm = this;
        val.filter( function( p, idx ) 
            return Object.keys(p).some( function( prop ) 
                var diff = p[prop] !== vm.clonethings[idx][prop];
                if(diff) 
                    p.changed = true;                        
                
            )
        );
      ,
      deep: true
    
  ,
  ...
)

【讨论】:

每次更新时对整个数组进行 diff 似乎有点过分。我想知道是否有办法让 Vue 直接告诉我更新了哪个元素...【参考方案3】:

有一种更简单的方法可以在没有深度观察的情况下观察 Array 的项目:使用计算值


  el: "#app",
  data () 
    return 
      list: [a: 0],
      calls: 0,
      changes: 0,
    
  ,
  computed: 
    copy ()  return this.list.slice() ,
  ,
  watch: 
    copy (a, b) 
      this.calls ++
      if (a.length !== b.length) return this.onChange()
      for (let i=0; i<a.length; i++) 
        if (a[i] !== b[i]) return this.onChange()
      
    
  ,
  methods: 
    onChange () 
      console.log('change')
      this.changes ++
    ,
    addItem ()  this.list.push(a: 0) ,
    incrItem (i)  this.list[i].a ++ ,
    removeItem(i)  this.list.splice(i, 1) 
  

https://jsfiddle.net/aurelienlt89/x2kca57e/15/

我们的想法是构建一个计算值copy,它恰好具有我们想要检查的内容。计算值很神奇,只将观察者放在实际读取的属性上(这里,list 的项目在list.slice() 中读取)。 copy watcher 中的检查实际上几乎没有用(可能除了奇怪的极端情况),因为计算值已经非常精确。

【讨论】:

【参考方案4】:

你应该传递一个对象而不是布尔值作为options,所以:

mounted: function () 
  this.$watch('things', function () 
    console.log('a thing changed')
  , deep:true)

或者您可以像这样将观察者设置为 vue 实例:

new Vue(
  ...
  watch: 
    things: 
      handler: function (val, oldVal) 
        console.log('a thing changed')
      ,
      deep: true
    
  ,
  ...
)

[demo]

【讨论】:

很好,这是一个迁移问题。在 vue 的最后一个版本中,我使用 true 作为最后一个参数的意思是 deep。泰! 为我工作。谢谢!

以上是关于vue.js $watch 对象数组的主要内容,如果未能解决你的问题,请参考以下文章

访问 Vue JS 实例监视对象中的 $refs 数组

vue.js中$watch的用法示例

Vue JS 2 中复杂对象数组的数组更改检测

Vue.js - 如何在数组对象上实现计算属性?

如何使用 Vue.js 为数组(数据)中的所有对象添加属性?

vue.js 结构赋值--数组