编程语言
首页 > 编程语言> > vue双向数据绑定数组失效,源码修改

vue双向数据绑定数组失效,源码修改

作者:互联网

我们都知道在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的话,可以这么玩,如果是公司项目的话,个人建议还是保持原样,因为涉及到性能!

标签:__,vue,Observer,绑定,ob,value,源码,数组,observeArray
来源: https://www.cnblogs.com/huoshengmiao/p/16587328.html