小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
$set的作用
vm.$set(target, key, value)中接收三个参数
- targer 目标值
- key 将要设置的属性
- value 要设置的值
对于在初始化data时已经设置的值,当我们改变他们的值,可以触发视图更新,但是新增的属性却无法被追踪到并触发视图更新,例如:
person:{name:'张三'}中我们想要再添加一个age属性,通过赋值的方式设置属性并不是响应式。因此需要借助$set方法去设置。
前期准备和资料
解读
前端相关代码
<div id="app">
<h2>数组的处理</h2>
<p v-for="num in numList">{{num}}</p>
<button v-on:click="add">添加</button>
<h2>新增的属性</h2>
<p v-if="person.name">{{person.name}}</p>
<p v-if="person.age">{{person.age}}</p>
<button v-on:click="setAge">添加age</button>
</div>
<script>
let vue = new Vue({
el: '#app',
data: {
numList:[0,1],
person:{
name: '张三',
}
},
methods:{
add(){
this.$set(this.numList, this.numList.length, this.numList.length)
},
setAge(){
this.$set(this.person, 'age', 18)
}
},
});
</script>
$set的原理是在vue的原型上添加$set的方法,同时针对以下三种情况情况分别进行处理
- 当key已经存在于target上的时候,直接修改target中对应key的值
- 当target是数组的时候,借助vue内部拦截处理后数组的splice方法进行赋值,vue对数组的
'push','pop','shift','unshift','splice','sort','reverse'方法进行拦截处理成响应式,调用这些方法,可以触发界面的更新(后续添加这部分解说),如果只是通过arr[2]=2的方式进行赋值不会触发视图更新。 - 对于新增的属性,通过defineReactive把数据转化成getter和setter的方式,并触发数据变化通知
function set (target, key, val) {
if (isUndef(target) || isPrimitive(target)) {
warn(("无法在未定义、null或基元值上设置被动属性"));
}
// 对数组的处理
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key);
target.splice(key, 1, val);
return val
}
// target已经存在对应的key
if (key in target && !(key in Object.prototype)) {
target[key] = val;
return val
}
// 新增的属性的处理
var ob = (target).__ob__;
if (target._isVue || (ob && ob.vmCount)) {
warn("target不能是vue的实例或根数据对象");
return val
}
if (!ob) {
target[key] = val;
return val
}
defineReactive$$1(ob.value, key, val);
ob.dep.notify();
return val
}
Vue.prototype.$set = set;
下图是对数组进行处理的代码执行
下图是对新增属性处理的代码执行