這篇文章不是原創,看了其他人的分析貼,記錄下自己學到的。本篇主要記錄一下vue內部流程,以及雙向綁定原理。Vue的可愛之處在於他的雙向綁定及Virtual DOM的思想。
vue內部流程
如圖所示,實例化組件時,調用init方法,初始化事件,屬性,data等。初始化data,是實現雙向綁定的重要一步(後面再詳細説)。掛載($mount)時,根據傳入的模版解析編譯成 render function。 再把render function 轉成 Virtual DOM tree(虛擬DOM樹)。數據更新時,Virtual DOM tree轉成 真正的DOM之前,經歷patch方法,計算那些更新的節點,更新相應的節點,生成DOM.每個步驟拆開的話如下:
init
組件實例化時,調用init(),初始化組件的生命週期相關屬性,事件,props,data等等。vue雙向綁定也在這個期間完成的(後面再細説)。
compile
組件$mount(掛載)時,根據傳入的模版或者節點標識(id等)把組件模版編譯(compile)成render function。 編譯過程分三步:
- parse 解析模版中的指令,屬性等數據,形成AST(抽象語法樹),例如:
const element2 = {
type: 1,
tag: 'a',
attrsList: [{name: ":href", value: "url"}, {name: "target", value: "_blank"}],
attrsMap: {':href': 'url', 'target': '_blank'},
parent: element1,
children: []
};
- optimize 標記靜態節點,更新視圖時,根據diff算法計算更新的節點時,直接跳過靜態節點,提高diff算法性能。
- generate 把AST 轉成render function.
render
render function 轉成 VNode, 生成Virtual DOM tree(虛擬DOM樹).VNode其實是一個描述DO節節點的javascript對象,抽象真正的DOM節點.為什麼需要Virtual DOM ? 因為DOM操作總是很慢,操作數據對象不僅快,還有跨平台的能力。VNode比如:
{
tag: 'div',
children: [
tag: 'a',
text: 'click me'
}
]
}
patch
數據更新時,patch方法是新的 Virtual DOM 樹和舊 Virtual DOM 的diff算法,算出更新了哪些節點,更新對應的DOM節點。
雙向綁定實現
vue的雙向綁定是通過Object.definerProperty加發布訂閲模式實現的。
object.defineProperty具體知識移步這裏。重點是它的get和set方法,比如這個例子:
var obj = {};
var a;
Object.defineProperty(obj, 'a', {
get: function() {
console.log('get val');
return a;
},
set: function(newVal) {
console.log('set val:' + newVal);
a = newVal;
}
});
obj.a; // get val
obj.a = '111'; // set val: 111
vue的雙向綁定原理就是,比如data.number ='123';每個組件用到number屬性的時候,都會調object.defineProperty()的get函數,從而收集到依賴number屬性的vue組件。每個組件實例話時都有一個watcher,就是訂閲者。我們叫收集依賴的對象為Dep。
看下Dep對象
//依賴收集對象
class Dep {
constructor () {
this.subs = [];
}
//收集依賴
addSub (sub) {
this.subs.push(sub);
}
//發佈變化
notify () {
this.subs.forEach((sub) => {
sub.update();
})
}
}
watcher對象
class Watcher {
constructor () {
Dep.target = this;
}
//更新視圖
update () {
console.log("視圖更新了哦");
}
}
初始化過後,Dep對象收集到依賴number屬性的訂閲者watcher1,watcher2(用到number屬性的組件vue1,vue2),當number屬性變化時,調用set函數,我們調用依賴收集對象的(發佈者)update方法去發佈更新,每個watcher(訂閲者)都收到更新提示,更新視圖。就是這個樣子啦~其實不難。
對於那些,show me the code 的同學:demo代碼
參考:
掘金[vue內部運行機制][4],、
源碼講解[vue2.0遠嗎解讀][5]