当vue的data里面声明或者已经赋值过的对象或者数组(数组里边的值是对象)时,向对象添加新的属性,如果更新此属性的值,是不会更新视图的。
根据官方文档定义:如果在实例创建之后添加新的属性到实例上,它不会触发视图更新
原理:当你把一个普通的javascript对象传入Vue实例作为data选项,Vue将遍历此对象所有的属性,并使用Object.defineProperty把这些属性全部转为getter/setter
受现代javascript的限制(以及废弃Object.observe),Vue不能检测对象属性的添加或者删除。由于Vue会在初始化实例是对属性执行getter/setter转化过程,所以属性必须在data对象上存在才能让Vue转换它,这样才能让它是响应的。
实例:
<template>
<view class="content">
<text @click="addd(obj)">{{obj.d}}</text>
<text @click="adde(obj)">{{obj.e}}</text>
</view>
</template>
<script lang="ts">
import moment from 'moment';
moment.locale("zh-cn");
import Vue from "vue";
export default Vue.extend({
data(){
return{
obj:{}
}
},
mounted(){
this.obj= {d:0};
this.obj.e=0;
console.log('after--',this.obj);
},
methods:{
addd(item: any){
item.d=item.d+1;
console.log('item--',item);
},
adde(item: any){
item.e = item.e+1;
console.log('item--',item);
}
}
});
</script>
点击触发3次addd,点击触发3次adde,页面效果及控制台信息如下:
此时我们触发一次addd,页面效果如下:
很明显,我们可以看出,更新新增属性e,是不会更新视图,但是会改变其值,当更新原有的属性d时才会更新视图,同时将新增的属性e的值也更新导视图里边。
解决方案
官方定义:Vue不允许在已经创建的实例上动态添加新的根级响应式属性(root-level reactive property)。然后而他可以使用Vue.set(object,key,value)方法将响应属性添加到嵌套的对象上:
Vue.set(vm.obj,’e’,0)
你还可以使用vm.$set实例方法,这也是全局Vue.set方法的别名:
this.$set(this.obj,’e’,02)
有时你想向已有的对象上添加一些属性,例如使用Object.assign()或_.extend()方法来添加属性。但是,添加到对象上的新属性不会触发更新。在这种情况下可以创建一个新的对象,让它包含原对象的属性和新的属性。
//代替Object.assign(this.obj,{a:1,e:2})
this.obj=Object.assign({},this.obj,{a:1,e:2})
上述实例解决方案如下:
点击触发三次addd,点击触发三次adde,页面效果及控制台信息如下: