国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【Vue原理】Directives - 源碼版

draveness / 1648人閱讀

摘要:對(duì)綁定的事件和屬性等進(jìn)行處理,其中包含指令。有專門的方法來處理指令,這個(gè)方法是,其作用,獲取指令鉤子,和對(duì)不同鉤子進(jìn)行不同處理。

寫文章不容易,點(diǎn)個(gè)贊唄兄弟
專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧
研究基于 Vue版本 【2.5.17】

如果你覺得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧

【Vue原理】Directives - 源碼版

咦,上一篇我們已經(jīng)講過白話版啦,主要的邏輯大家應(yīng)該也清楚了的,今天我們就直接開干源碼。有興趣讀源碼的同學(xué),希望對(duì)你們有幫助哦~

沒看過白話版的,還是先別看源碼版了,那么多代碼看了估計(jì)會(huì)懵逼...

首先,上一篇說過,Vue 會(huì)在DOM 創(chuàng)建之后,插入父節(jié)點(diǎn)之前。對(duì)DOM綁定的事件和屬性等進(jìn)行處理,其中包含指令。

Vue 有專門的方法來處理指令,這個(gè)方法是 updateDirectives,其作用,獲取指令鉤子,和對(duì)不同鉤子進(jìn)行不同處理。

updateDirectives 的源碼不是很短,其中還涉及其他方法,不打算一次性放出來,打算一塊一塊分解地講,所以 源碼會(huì)被我分成很多塊

今天我們以兩個(gè)問題開始

1、怎么獲取到設(shè)置的指令鉤子

2、內(nèi)部怎么調(diào)用鉤子函數(shù)

還有,模板上指令會(huì)被解析成數(shù)組,比如下面這個(gè)模板

會(huì)被解析成下面的渲染函數(shù),看下其中的 directives,這就是指令被解析成的終極形態(tài)了。下面 updateDirectives 方法處理指令,處理的就是這個(gè)數(shù)組

with(this) {    
    return _c("div", {        
        directives: [{            
            name: "test",            
            rawName: "v-test"
        },{
            name: "test2",
            rawName: "v-test2"
        }]
    })
}
怎么獲取設(shè)置的指令鉤子

在 updateDirectives 中,處理的是指令的鉤子,那么第一步肯定是要先獲取鉤子啊,不要處理個(gè)錘子。

function updateDirectives(oldVnode, vnode) { 

    // 獲取舊節(jié)點(diǎn)的指令  
    var oldDirs = normalizeDirectives$1(
            oldVnode.data.directives, 
            oldVnode.context);   

    // 獲取新節(jié)點(diǎn)的指令
    var newDirs = normalizeDirectives$1(
            vnode.data.directives, 
            vnode.context);  
}

你也看到了,上面的源碼中有一個(gè) normalizeDirectives$1,他就是獲取鉤子的幕后黑手。

先看作用,再看源碼

1、遍歷本節(jié)點(diǎn)所有的指令,逐個(gè)從組件中獲取

2、把獲取的鉤子添加到 遍歷到的當(dāng)前指令上

function normalizeDirectives$1(dirs, vm) {    

    var res = {};  
    var i, dir;  

    for (i = 0; i < dirs.length; i++) {
        dir = dirs[i]; 
        res[dir.name] = dir;
        dir.def = vm.$options["directives"][dir.name];
    }   
    return res
}

最后返回的是什么呢,舉個(gè)例子看下

比如開始處理的指令數(shù)組是下面

directives: [{            
    name: "test",            
    rawName: "v-test"
}]

v-test 的鉤子函數(shù)是

new Vue({    
    directives:{        
        test:{
            bind(){...},
            inserted(){...},       
            .... 等其他鉤子
        }
    }
})

經(jīng)過 normalizeDirectives$1 ,就會(huì)返回下面這個(gè)

directives: [{            
    name: "test",   
    rawName: "v-test", 
    def:{
        bind(){...},
        .... 等其他鉤子
    }             
}]

