我们都知道在vue中直接修改数组下标来修改数据,是不能触发vue的更新机制的,但是当你发现随着项目代码越来越多,你的$set会越来越多,这样会让你的代码可读性、维护性越来越差
本次博主就来为大家分享一下,修改vue源码,让vue支持修改下标触发更新
function observe (value, asRootData) {
if (!isObject(value) || value instanceof VNode) {
return
}
var ob;
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
ob = value.__ob__;
} else if (
shouldObserve &&
!isServerRendering() &&
(Array.isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value._isVue
) {
ob = new Observer(value); // 看这里,那么Observer又是什么呢?
}
if (asRootData && ob) {
ob.vmCount++;
}
return ob
}
// 我们继续看
var Observer = function Observer (value) {
this.value = value;
this.dep = new Dep();
this.vmCount = 0;
def(value, '__ob__', this);
// 我们看到如果是数组,则执行this.observeArray,那么这个方法又做了什么呢?
if (Array.isArray(value)) {
if (hasProto) {
protoAugment(value, arrayMethods);
} else {
copyAugment(value, arrayMethods, arrayKeys);
}
this.observeArray(value);
} else {
// 看完上面的observeArray,我们继续看this.walk又做了什么?
this.walk(value);
}
};
// 原来这个observeArray,其实就是个递归,如果是数组就遍历,然后继续执行observe -> new Observer
Observer.prototype.observeArray = function observeArray (items) {
for (var i = 0, l = items.length; i < l; i++) {
observe(items[i]);
}
};
Observer.prototype.walk = function walk (obj) {
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++) {
defineReactive$$1(obj, keys[i]);
}
};
// 我们继续看defineReactive$$1,又做了什么?
// 原来他的庐山真面目就是defineProperty,这下我们都明白了吧
function defineReactive$$1 (
obj,
key,
val,
customSetter,
shallow
) {
...
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
var value = getter ? getter.call(obj) : val;
...
},
set: function reactiveSetter (newVal) {
...
dep.notify();
}
});
}
原来在vue源码中,只对Object的各个key进行了监听,对数组下标并没有,那么我们如何修改呢?
var Observer = function Observer (value) {
this.value = value;
this.dep = new Dep();
this.vmCount = 0;
def(value, '__ob__', this);
// 我们看到如果是数组,则执行this.observeArray,那么这个方法又做了什么呢?
if (Array.isArray(value)) {
if (hasProto) {
protoAugment(value, arrayMethods);
} else {
copyAugment(value, arrayMethods, arrayKeys);
}
this.observeArray(value);
this.walk(value); // 我们只需要在这里添加这行,就可完成对下标的监听
} else {
// 看完上面的observeArray,我们继续看this.walk又做了什么?
this.walk(value);
}
};
完成以上修改后,我们再直接修改数组下标,页面也会进行更新
以上内容是我自己平时写项目得到的想法(不想写那么多$set),那我这个菜鸡能想到,尤大就想不到吗?
下面贴上尤大对此处的回答https://github.com/vuejs/vue/issues/8562
看到了吧?因为性能!我们可以想数组也是对象,不过比较特殊,数组的下标是对象的key,那么如果是一个对象数组,甚至说层级嵌套更加深的数据,是不是监听每一个下标的话,会非常庞大,我使用了100个循环来验证,结果是如果监听数组下标的话渲染时间要比不监听的时候慢了4倍还不止!
所以,这个监听数组下标是可以实现,也可以让你的代码看起来更加优雅,但是如果项目特别小,或者只是自己的测试demo的话,可以这么玩,如果是公司项目的话,个人建议还是保持原样,因为涉及到性能!