前言
閱讀本節,需要理解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幾部分實現。不瞭解的可以先去學習這部分內容。