Vue.js $watch массив объектов
mounted: function() {
this.$watch('things', function(){console.log('a thing changed')}, true);
}
things
- это массив объектов [{foo:1}, {foo:2}]
$watch
определяет, когда объект добавляется или удаляется, но не когда значения объекта изменяются. Как я могу это сделать?
Ответы
Ответ 1
Вы должны передать объект вместо логического значения в качестве 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
}
},
...
})
[демо]
Ответ 2
Если кому-то нужно получить элемент, который был изменен внутри массива, пожалуйста, проверьте его:
Пример JSFiddle
Код примера поста:
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
}
},
...
})
Ответ 3
с https://vuejs.org/v2/api/#vm-watch:
Примечание: при замене (а не замене) объекта или массива старое значение будет совпадать с новым значением, поскольку они ссылаются на один и тот же объект/массив. Vue не хранит копию значения перед изменением.
Тем не менее, вы можете перебирать dict/array и $ watch каждый элемент независимо. то есть. $watch.foo.bar
- отслеживает изменения в свойстве 'bar' в словаре 'foo'.
В этом примере мы наблюдаем все элементы в arr_of_numbers, а также свойства 'foo' всех элементов в arr_of_objects:
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'}]
}
}
Ответ 4
Существует более простой способ просмотра элементов массива без глубокого наблюдения: использование вычисленных значений
{
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
самом деле почти бесполезны (за исключением странных угловых случаев, может быть), потому что вычисленные значения уже чрезвычайно точны.