一、添加属性的问题
<template>
<div>
<p v-for="(value,key) in item" :key="key">
{{ value }}
</p>
<button @click="addProperty">动态添加新属性</button>
</div>
</template>
<script>
export default {
data:()=>{
item:{
oldProperty:"旧值"
}
},
methods:{
addProperty(){
this.item.newProperty = "新值" // 为items添加新属性
console.log(this.items) // 输出带有newProperty的items
}
}
};
</script>
这时候我们会遇到一个问题:log打印结果了,但是dom并没有重新渲染。
二、问题分析:
const item = {}
Object.defineProperty(obj, 'oldProperty', {
get() {
console.log(`get oldProperty:${val}`);
return val
},
set(newVal) {
if (newVal !== val) {
console.log(`set oldProperty:${newVal}`);
val = newVal
}
}
})
}
三、解决方案
由于Vue已经不允许在已经创建的实例上添加新的响应式属性,所有可以采用以下三种方法:
-
Vue.set()
-
Object.assign()
-
$forcecUpdated()
(1)、Vue.set()
Vue.set( target, propertyName/index, value )
- 参数1:target:要修改的对象或数组
- 参数2:propertyName/index:属性或下标
- 参数3:value:修改后的value值
function set (target: Array<any> | Object, key: any, val: any): any {
...
defineReactive(ob.value, key, val)
ob.dep.notify()
return val
}
(2)、Object.assign()
- 参数1:一个空对象,用来存放新增属性与原对象混合之后的对象
- 参数2:原来的对象
- 参数3:需要给对象新增的属性
this.item = Object.assign({},this.item,{newProperty:'新值'})
(3)、$forcecUpdated
在Vue实例添加这个方法
this.$forcecUpdated()
四、小结。
PS:vue3是用过proxy实现数据响应式的,直接动态添加新属性仍可以实现数据响应式