vue2的缺陷
下班回家的途中,一个问题困扰我很久,在vue2中为什么不能给对象直接赋值? 若是使用其他的的api又觉得麻烦,于是就有了这篇博客!!!
数组的部分操作也没有响应式
- push(),pop(),shift(),unshift(),splice(),sort(),reverse()
因为这7个api会修改原数组,换句话来说,只要不修改原数组的api都没有响应式.
一、直接添加属性的问题
我们从一个例子开始
定义一个p标签,通过v-for指令进行遍历
然后给botton标签绑定点击事件,我们预期点击按钮时,数据新增一个属性,界面也 新增一行
<p v-for="(value,key) in item" :key="key">
{{ value }}
</p>
<button @click="addProperty">动态添加新属性</button>
实例化一个vue实例,定义data属性和methods方法
const app = new Vue({
el:"#app",
data:()=>{
item:{
oldProperty:"旧属性"
}
},
methods:{
addProperty(){
this.items.newProperty = "新属性" // 为items添加新属性
console.log(this.items) // 输出带有newProperty的items
}
}
})
点击按钮,发现结果并不是我所想的,数据虽然更新了(console打印出了新属性),但页面并没有更新
二、原理分析
下面来分析一下
由于vue2是用过Object.defineProperty实现数据响应式
const obj = {}
Object.defineProperty(obj, 'foo', {
get() {
console.log(`get foo:${val}`);
return val
},
set(newVal) {
if (newVal !== val) {
console.log(`set foo:${newVal}`);
val = newVal
}
}
})
}
当我们访问foo属性或者设置foo值的时候都能够触发setter与getter
obj.foo
obj.foo = 'new'
但是我们为obj添加新属性的时候,却无法触发事件属性的拦截
obj.bar = '新属性'
原因是一开始obj的foo属性被设成了响应式数据,而bar是后面新增的属性,并没有通过Object.defineProperty设置成响应式数据
三、解决方案
Vue 不允许在已经创建的实例上动态添加新的响应式属性
若想实现数据与视图同步更新,可采取下面三种解决方案:
- Vue.set()
- Object.assign()
- $forcecUpdated()
自我认为 三种方法中了解一个即可
Vue.set()
格式:
fn2(){
// 添加一个属性+有响应式
// vue提供的API
// $set(对象,属性名,属性值)
this.$set(item, this.items.newProperty, '新属性')
},
转载自:https://juejin.cn/post/7097958274091188231