vue生命週期及雙向綁定

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

vue內部流程

vue內部流程

如圖所示,實例化組件時,調用init方法,初始化事件,屬性,data等。初始化data,是實現雙向綁定的重要一步(後面再詳細說)。掛載($mount)時,根據傳入的模版解析編譯成 render function。 再把render function 轉成 Virtual DOM tree(虛擬DOM樹)。數據更新時,Virtual DOM tree轉成 真正的DOM以前,經歷patch方法,計算那些更新的節點,更新相應的節點,生成DOM.每一個步驟拆開的話以下:vue

init

組件實例化時,調用init(),初始化組件的生命週期相關屬性,事件,props,data等等。vue雙向綁定也在這個期間完成的(後面再細說)。java

compile

組件$mount(掛載)時,根據傳入的模版或者節點標識(id等)把組件模版編譯(compile)成render function。 編譯過程分三步:git

  • 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好比:github

{
    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對象this

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代碼url

參考:

掘金[vue內部運行機制][4],、
源碼講解[vue2.0遠嗎解讀][5]
相關文章
相關標籤/搜索