vue中wath的源碼實現

前言

閱讀本節,需要理解vue的數據驅動原理。

看這樣一段代碼

new Vue({
    data: {
        msg: 'hello',
        say: 'hello world',
    },
    watch: {
        msg(newVal) {
            this.say = newVal + ' world';
        }
    }
})

vue的data包括2個屬性msg和say,watch中監聽msg並更新say的值。

源碼實現

1. new Vue

function Vue (options) {
  if ("development" !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword');
  }
  this._init(options);
}

new Vue會執行原型上的_init方法, _init方法中hi調用 initState,這個方法會初始化所有狀態相關內容

2. initWatch

initStatus會判斷如果我們定義了watch則執行initWatch

function initWatch (vm, watch) {
  for (var key in watch) {
    var handler = watch[key];
    if (Array.isArray(handler)) {
      for (var i = 0; i < handler.length; i++) {
        createWatcher(vm, key, handler[i]);
      }
    } else {
   createWatcher(vm, key, handler); } } }

這段代碼意思是如果watch聲明瞭一個數組,則遍歷數組並調用createWatcher,如果不是數組就直接調用createWatcher傳遞過去。這就證明,watch我們可以聲明多個處理函數。

3. createWatcher

createWatcher主要工作是處理傳入值,傳入不同的值,做不同的兼容處理

function createWatcher (
  vm,
  expOrFn,
  handler,
  options
) {
 // 如果handler是對象,則獲取handler下面的handler屬性當作watch的執行函數
  if (isPlainObject(handler)) {
    options = handler;
    handler = handler.handler;
  }
// 如果handler是字符串,則獲取vue原型上的方法
  if (typeof handler === 'string') {
    handler = vm[handler];
  }
// 調用vue原型上的$watch
  return vm.$watch(expOrFn, handler, options)
}

通過以上我們可以看出,watch定義有很多種類型,比如:

new Vue({
    watch: {
       // 字符串
        test1: 'handleTest',
        // 對象
        test2: {
            handler(newVal) {
                // ....
            }
        }
    },
    methods: {
        handleTest(newVal) {
            // ...
        }
    }
})

4. vm.$watch

Vue.prototype.$watch = function (
    expOrFn,
    cb,
    options
) {
    var vm = this;
    if (isPlainObject(cb)) {
        return createWatcher(vm, expOrFn, cb, options)
    }
    options = options || {};
    options.user = true;
    // new 一個Watcher實例
    var watcher = new Watcher(vm, expOrFn, cb, options);
    if (options.immediate) {
        cb.call(vm, watcher.value);
    }
    return function unwatchFn() {
        watcher.teardown();
    }
};

通過以上代碼可以看出,watch的創建最終其實是vue內部創建了一個Watcher實例。那麼Watcher是vue中很重要的一部分,它是數據驅動不可缺少的一部分。

接下來大概講一下new Watcher的功能是什麼樣的。

5. new Watcher

vue在拿到了要監聽的屬性和屬性更新執行的函數後,new Watcher創建一個Watcher。

Watcher是訂閱者,它“監聽更新行爲”並執行更新函數。

爲什麼雙引號?其實不是它在監聽。以最初的代碼爲例更新步驟如下:

1. vue內部new Watcher創建一個Watcher實例

2. Watcher實例創建時會將自己添加到data.msg的Observer中(數據驅動原理知識)

3. 當我們改變msg值時,msg Observer會通知所有被觀察者,其中就包括以上Watcher。(數據驅動原理知識)

4. Watcher觸發更新並且執行回調,因此執行了我們聲明的函數。

完結

watch的實現很簡單,這裏需要vue的數據驅動原理,由Object.defileProperty、Dep、Watcher幾部分實現。不瞭解的可以先去學習這部分內容。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章