一、直接添加属性产生的现象
const app = new Vue({
el:"#app",
data:()=>{
item:{
oldProperty:"旧属性"
}
},
methods:{
addProperty(){
this.items.newProperty = "新属性" // 为items添加新属性
console.log(this.items) // 输出带有newProperty的items
}
}
})
代码解析:当执行 addProperty 为 data 添加新属性时,data 确实更新了,但是没有响应式,页面并没有更新,众所周知 vue2 是用过 Object.defineProperty 实现数据响应式的,当我们调用 oldProperty 或者修改 oldProperty 的时候都能够触发他的 setter 与 getter 方法,是因为oldProperty 在初始化的时候就已经被 defineProperty 重新定义了,而 newProperty 是新添加的属性,并没有被 defineProperty 重新定义
二、解决方法
2-1 Vue.set()
-
通过 Vue.set 向响应式对象中添加一个新的属性 ,并确保这个新属性同样是响应式的,且触发视图更新,无需在再调用
defineReactive方法,实现新增属性的响应式 -
Vue.set( target, key, value ) / this.$set( target, key, value )
target:要更改的数据源(可以是对象或者数组)
key:新增的属性名
value :重新赋的值
<template>
<p>{{item.oldProperty}}</p>
<p>{{item.newProperty}}</p>
<button @click="dynamicClick()">新增属性</button>
</template>
<script>
data() {
return {
items:{ oldProperty:"旧属性"}
}
},
methods: {
dynamicClick:function(){
this.$set(this.items,"newProperty","新属性")
},
}
</script>
2-2 Object.assign()
直接使用 Object.assign() 添加到对象的新属性不会触发更新,应该合并原对象和混入对象的属性后,再去给对象重新赋值,就会触发更新,本质上就是通过重新给对象赋值,来使视图更新
<template>
<p>{{item.oldProperty}}</p>
<p>{{item.newProperty}}</p>
<button @click="dynamicClick()">新增属性</button>
</template>
<script>
data() {
return {
items:{ oldProperty:"旧属性"}
}
},
methods: {
dynamicClick:function(){
this.items = Object.assign({}, this.items, {newProperty: "新属性"})
}
}
</script>
2-3 forceUpdate
$forceUpdate 会迫使 Vue 实例重新渲染,也就是强制更新,不建议使用