前言
在Vue2中当我们通过数组的下标去修改数组值,或者向对象添加添加属性时,对应的视图都无法进行更新,这是因为我们所添加的数据不是响应式的,无法响应视图的变化。那么此时我们可以通过$set来实现。对于数组可以通过this.$set(this.arr,0,‘xx’)来去修改数组下标对应的值,对于对象可以通过this.$set(this.obj,‘a’,‘xxx’)向对象新增属性a,接下来我们来根据源码来分析原理。
源码分析
源码如下:
if (isUndef(target) || isPrimitive(target)) {
warn(("Cannot set reactive property on undefined, null, or primitive value: " + ((target))));
}
// 判断是否为数组,并判断key是不是有效索引,
if (Array.isArray(target) && isValidArrayIndex(key)) {
// 判断下标和数组长度,将数组的.length属性设置为最大值
target.length = Math.max(target.length, key);
// 调用数组的splice方法,将修改的数据变为响应式
target.splice(key, 1, val);
// 返回对应的val
return val
}
// 如果这个属性在这个对象上,则设置属性为对应的属性值后直接返回val
if (key in target && !(key in Object.prototype)) {
target[key] = val;
return val
}
// 获取响应式对象__ob__
var ob = (target).__ob__;
// 判断当前的目标对象是否是Vue实例,或者根数据对象,如果是则warn警告并返回
if (target._isVue || (ob && ob.vmCount)) {
warn(
'Avoid adding reactive properties to a Vue instance or its root $data ' +
'at runtime - declare it upfront in the data option.'
);
return val
}
// 当前的这个目标对象如果不是响应式对象则直接赋值返回
if (!ob) {
target[key] = val;
return val
}
// 给目标对象对应的属性添加响应式
defineReactive$$1(ob.value, key, val);
// 通知所有订阅者,调用update,更新渲染视图
ob.dep.notify();
return val
源码分析如下:
当$set所设置的目标对象为数组时,则调用目标对象的splice方法将修改的数据变为响应式。
当$set所设置的目标对象为对象时,首先判断这个属性是否在这个对象上,如果存在则设置属性为对应的属性值后直接返回val,然后判断目标对象是否为Vue实例或者根数据对象,如果是则warn警告后返回,再去判断这个目标对象是否是响应式的,如果不是响应式对象则直接赋值返回。最后在给目标对象的属性添加响应式,通知dep实例的所有订阅者进行更新。