好的,拿到了鉤子,那我們下一步就是要處理鉤子了!

怎么調(diào)用鉤子

哈哈,看過白話版的,就知道這里不同的鉤子的處理流程大概是什么樣子,今天,這里是不會(huì)重復(fù)去描述啦,大概放些源碼,供大家去學(xué)習(xí)。

bind 、update、unbind 都是直接觸發(fā)的,沒有什么好講的,觸發(fā)的代碼我已經(jīng)標(biāo)藍(lán)了

function updateDirectives(oldVnode, vnode) { 

    // 如果舊節(jié)點(diǎn)為空,表示這是新創(chuàng)建的
    var isCreate = oldVnode === emptyNode;  
    
    // 如果新節(jié)點(diǎn)為空,表示要銷毀  
    var isDestroy = vnode === emptyNode;   
    var key, oldDir, dir; 

    for (key in newDirs) {
        oldDir = oldDirs[key];
        dir = newDirs[key];  
        if (!oldDir) {      
            dir.def.bind(vnode.elm, dir, vnode, oldVnode, isDestroy)  
            ...inserted 處理
        } else { 
            dir.def.update(vnode.elm, dir, vnode, oldVnode, isDestroy)   
            ...componentUpdated處理  
        }
    }  
  
    ...

    ...inserted 和 componentUpdated 處理

    ...

    if (!isCreate) {        
        for (key in oldDirs) {            
            if (!newDirs[key]) {
                oldDirs[key].def.unbind(vnode.elm, 
                        dir, vnode, oldVnode, isDestroy) 
            }
        }
    }
}

重點(diǎn)我們講 inserted 和 componentUpdated 兩個(gè)鉤子就好了

1、inserted

inserted 是在DOM 插入父節(jié)點(diǎn)之后才觸發(fā)的,而 處理 inserted 是在 DOM 插入之前,所有這里不可能直接觸發(fā),只能是先保存起來,等到 節(jié)點(diǎn)被插入之后再觸發(fā)

所以,inserted 分為 保存和 執(zhí)行兩個(gè)步驟,我們按兩個(gè)步驟來看源碼

保存鉤子

下面保存 inserted 鉤子的源碼可以看成三步

1、保存進(jìn)數(shù)組 dirsWithInsert

2、組裝成函數(shù) callInsert

3、合并到 insert 鉤子

function updateDirectives(oldVnode, vnode) { 

    // 如果舊節(jié)點(diǎn)為空,表示這是新創(chuàng)建的
    var isCreate = oldVnode === emptyNode;  
    var dirsWithInsert = [];     
    var key, oldDir, dir; 

    for (key in newDirs) {

        oldDir = oldDirs[key];
        dir = newDirs[key];  

        if (!oldDir) {             
            if (dir.def && dir.def.inserted) {
                dirsWithInsert.push(dir);
            }
        } 
    }   

    if (dirsWithInsert.length) {        

        var callInsert = function() {            
            for (var i = 0; i < dirsWithInsert.length; i++) {
                callHook$1(dirsWithInsert[i], "inserted", vnode, oldVnode);
            }
        };        

        if (isCreate) {
            // 把callInsert 和本節(jié)點(diǎn)的 insert 合并起來
            vnode.data.hook["insert"] = callInsert
        } else {
            callInsert();
        }
    }   
}

執(zhí)行鉤子

通過白話版的測(cè)試我們已經(jīng)知道,inserted 鉤子是所有節(jié)點(diǎn)都插入完畢之后才觸發(fā)的,而不是插入一個(gè)節(jié)點(diǎn)就觸發(fā)一次

現(xiàn)在我們從頭探索這個(gè)執(zhí)行的流程

頁面初始化,調(diào)用 patch 處理根節(jié)點(diǎn),開始插入頁面的步驟,其中會(huì)不斷遍歷子節(jié)點(diǎn)

