如何让 Vue.js 对动态添加的数组属性的更改做出反应?
How can I get Vue.js to be reactive for changes to dynamically added array properties?
在 Vue.js 中,我有一个动态 added/edited 属性的数据对象,这些属性本身就是数组。例如,属性 开始如下:
data: function () {
return {
vals: {}
};
}
随着时间的推移,通过各种按钮点击等,vals
可能如下所示(实际 属性 名称和值根据多种因素是 100% 动态的) :
vals: {
set1: [
{
prop1: 123,
prop2: 'hello'
},
{
prop1: 456,
prop2: 'bye'
}
],
set2: [
{
prop3: 'Why?!',
prop4: false
}
]
}
随着数组属性(即 set1
和 set2
)发生变化,我希望能够对这些变化做出反应。
例如,我可能会在我的代码中执行如下操作:
var prop = 'set1';
this.vals[prop].push({
{
prop1: 789,
prop2: 'hmmm...'
}
});
但是,当我这样做时,组件没有更新(我想是因为我将一个对象推到对象子数组的末尾;并且 Vue.js 似乎没有跟踪这些变化).
我已经能够通过在上述 push
之后执行 this.$forceUpdate();
来强制组件响应,但我想必须有更多 eloquent 的方式来获得 Vue.js 当对象被推到对象子数组的末尾时反应。
有谁知道有更好的方法来尝试实现我想要实现的目标吗?谢谢。
任何时候向对象添加新的 属性 或更改数组中的值时,都需要使用 Vue.set()
.
Vue.set(this.vals, prop, [ /* ... */ ])
理想情况下,您应该预先定义所有属性,这样 Vue 就不必根据数据模型的形状使计算属性无效。即使您将它们设置为 null
,您也应该尝试映射出您希望组件需要的所有属性。
此外,在您的第一个代码块中,您的 return:
之后有一个冒号,它将评估为一个标签,这意味着您的数据函数没有返回任何内容。
您可以尝试使用 lodash
和 deep watcher
..
更多关于 deep watcher
here
new Vue({
el: "#app",
methods: {
setValue() {
this.oldPeople = _.cloneDeep(this.people);
}
},
mounted() {
this.setValue();
},
el: "#app",
data: {
changed: null,
people: [
{ id: 0, name: "Bob", age: 27 },
{ id: 1, name: "Frank", age: 32 },
{ id: 2, name: "Joe", age: 38 }
],
oldPeople: []
},
watch: {
people: {
deep: true,
handler(after, before) {
// Return the object that changed
let vm = this;
let changed = after.filter(function(p, idx) {
return Object.keys(p).some(function(prop) {
return p[prop] !== vm.oldPeople[idx][prop];
});
});
vm.setValue();
this.changed = changed;
},
}
}
});
input {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.6/vue.js"></script>
<script src="https://cdn.jsdelivr.net/lodash/4.17.2/lodash.min.js"></script>
<div id="app">
<div>
<input type="text" v-for="(person, index) in people" v-model="people[index].age" />
<div v-if="changed !== null">
You changed:<br/>{{ changed }}
</div>
</div>
</div>
在 Vue.js 中,我有一个动态 added/edited 属性的数据对象,这些属性本身就是数组。例如,属性 开始如下:
data: function () {
return {
vals: {}
};
}
随着时间的推移,通过各种按钮点击等,vals
可能如下所示(实际 属性 名称和值根据多种因素是 100% 动态的) :
vals: {
set1: [
{
prop1: 123,
prop2: 'hello'
},
{
prop1: 456,
prop2: 'bye'
}
],
set2: [
{
prop3: 'Why?!',
prop4: false
}
]
}
随着数组属性(即 set1
和 set2
)发生变化,我希望能够对这些变化做出反应。
例如,我可能会在我的代码中执行如下操作:
var prop = 'set1';
this.vals[prop].push({
{
prop1: 789,
prop2: 'hmmm...'
}
});
但是,当我这样做时,组件没有更新(我想是因为我将一个对象推到对象子数组的末尾;并且 Vue.js 似乎没有跟踪这些变化).
我已经能够通过在上述 push
之后执行 this.$forceUpdate();
来强制组件响应,但我想必须有更多 eloquent 的方式来获得 Vue.js 当对象被推到对象子数组的末尾时反应。
有谁知道有更好的方法来尝试实现我想要实现的目标吗?谢谢。
任何时候向对象添加新的 属性 或更改数组中的值时,都需要使用 Vue.set()
.
Vue.set(this.vals, prop, [ /* ... */ ])
理想情况下,您应该预先定义所有属性,这样 Vue 就不必根据数据模型的形状使计算属性无效。即使您将它们设置为 null
,您也应该尝试映射出您希望组件需要的所有属性。
此外,在您的第一个代码块中,您的 return:
之后有一个冒号,它将评估为一个标签,这意味着您的数据函数没有返回任何内容。
您可以尝试使用 lodash
和 deep watcher
..
更多关于 deep watcher
here
new Vue({
el: "#app",
methods: {
setValue() {
this.oldPeople = _.cloneDeep(this.people);
}
},
mounted() {
this.setValue();
},
el: "#app",
data: {
changed: null,
people: [
{ id: 0, name: "Bob", age: 27 },
{ id: 1, name: "Frank", age: 32 },
{ id: 2, name: "Joe", age: 38 }
],
oldPeople: []
},
watch: {
people: {
deep: true,
handler(after, before) {
// Return the object that changed
let vm = this;
let changed = after.filter(function(p, idx) {
return Object.keys(p).some(function(prop) {
return p[prop] !== vm.oldPeople[idx][prop];
});
});
vm.setValue();
this.changed = changed;
},
}
}
});
input {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.6/vue.js"></script>
<script src="https://cdn.jsdelivr.net/lodash/4.17.2/lodash.min.js"></script>
<div id="app">
<div>
<input type="text" v-for="(person, index) in people" v-model="people[index].age" />
<div v-if="changed !== null">
You changed:<br/>{{ changed }}
</div>
</div>
</div>