【Vue原理】Component - 源碼版 之 建立組件VNode

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

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

【Vue原理】Component - 源碼版 之 建立組件VNode ios

今天就要開啓咱們 Component 探索之旅,旅途有點長,各位請坐好,不要睡着了函數

內容的主題是,Component 的建立過程,從調用 component,到 component 掛載,到底經歷了什麼?歡迎來到 component 的心裏世界學習

建議能夠先看看白話版this

Component - 白話版 prototype

Component 建立,我主要分了兩個流程3d

一、建立 組件 VNode
二、掛載 組件 DOM

每一個流程涉及源碼都不少,因此每一個流程寫一篇文章。沒錯了,今天講的就是 建立組件 VNodecode


場景設置

首先,咱們假定如今有這麼一個模板,使用了 test 組件component

公衆號

公衆號

而後頁面噼裏啪啦執行到了 準備掛載DOM 的步驟(以前的部分跟本主題無關,跳過)

而後頁面準備執行渲染函數 render,嗯,就是執行上面模板生成的渲染函數,以下

公衆號

沒有錯,咱們的 Vue 已經走到了這一步,那麼咱們的突破口是什麼?

沒錯,就是 _c

function _createElement(

    context, tag, data, children

) {    

    var vnode;        

    var options = context.$options    

    // 從父組件選項上拿到 對應的組件的選項

    var Ctor = options.components[tag]    

    if (正常的HTML標籤) { ....直接新建VNode }    

    else if ( Ctor ) {

        vnode = createComponent(

            Ctor, data, context, 

            children, tag

        );

    }    

    return vnode

}

今天講的是 component,跳過其餘,直接走到 第二個 if,嗯,他調用了一個 createComponent

好的,我去前面探探路

function createComponent(
    Ctor, data, context, 

    children, tag

) {    

    var baseCtor = context.$options._base;  

    // 建立組件構造函數
    Ctor = baseCtor.extend(Ctor);    

    var vnode = new VNode(

        "vue-component-" + (Ctor.cid) + name, 
        data, undefined, undefined, 

        undefined, context,

        {            
            Ctor: Ctor
        }
    );    

    return vnode

}

這個 createComponent 什麼鬼的,做用大概是

一、建立組件構造函數

二、處理父組件給子組件的數據

三、建立組件 外殼 VNode

因爲處理數據什麼的,跟本內容無關,因此其餘源碼一概去掉,那麼就只剩下兩個流程

下面就開始這兩個流程


建立組件構造函數

上面的源碼中有兩句話(以下),做用就是爲組件建立一個構造函數!

var baseCtor = context.$options._base;
Ctor = baseCtor.extend(Ctor);

看得懂嗎?看懂了?好吧,那我就不講了

算了,算了,仍是講吧,畢竟當時本身也是懵逼的

首先,context 是什麼?

context 是執行整個渲染函數的上下文對象,很明顯,這裏就是頁面的 實例vm 了

那麼,$options 是什麼?

$options 就是 實例自定義選項 和 全局選項合併以後的 產物

Vue.prototype._init = function(options) {
    .....

    vm.$options = mergeOptions( // 把兩個對象合併       

        vm.constructor.options, 
        options, vm
    );
    .....

}

vm.constructor 是什麼?

沒錯,就是 Vue,你使用 new Vue 建立的頁面,構造函數確定是 Vue 啦

vm.constructor.options 是什麼?

看下面

Vue.options = Object.create(null);

Vue.options.components = Object.create(null);
Vue.options.directives = Object.create(null);
Vue.options.filters = Object.create(null);

Vue.options._base = Vue;

Vue 在引入的時候,就完成了不少初始化的內容,這裏就是其中給 Vue 增長options 的部分

你看到的 component 啊,filter 什麼的啊,沒錯,保存的就是你全局註冊的 component,filter

而後每一個頁面都能使用到 全局組件,全局filter 的緣由

就是由於在 頁面實例初始化的時候,把 頁面選項 和 全局選項私下合併

而後,你應該能看到這一句,保存了 Vue 構造函數在 options._base 中

Vue.options._base = Vue;

那麼,你應該能理解前面出現的源碼了

var baseCtor = context.$options._base;

沒錯!baseCtor 拿到的就是 Vue!!!!

而後還有一句

Ctor = baseCtor.extend(Ctor);

既然 baseCtor 是 Vue,那 baseCtor.extend 是 Vue.extend?沒有錯!

正是他!完成了建立組件構造函數的偉大之舉!!讓咱們一塊兒來欣賞下

Vue.extend = function(extendOptions) {    

    // this 指向Vue 
    var Super = this;    

    var Sub = function VueComponent(options) {        

        this._init(options); 

    };    
    // 原型鏈繼承

    Sub.prototype = Object.create(Super.prototype);
    Sub.prototype.constructor = Sub;    

    // Super 永遠是 Vue,因此這裏就是 合併全局選項

    // 如今 Super 就是 vue,把 Vue 和 Sub 合併

    // 是把一些全局的組件 指令合併到 Sub 中

    Sub.options = mergeOptions(        

        // optios 還包括 mixins 注入的全局

        Super.options, 
        extendOptions

    );   

    return Sub

};

這個函數,會返回一個函數 VueComponent,他就是組件的構造函數!用來下篇文章建立組件實例的!!

上面的源碼,作的事,簡單說,就是繼承父類Vue,而後合併 options 等

最後,提一下,全部實例的父類構造函數 Super 都是 Vue

並非說,組件 a 有一個子組件b,而後組件b 的父類構造函數就是 a.contructor,這是不對的,永遠是Vue,誰都是 Vue

公衆號


建立組件外殼VNode

如今就是前面代碼 createComponent 中的最後一步了

注意注意,這裏建立的是【組件外殼節點】,內部節點尚未上場,在下篇文章纔出現

至於,什麼是外殼節點,去看下個人 VNode - 源碼版

跳到相關內容看就行了

var vnode = new VNode(
    "vue-component-" + Ctor.cid + name, 
    data, undefined, undefined, 

    undefined, context, 

    {        

        Ctor: Ctor

    }
);

那麼這個外殼節點的做用是什麼?

一、保存剛建立好的組件構造函數,下篇文章中會調用到

二、保存父組件給子組件 關聯的數據,好比 event,props 之類的(因爲跟本主題無關,爲了整潔,通通去掉了)


總結

Component 建立 外殼節點的流程,總結以下

一、頁面渲染函數執行

二、_c('test') 執行

三、createElement 碰到 tag 是一個組件

四、從父組件中,拿到 test 組件的options,傳入 createComponent (做用是建立構造函數和 VNode)

五、createComponent 調用 Vue.extend 建立組件構造函數

六、新建 VNode,並把構造函數和父組件給子組件的數據保存進去

七、返回 VNode

公衆號

相關文章
相關標籤/搜索