function patch(oldVnode, vnode, hydrating, removeOnly, parentElm, refElm) {  

    var insertedVnodeQueue=[]   

    if(需要更新){...省略...}

    // 不是更新,而是頁面初始化
    else{        

// 其中會(huì)不斷地遍歷子節(jié)點(diǎn),遞歸秭歸等....
        createElm(vnode,insertedVnodeQueue,...);
        invokeInsertHook(vnode, insertedVnodeQueue);
    }    
    return vnode.elm
}

上面的 createElm 會(huì)創(chuàng)建本節(jié)點(diǎn)以及其后代節(jié)點(diǎn),然后插入到父節(jié)點(diǎn)中

等到 createElm 執(zhí)行完,所有節(jié)點(diǎn)都已經(jīng)插入完畢了

function createElm(    
    vnode,insertedVnodeQueue,
    parentElm,refElm

){       
    vnode.elm = document.createElement(vnode.tag);    
   
    // 不斷遍歷子節(jié)點(diǎn),遞歸調(diào)用 createElm
    if (Array.isArray(children)) {        

        for (var i = 0; i < children.length; ++i) {
            createElm(children[i], insertedVnodeQueue,
                vnode.elm, null, true, children, i);
        }
    }

    // 處理本節(jié)點(diǎn)的事件,屬性等,其中包含對(duì)指令的處理
    invokeCreateHooks(vnode, insertedVnodeQueue);    

    // 插入 本DOM 到父節(jié)點(diǎn)中
    insert(parentElm, vnode.elm, refElm); 
}

此時(shí),invokeInsertHook 開始執(zhí)行,invokeInsertHook 是統(tǒng)一調(diào)用 inserted 鉤子的地方。

function invokeInsertHook(vnode, insertedVnodeQueue) {    

    for (var i = 0; i < insertedVnodeQueue.length; ++i) {
        insertedVnodeQueue[i].data.hook.insert(queue[i]);
    }
}

因?yàn)?patch 只會(huì)在 根節(jié)點(diǎn)調(diào)用一次,invokeInsertHook 只在 patch 中調(diào)用

所以 inserted 才會(huì)在所有節(jié)點(diǎn)都插入父節(jié)點(diǎn)完畢之后,統(tǒng)一觸發(fā),而不是一個(gè)個(gè)來。

收集節(jié)點(diǎn)

invokeCreateHooks 用于調(diào)用各種函數(shù)處理事件、屬性、指令等

也是在這里添加節(jié)點(diǎn)到 insertedVnodeQueue

function invokeCreateHooks(vnode, insertedVnodeQueue) {    

    // 其中會(huì)執(zhí)行 updateDirectives...
    for (var i$1 = 0; i$1 < cbs.create.length; ++i$1) {
        cbs.create[i$1](emptyNode, vnode);
    }
    i = vnode.data.hook; 

    // 保存含有 insert 函數(shù)的節(jié)點(diǎn)
    if (isDef(i) && isDef(i.insert)) {   
        insertedVnodeQueue.push(vnode);
    }
}
然后,執(zhí)行 inserted 的源碼可以看成 兩步

1、把所有含有 insert 函數(shù)的節(jié)點(diǎn),保存到 insertedVnodeQueue

2、所有節(jié)點(diǎn)插入完畢,遍歷 insertedVnodeQueue ,執(zhí)行其中節(jié)點(diǎn)的 insert 函數(shù)

注意,insert 不是 inserted 哦,只是邏輯上 insert 包含 inserted

大概的函數(shù)調(diào)用邏輯如下

2、componentUpdated

這個(gè)鉤子和 inserted 差不多,只是執(zhí)行的流程不一樣

同樣分為保存和執(zhí)行兩段源碼

保存鉤子

function updateDirectives(oldVnode, vnode) { 

    // 如果舊節(jié)點(diǎn)為空,表示這是新創(chuàng)建的
    var isCreate = oldVnode === emptyNode;  
    var dirsWithPostpatch = [];    
    var key, oldDir, dir; 

    for (key in newDirs) {

        oldDir = oldDirs[key];
        dir = newDirs[key];  
        if (!oldDir) {....} 
        else {                     
            if (dir.def && dir.def.componentUpdated) {
                dirsWithPostpatch.push(dir);
            }
        }
    }

    // 把指令componentUpdated的函數(shù) 和本節(jié)點(diǎn)的 postpatch 合并起來
    if (dirsWithPostpatch.length) {
        vnode.data.hook["postpatch"] = function() {            
            for (var i = 0; i < dirsWithPostpatch.length; i++) {
                callHook$1(dirsWithPostpatch[i], 
                    "componentUpdated", vnode, oldVnode);
            }
        });
    }  
}

執(zhí)行鉤子

componentUpdated 鉤子是更新一個(gè)節(jié)點(diǎn)就馬上執(zhí)行的

更新一個(gè)節(jié)點(diǎn)的意思是包括其內(nèi)部的子節(jié)點(diǎn)的

那內(nèi)部的流程是怎么樣的呢?

同樣,更新就是更新節(jié)點(diǎn),也會(huì)調(diào)用 patch

function patch(oldVnode, vnode) {     
    if(需要更新){  
        patchVnode(oldVnode, vnode)
    }    
    return vnode.elm  
}

function patchVnode(oldVnode, vnode){   

   // 遞歸調(diào)用 patchVnode 更新子節(jié)點(diǎn)
   updateChildren(oldVnode, vnode,.....);    

    // 執(zhí)行本節(jié)點(diǎn)的 postpatch
   if (isDef(i = data.hook) && isDef(i = i.postpatch)) {
        i(oldVnode, vnode);        
   }
}

舉個(gè)栗子走下流程

需要更新的時(shí)候,調(diào)用順序

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/105267.html

相關(guān)文章

  • Vue原理】Compile - 源碼 之 generate 節(jié)點(diǎn)數(shù)據(jù)拼接

    摘要:寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺得排版難看,請(qǐng)點(diǎn)擊下面鏈接或者拉到下面關(guān)注公眾號(hào)也可以吧原理源碼版之節(jié)點(diǎn)數(shù)據(jù)拼接上一篇我們 寫文章不容易,點(diǎn)個(gè)贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究...

    fizz 評(píng)論0 收藏0
  • Vue原理】Mixins - 源碼

    寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧 【Vue原理】Mixins - 源碼版 今天探索的是 mixins 的源碼,mixins 根據(jù)不同的選項(xiàng)類型會(huì)做不同的處理 篇幅會(huì)有些長(zhǎng),...

    gotham 評(píng)論0 收藏0
  • Vue原理】VModel - 源碼 之 表單元素綁定流程

    摘要:首先,兄弟,容我先說幾句涉及源碼很多,篇幅很長(zhǎng),我都已經(jīng)分了上下三篇了,依然這么長(zhǎng),但是其實(shí)內(nèi)容都差不多一樣,但是我還是毫無保留地給你了。 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也...

    sarva 評(píng)論0 收藏0
  • Vue原理】Compile - 源碼 之 generate 節(jié)點(diǎn)拼接

    摘要:還原的難度就在于變成模板了,因?yàn)槠渌氖裁吹仁窃獠粍?dòng)的哈哈,可是直接照抄最后鑒于本人能力有限,難免會(huì)有疏漏錯(cuò)誤的地方,請(qǐng)大家多多包涵,如果有任何描述不當(dāng)?shù)牡胤剑瑲g迎后臺(tái)聯(lián)系本人,有重謝 寫文章不容易,點(diǎn)個(gè)贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺得排版...

    macg0406 評(píng)論0 收藏0
  • Vue原理】Component - 源碼 之 創(chuàng)建組件VNode

    摘要:寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺得排版難看,請(qǐng)點(diǎn)擊下面鏈接或者拉到下面關(guān)注公眾號(hào)也可以吧原理源碼版之創(chuàng)建組件今天就要開啟我 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于...

    hover_lew 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<