【Vue原理】Event - 源碼版 之 綁定標籤DOM事件

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

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

【Vue原理】Event - 源碼版 之 綁定標籤DOM事件 dom

這裏的綁定DOM事件,是指綁定原生標籤的DOM 事件函數

由於組件也是能夠綁定原生DOM事件的,不過並非在原生標籤上綁定,而是直接在組件上綁定的,這部份內容會其餘文章說明學習

或者你能夠看看白話版先了解下Eventspa

【Vue原理】Event - 白話版 prototype


怎麼解析

因爲解析不是本內容的重點,因此在這裏就不談怎麼解析的了,只說一個結果就行了3d

如今有這麼一個模板code

公衆號

模板被解析成這樣的渲染函數blog

公衆號

渲染函數執行以後,獲得這樣的 VNode遞歸

你能夠看到,事件被存放到了 vnode.data 上

公衆號

Vnode 有疑惑的能夠看介裏

【Vue原理】VNode - 源碼版


怎麼綁定

既然模板已經被解析完成了,下一步就是開始綁定了

好的,繼續來走流程

在 template 解析獲得 Vnode 以後,下面就會進行DOM生成掛載

而綁定事件,就發生在開始掛載,建立DOM 以後 的階段

掛載時從 Vue.prototype._update 這個函數開始的

掛載的流程,能夠看看這篇文章

從模板到DOM的簡要流程

一、開始掛載

VNode建立完畢,傳入 Vue.prototype._update 這個方法中,進行比對新舊VNode

而後生成DOM掛載頁面

其中須要生成DOM,調用的方法是 createElm

二、建立DOM

建立DOM,在Vue 中調用的是 createElm 這個方法

看過之前的文章的,都知道這個函數的做用是

根據 vnode 生成DOM,而且進行掛載

而在 createElm 中,會調用一個函數去 處理模板上相關的數據

好比處理屬性,類名,style 之類的,其中DOM事件也是在這裏處理的

這個函數就是 invokeCreateHooks,繼續往下看

function createElm(vnode) {    

    // ....處理組件

    // ....生成標籤對應dom

    // ....遞歸遍歷子節點

    invokeCreateHooks(vnode);    

    // ....插入DOM 節點

}

三、處理數據

上面源碼中出現的 invokeCreateHooks 這個方法是用來處理數據的

每種數據(style,class等),都有一個專門的函數去進行處理

而 invokeCreateHooks,就是負責執行每種數據的處理函數,很簡單,就是一個單純遍歷執行的過程

其中就包括處理 DOM 事件的函數,即是 updateDOMListeners

function invokeCreateHooks(

    vnode

) {    

    /**

     * 執行的函數包括下面這麼多
     * cbs = [
     *  create:[
     *      updateAttrs, updateClass,
     *      updateDOMListeners, updateDOMProps,
     *      updateStyle, create, updateDirectives
     *  ]
     * ]

     **/
    for (var b = 0; b < cbs.create.length; ++b) {        

        // 其中會調用 updateDOMListeners

        // emptyNode 是空節點,由於這裏是初始化纔會調用的

              // 因此舊節點是空節點

        cbs.create[b](emptyNode, vnode);
    }
    ....

}

下面看下 處理DOM 事件的函數

四、綁定DOM事件

簡化的源碼,看起來順眼多了,主要邏輯一清二楚,主要就是綁定事件和解綁事件,你看下嘍,挺簡單的

function updateDOMListeners(oldVnode, vnode) {  

    var on = vnode.data.on || {};    

    var oldOn = oldVnode.data.on || {};

    var target = vnode.elm;
    

    // 遍歷綁定的事件

    for (name in on) {

        newHandler = on[name];

        oldHandler = oldOn[name];   
     
        // 沒有舊事件,就直接添加新事件

        if (typeof oldHandler === "undefined") {
          
            // 給事件回調包裝一層

            target.addEventListener(name, function(){

                on[name]() // 執行保存在vnode的事件

            });

        }        
        // 新事件和舊事件不同,替換舊事件

        else if (newHandler !== oldHandler) {
            on[name] = newHandler;
        }
    }   

    // 移除舊事件

    for (name in oldOn) {   

        // 舊事件不存在新事件中,直接移除  

        if (typeof on[name] === "undefined") {

            target.removeEventListener(
                name, oldOn[name]
            );

        }
    }

}

看看綁定函數和 移除函數,就只是簡單使用 addEventListener 和 removeEventListener,我沒看以前還覺得 Vue 寫了不少兼容,沒想到就是這麼簡單完成這個功能

有點驚訝,反正簡單也好吧,哈哈哈,簡單看着就是蘇胡啊~~

綁定邏輯很簡單

一、新舊事件相同,替換舊事件

二、新事件不存在舊事件中,綁定新事件

三、舊事件不存在新事件中,解綁舊事件

其中會給回調事件函數包裝一層函數,而後在內部執行綁定的回調,包裝一層的緣由是,爲了在回調中作點其餘操做(好比宏微任務的處理等,這裏爲了簡單去掉了)

而且舊事件回調改了的時候,就更加方便了,不用解綁再綁定,直接把執行的事件回調 on[name]替換掉就ok了

好的,原生標籤綁定DOM 事件到這裏就完成了,但願對你們有所幫助

公衆號

相關文章
相關標籤/搜索