關於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的雙向綁定原理和實現

好的,先看看這個吧。哈哈!

從圖開始

咱們先看下下面的圖,先瞭解下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
    });
}

以上就是關於vue中如何監聽數組變化的詳細內容,更多關於vue如何監聽數組的資料請關註WalkonNet其它相關文章!

推薦閱讀: