【Vue原理】Diff - 源碼版 之 重新建實例到開始diff

寫文章不容易,點個讚唄兄弟 <br> <br> 專一 Vue 源碼分享,文章分爲白話版和 源碼版,白話版助於理解工做原理,源碼版助於瞭解內部詳情,讓咱們一塊兒學習吧 研究基於 Vue版本 【2.5.17】node

若是你以爲排版難看,請點擊 下面連接 或者 拉到 下面關注公衆號也能夠吧函數

【Vue原理】Diff - 源碼版 之 重新建實例到開始diff 學習

Diff 的內容不少,咱們先來探索一下從 新建實例 到 開始Diff 的流程走一遍,本文很短this

先對整個流程有個把握,再仔細去探索 Diff 的思想spa

公衆號

首先,當你新建實例的時候,好比這樣prototype

公衆號

你調用一個 Vue 函數,因此來看下 Vue 函數code

function Vue() {    

    ... 已省略其餘

    new Watcher(function() {

        vm._update(vm._render());
    })

    ... 已省略其餘

}

函數中作了兩件事blog

一、爲實例新建一個 watchertoken

二、爲 watcher 綁定更新回調(就是 new Watcher 傳入的 function )ci

每一個實例都會有一個專屬的 watcher,而綁定的回調,在頁面更新時會調用

咱們如今來看下簡化的 Watcher 的源碼

funciton Watcher(expOrFn){    

    this.getter = expOrFn;    

    this.get();

}



Watcher.prototype.get = function () {    

    this.getter()

}

watcher 會保存更新回調,而且在新建 watcher 的時候就會馬上調用一遍更新回調

如今咱們繼續看 更新回調的內容

vm._update(vm._render());

若是你看到以前的文章應該知道這兩個函數的做用

如今就來簡單說一下

1vm._render

生成頁面模板對應的 Vnode 樹,好比

公衆號

生成的 Vnode 樹是( 其中num的值是111 )

{    

    tag: "div",    

    children:[{        

        tag: "span"

    },{        

        tag: undefined,        

        text: "111"

    }]
}

這一步是經過 compile 生成的,具體的話能夠簡單看下 Compile - 白話版

有興趣的有耐心的也能夠看源碼版

公衆號

2vm._update

比較 舊Vnode 樹 和 vm._render 生成的新 Vnode 樹 進行比較

比較完後,更新頁面的DOM,從而完成更新

ok,咱們看下源碼

Vue.prototype._update = function(vnode) {  



    var vm = this;    

    var prevEl = vm.$el;    

    var prevVnode = vm._vnode;

    vm._vnode = vnode;    



    // 不存在舊節點

    if (!prevVnode) {

        vm.$el = vm.__patch__(
            vm.$el, vnode,
            vm.$options._parentElm,
            vm.$options._refElm
        );
    }    

    else {

        vm.$el = vm.__patch__(

            prevVnode, vnode

        );

    }
};

解釋其中幾個點

1 vm._vnode

看過 VNode - 源碼版 應該知道,這個屬性保存的就是當前 Vnode 樹

當頁面開始更新,而生成了新的 Vnode 樹以後

這個屬性則會替換成新的Vnode

因此保存在這裏,是爲了方便拿到 舊 Vnode 樹

2 vm.patch

是的,沒有錯,你在兩處地方看到這個東西

這個東西就是 Diff 的主要內容,內有乾坤,內容不少,不會在這裏說,畢竟今天只探索流程

可是要看看這個東西怎麼來的

var patch = createPatchFunction();

Vue.prototype.__patch__ =  patch ;

嗯,是通過一個 createPatchFunciton 生成的

而後賦值到 Vue 的原型上,因此能夠 vm.patch 調用嘍

咱們再來講說 _update 函數中出現的那兩處 patch

1 不存在舊節點

不須要進行比較,直接所有建立

vm.$el 保存的是 DOM 節點,若是不存在舊節點,那麼 vm.$el 此時也是不存在的

而傳入 vm.$el 爲空的時候,patch 拿到這個值判斷爲空的時候,就直接建立DOM,不會去作其餘操做了

2 存在舊節點

須要把舊節點和新節點比較,儘可能找到最小差別部分,而後進行更新,這部份內容就是 Diff 的重點了,須要花費很多精力的。會放在其餘文章進行記錄

公衆號


最後

鑑於本人能力有限,不免會有疏漏錯誤的地方,請你們多多包涵,若是有任何描述不當的地方,歡迎後臺聯繫本人,有重謝

公衆號

相關文章
相關標籤/搜索