在開(kāi)發(fā)過(guò)程中月腋,我們時(shí)常會(huì)遇到這樣一種情況:當(dāng)vue的data里邊聲明或者已經(jīng)賦值過(guò)的對(duì)象或者數(shù)組(數(shù)組里邊的值是對(duì)象)時(shí),向?qū)ο笾刑砑有碌膶傩园曷福绻麓藢傩缘闹涤苌В遣粫?huì)更新視圖的。
根據(jù)官方文檔定義:如果在實(shí)例創(chuàng)建之后添加新的屬性到實(shí)例上煌集,它不會(huì)觸發(fā)視圖更新妓肢。
當(dāng)你把一個(gè)普通的 JavaScript 對(duì)象傳入 Vue 實(shí)例作為 data
選項(xiàng),Vue 將遍歷此對(duì)象所有的屬性牙勘,并使用 Object.defineProperty
把這些屬性全部轉(zhuǎn)為 getter/setter职恳。
受現(xiàn)代 JavaScript 的限制 (以及廢棄 Object.observe),Vue 不能檢測(cè)到對(duì)象屬性的添加或刪除方面。由于 Vue 會(huì)在初始化實(shí)例時(shí)對(duì)屬性執(zhí)行 getter/setter 轉(zhuǎn)化過(guò)程放钦,所以屬性必須在 data 對(duì)象上存在才能讓 Vue 轉(zhuǎn)換它,這樣才能讓它是響應(yīng)的恭金。
看以下實(shí)例:
<template>
<div>
<p @click="addd(obj)">{{obj.d}}</p>
<p @click="adde(obj)"> {{obj.e}}</p>
</div>
</template>
<script>
export default {
data(){
return {
obj:{}
}
},
mounted() {
this.obj = {d: 0};
this.obj.e = 0;
console.log('after--', this.obj);
},
methods: {
addd(item) {
item.d = item.d + 1;
console.log('item--',item);
},
adde(item) {
item.e = item.e + 1;
console.log('item--',item);
}
}
}
</scirpt>
可以看出d屬性是有g(shù)et 和 set方法的操禀,而新增的e屬性是沒(méi)有的。
點(diǎn)擊觸發(fā)3次addd横腿,點(diǎn)擊觸發(fā)3次adde,頁(yè)面效果及控制臺(tái)信息如下
此時(shí)觸發(fā)1次addd,頁(yè)面效果如下:
由此可以看出颓屑,更新新增屬性e,是不會(huì)更新視圖耿焊,但是會(huì)改變其值揪惦,當(dāng)更新原有屬性d時(shí)會(huì)更新視圖,同時(shí)將新增的屬性e的值也更新到視圖里邊
解決方案
官方定義:
Vue 不允許在已經(jīng)創(chuàng)建的實(shí)例上動(dòng)態(tài)添加新的根級(jí)響應(yīng)式屬性 (root-level reactive property)罗侯。然而它可以使用 Vue.set(object, key, value) 方法將響應(yīng)屬性添加到嵌套的對(duì)象上:
Vue.set(vm.obj, 'e', 0)
您還可以使用 vm.$set 實(shí)例方法器腋,這也是全局 Vue.set 方法的別名:
this.$set(this.obj,'e',02)
有時(shí)你想向已有對(duì)象上添加一些屬性,例如使用 Object.assign() 或 _.extend() 方法來(lái)添加屬性钩杰。但是纫塌,添加到對(duì)象上的新屬性不會(huì)觸發(fā)更新。在這種情況下可以創(chuàng)建一個(gè)新的對(duì)象讲弄,讓它包含原對(duì)象的屬性和新的屬性:
// 代替 Object.assign(this.obj, { a: 1, e: 2 })
this.obj= Object.assign({}, this.obj, { a: 1, e: 2 })
上述實(shí)例解決如下:
點(diǎn)擊觸發(fā)3次addd措左,點(diǎn)擊觸發(fā)3次adde,頁(yè)面效果及控制臺(tái)信息如下: