vue中的虛擬dom和雙向數據綁定的結合。vue1.0中使用Object.defineProperty了雙向數據綁定,使用dep進行訂閱發布鏈接watcher和data的橋梁。這時候,一個data頁面中用到幾處就會在dep中添加幾個函數更新相對應的dom。但是vue2.0中結合虛擬dom機制。所以沒有所謂的temple中一個指令對應一個dom更新函數。而是一個組件只有一個更新函數為render。這個當數據變化時候,這個函數會對比前后的虛擬dom更新真正需要更新的真實dom。
所以vue2中data的一個變量有3個地方會有對應的watcher
一個vm組件會對應一個watcher,這個watcher關注的是vm的_render方法,每個vue文件的template里面的內容都會被編譯成一個_render方法,
并且里面用到的屬性或者computed都會轉化成_vm.name 或者_vm.infoName 的代理形式,具體的轉化過程在dep里面說到computed對象里面的每個屬性,都有一個對應的watcher,如上例:infoName,infoSex都會有一個對應的watcher,并且生成的watcher的lazy為true,
即它們都是懶更新的,只有里面用到的相關數據出現變化的時候,這個watcher才會執行getter方法watch對象里面的每個屬性,都有一個對應的watcher,如上例:sex,name,"resultObj.allInfo"都會有一個對應的watcher
我發現vue2中 對于頁面渲染只會 new 一個 Watcher。因為每個Watcher的回調函數都是一樣的觸發render。在render的時候會遍歷data觸發所有的get。所有每個data的值的Watcher都是這個Watcher。更新的時候,Watcher的id一樣則只更新一個,每個computed或者watch的key都會 new 一個 Watcher。這時候再執行相對應的value,就會觸發相應的data的get。對應的data對push剛剛new 的這個 Watcher。
vue2中data的watcher是如何push到對應的dep中的呢?
vue2 中
- 首先會生成render函數
- 執行$mount函數,函數內簡易關鍵代碼如下
var updateComponent = function () {
vm._update(vm._render(), hydrating);
};
new Watcher(vm, updateComponent, noop, null, true /* isRenderWatcher */);
function Watcher (vm,
expOrFn,
cb,
) {
if (typeof expOrFn === 'function') { // expOrFn就為 updateComponent
debugger
this.getter = expOrFn;
} else {
this.getter = parsePath(expOrFn);
if (!this.getter) {
this.getter = function () {};
}
}
this.value = this.lazy // computed 的lazy 才會為true。
? undefined
: this.get(); // 如下段代碼
};
}
Watcher.prototype.get = function get () {
pushTarget(this); // Dep.target = this;
var value;
var vm = this.vm;
try {
value = this.getter.call(vm, vm); // 執行了vm._update(vm._render(), hydrating);
} catch (e) {
} finally {
popTarget();// Dep.target = null;
}
return value
};
this.getter.call(vm, vm)
觸發了vm._update(vm._render(), hydrating);
所以觸發所有的data的get屬性,所以所有的data屬性都在此時添加了依賴并且是一樣的依賴。