zoukankan      html  css  js  c++  java
  • 关于vue中如何监听数组变化

    前言

    前段时间学习了关于vue中响应式数据的原理,(并作了学习笔记vue响应式原理),其实是通过Object.defineProperty控制getter和setter,并利用观察者模式完成的响应式设计。那么数组有一系列的操作方法,这些方法并不会触发数组的getter和setter方法。那么vue中针对数组的响应式设计是如何实现的呢...那么我们一起去学习下吧~

    源码部分

    https://github.com/vuejs/vue/blob/dev/src/core/observer/array.js

    从哪开始第一步学习呢

    Emmmm...
    我觉得要先把Vue中的数据响应式原理弄清楚,这样对于理解vue中是如何检测数组的变化才比较好,所以,可以去网上找下文章然后配合源码进行阅读,相信你一定会理解的。推荐下我之前看的一篇博客,还有我看过后自己写的学习记录吧,哈哈。

    vue响应式原理

    vue的双向绑定原理和实现

    好的,先看看这个吧。哈哈!

    资源搜索网站大全https://55wd.com 广州品牌设计公司http://www.maiqicn.com

    从图开始

    咱们先看下下面的图,先了解下vue中实现的思路,这样接下来再看源码的实现,会一清二楚,明明白白。

    看到这个图然后思考一下,是不是大致了解了~

    首先判断浏览器是否支持__proto__指针

    重写数组的这7个方法,然后根据是否支持__proto__,将改写后的数组指向数组的prototype。

    是不是很简单!!!

    看看源码吧

    了解了实现原理,那么我们再看看源码吧,看下源码主要是更深入的了解作者是如何实现的,也可以看下优秀的代码编码方式,加以学习。

    关于一些解释我就写在下面的代码块中了哈!

    //https://github.com/vuejs/vue/blob/dev/src/core/observer/array.js
    
    
    //def方法是基于Object.defineProperty封装的一层方法,很简单,我会在下面把代码贴出来,免得大家去找了。
    import { def } from '../util/index' 
    
    //保存下原生的数组原型对象
    const arrayProto = Array.prototype
    
    //进行原型连接,将arrayMethods的原型指向Array.prototype
    export const arrayMethods = Object.create(arrayProto)
    
    const methodsToPatch = [
      'push',
      'pop',
      'shift',
      'unshift',
      'splice',
      'sort',
      'reverse'
    ]
    
    methodsToPatch.forEach(function (method) {
      // 缓存原生的方法
      const original = arrayProto[method]
      def(arrayMethods, method, function mutator (...args) {
        var args = [], 
        len = arguments.length;
        while (len--) args[len] = arguments[len];
        const result = original.apply(this, args) // 原来的数组方法执行结果
        const ob = this.__ob__ // 这个__ob__就是Observe的实例~~~~
        let inserted
        switch (method) {
          case 'push':
          case 'unshift':
            inserted = args
            break
          case 'splice':
            inserted = args.slice(2)
            break
        }
        if (inserted) ob.observeArray(inserted) // 如果数组有变化,则重新调用observeArray
        // notify change
        ob.dep.notify()  //
        return result
      })
    })

    这个是关于Observe的代码:

    var Observer = function Observer(value) {
        this.value = value;
        this.dep = new Dep();
        this.vmCount = 0;
        def(value, '__ob__', this);  //这里会看到在每个对象数据上都会绑定一个Observe的实例,所以上面代码中的this.__ob__就是这个
        if (Array.isArray(value)) { // 这里判断是否是数组类型的数据,如果是的话就走observeArray
          if (hasProto) {
            protoAugment(value, arrayMethods);
          } else {
            copyAugment(value, arrayMethods, arrayKeys);
          }
          this.observeArray(value); //这里就是处理数组类型的数据,如下
        } else {
          this.walk(value);
        }
      };

    如下是observeArray的实现:

    Observer.prototype.observeArray = function observeArray(items) {
        for (var i = 0, l = items.length; i < l; i++) {
          observe(items[i]); // 这个observe方法如下
        }
      };

    在这里我们看下observe这个方法:

    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);
        }
        if (asRootData && ob) {
          ob.vmCount++;
        }
        return ob
      }

    这个是关于def方法的实现,很简单我就不说了哈:

    function def (obj, key, val, enumerable) {
        Object.defineProperty(obj, key, {
          value: val,
          enumerable: !!enumerable,
          writable: true,
          configurable: true
        });
    }

    就这么多吧...
    也没讲什么,大致看下整理出来的核心代码,应该就可以了解它实现的思路了吧...
    等我研究透了再更新下,就这样吧

  • 相关阅读:
    RHEL安装oracle客户端(版本为11.2)
    为服务器设置固定IP地址
    RHEL配置本地yum
    网线水晶头内线排序
    《汇编语言(第三版)》王爽著----读书笔记01
    kali系统越来越大解决
    Markdown入门简介
    Linux之tail命令
    Linux之df命令
    Linux命令
  • 原文地址:https://www.cnblogs.com/qianxiaox/p/13750909.html
Copyright © 2011-2022 走看看