動態

詳情 返回 返回

vue生命週期及雙向綁定 - 動態 詳情

這篇文章不是原創,看了其他人的分析貼,記錄下自己學到的。本篇主要記錄一下vue內部流程,以及雙向綁定原理。Vue的可愛之處在於他的雙向綁定及Virtual DOM的思想。

vue內部流程

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]

Add a new 評論

Some HTML is okay.