前言:
前段时间给公司前端讲解$set使用场景,当场翻车了,很简单的问题,让我郁闷了一下午,各种查文档,终于知道了为啥对象新增一个属性,而这个属性在视图上更新了
咱们先聊下,vue.$set是什么?,怎么用?在什么场景下使用它?
概念:向响应式对象中添加一个property,并确保这个新的property同样是响应式的,且触发视图更新。
示例代码:
<template>
<div>
{{ userInfo }}
<div>
<button @click="handleAdd">新增属性</button>
<button @click="handleEdit">修改属性</button>
</div>
</div>
</template>
export default{
data(){
userInfo:{
name:"小甜甜"
},
},
methods: {
handleAdd() {
this.userInfo.age= "18";
console.log(this.userInfo);
},
handleEdit() {
this.userInfo.age= "28";
console.log(this.userInfo);
}
}
}
问题描述:在响应式对象userInfo上新增age属性,视图并没有更新,但是在控制台可以打印出来
用法:
Vue.set(target,propertyName/index,value)
参数一: 目标对象或数组
参数二:对象属性或数组下标值
参数三:新增属性的内容
//在示例代码的基础上 使响应式对象userInfo新增的age属性也具有响应式
...
handleAdd() {
this.$set(this.userInfo, "age", 18);
},
...
但是,请看下面的代码,没有使用this.$set去新增age属性,age居然也更新了
...
handleAdd(){
//执行如下代码,视图里的age也被更新了
this.userInfo.name="小宝贝";
this.userInfo.age=18;
}
...
原来:此时的 userInfo.age 并不是变成了响应式属性,而是 userInfo.name 更新了触发视图更新,所以userInfo.age在视图上也更新了!!!所以,终于破案了
总结:
- 由于vue2使用Object.defineProperty()对data,props,computed,watch,methods里的数据进行劫持,但它无法监听属性的新增和删除,所以需要使用set和delete
- set用于将响应式对象新增的属性变成响应式属性
- 注意有时候不使用set新增的属性在视图也更新了,可能是其它响应式属性更新触发了视图更新
最后,我们谈谈Vue.set的原理是啥
- 当目标是数组的时候,借助vue内部拦截处理后数组的splice方法进行赋值。vue对数组的'push','pop','shift','unshift','splice','sort','reverse'方法进行拦截处理成响应式,调用这些方法,可以触发界面的更新
- 如果目标是对象,会先判断属性是否存在,对象是否是响应式,如果要对属性进行响应式处理,则是通过调用defineReactive方法。(defineReactive 方法就是 Vue 在初始化对象时,给对象属性采用 Object.defineProperty 动态添加 getter 和 setter 功能所调用的方法)