我有一个名为 people
的数组,其中包含如下对象:
前
[
{id: 0, name: 'Bob', age: 27},
{id: 1, name: 'Frank', age: 32},
{id: 2, name: 'Joe', age: 38}
]
它可以改变:
后
[
{id: 0, name: 'Bob', age: 27},
{id: 1, name: 'Frank', age: 33},
{id: 2, name: 'Joe', age: 38}
]
注意弗兰克刚满 33 岁。
我有一个应用程序,我试图在其中查看人员数组,当任何值发生更改时,然后记录更改:
<style>
input {
display: block;
}
</style>
<div id="app">
<input type="text" v-for="(person, index) in people" v-model="people[index].age" />
</div>
<script>
new Vue({
el: '#app',
data: {
people: [
{id: 0, name: 'Bob', age: 27},
{id: 1, name: 'Frank', age: 32},
{id: 2, name: 'Joe', age: 38}
]
},
watch: {
people: {
handler: function (val, oldVal) {
// Return the object that changed
var changed = val.filter( function( p, idx ) {
return Object.keys(p).some( function( prop ) {
return p[prop] !== oldVal[idx][prop];
})
})
// Log it
console.log(changed)
},
deep: true
}
}
})
</script>
我基于关于数组比较的 question that I asked yesterday 并选择了最快的工作答案。
因此,此时我希望看到以下结果:{ id: 1, name: 'Frank', age: 33 }
但是我在控制台中得到的只是(记住我在一个组件中拥有它):
[Vue warn]: Error in watcher "people"
(found in anonymous component - use the "name" option for better debugging messages.)
在 codepen that I made 中,结果是一个空数组,而不是我所期望的改变的对象。
如果有人能提出为什么会发生这种情况或我在这里出错的地方,那么将不胜感激,非常感谢!
您在旧值和新值之间的比较函数有一些问题。最好不要把事情复杂化,因为这会增加你以后的调试工作。你应该保持简单。
最好的方法是创建一个 person-component
并在其自己的组件中分别观察每个人,如下所示:
<person-component :person="person" v-for="person in people"></person-component>
请在下面找到一个用于观看内部人员组件的工作示例。如果你想在父端处理它,你可以使用$emit
向上发送一个事件,包含被修改的人的id
。
Vue.component('person-component', { props: ["person"], template: `
人员名单: p>
我已经更改了它的实现以解决您的问题,我创建了一个对象来跟踪旧更改并将其与之进行比较。您可以使用它来解决您的问题。
在这里,我创建了一个方法,其中旧值将存储在一个单独的变量中,然后将在手表中使用。
new Vue({
methods: {
setValue: function() {
this.$data.oldPeople = _.cloneDeep(this.$data.people);
},
},
mounted() {
this.setValue();
},
el: '#app',
data: {
people: [
{id: 0, name: 'Bob', age: 27},
{id: 1, name: 'Frank', age: 32},
{id: 2, name: 'Joe', age: 38}
],
oldPeople: []
},
watch: {
people: {
handler: function (after, before) {
// Return the object that changed
var vm = this;
let changed = after.filter( function( p, idx ) {
return Object.keys(p).some( function( prop ) {
return p[prop] !== vm.$data.oldPeople[idx][prop];
})
})
// Log it
vm.setValue();
console.log(changed)
},
deep: true,
}
}
})
查看更新 codepen
vm.$data
,谢谢!
这是定义明确的行为。您无法获取 mutated 对象的旧值。这是因为 newVal
和 oldVal
都引用同一个对象。 Vue 将不会保留您变异的对象的旧副本。
如果你用另一个对象替换了这个对象,Vue 会为你提供正确的引用。
阅读 docs. (vm.$watch
) 中的 Note
部分
组件方案和深度克隆方案各有优势,但也存在问题:
有时您想跟踪抽象数据的变化——围绕该数据构建组件并不总是有意义的。每次进行更改时深度克隆整个数据结构可能会非常昂贵。
我认为有更好的方法。如果您想查看列表中的所有项目并知道列表中的哪个项目发生了变化,您可以分别在每个项目上设置自定义观察者,如下所示:
var vm = new Vue({
data: {
list: [
{name: 'obj1 to watch'},
{name: 'obj2 to watch'},
],
},
methods: {
handleChange (newVal) {
// Handle changes here!
console.log(newVal);
},
},
created () {
this.list.forEach((val) => {
this.$watch(() => val, this.handleChange, {deep: true});
});
},
});
使用这种结构,handleChange()
将接收已更改的特定列表项 - 从那里您可以进行任何您喜欢的处理。
我还记录了一个 more complex scenario here,以防您在列表中添加/删除项目(而不仅仅是操作已经存在的项目)。
created()
思想的变化吗?并且不是每次带有数组的对象的子属性都发生变化?我试过了,当我在创建的@ErikKoopmans 中添加它时,它没有将任何内容记录到控制台
created
中的代码只是设置了观察者。该代码运行后,只要列表中的任一值发生更改(如您设置 this.list[0].name = 'new name'
),就会触发 handleChange
代码。
这就是我用来深入观察物体的方法。我的要求是观察对象的子字段。
new Vue({
el: "#myElement",
data:{
entity: {
properties: []
}
},
watch:{
'entity.properties': {
handler: function (after, before) {
// Changes detected.
},
deep: true
}
}
});
如果我们有对象或对象数组,并且我们想在 Vuejs 或 NUXTJS 中观看它们,则需要在观看中使用 deep: true
watch: {
'Object.key': {
handler (val) {
console.log(val)
},
deep: true
}
}
watch: {
array: {
handler (val) {
console.log(val)
},
deep: true
}
}
而不是“看”,我用“计算”解决了这个问题!
我没有测试过这段代码,但我认为它应该可以工作。如果没有,请在评论中告诉我。
<script>
new Vue({
el: '#app',
data: {
people: [
{id: 0, name: 'Bob', age: 27},
{id: 1, name: 'Frank', age: 32},
{id: 2, name: 'Joe', age: 38}
],
oldVal: {},
peopleComputed: computed({
get(){
this.$data.oldVal = { ...people };
return people;
},
set(val){
// Return the object that changed
var changed = val.filter( function( p, idx ) {
return Object.keys(p).some( function( prop ) {
return p[prop] !== this.$data.oldVal[idx][prop];
})
})
// Log it
console.log(changed)
this.$data.people = val;
}
}),
}
})
</script>