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

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

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

【Vue原理】Event - 源碼版 之 綁定組件DOM事件 函數

上一篇已經說了綁定正常標籤的原生事件,今天是組件的原生事件,二者最終做用是同樣的,可是過程有少少不一樣學習

最近更新快是由於文章早就寫完了,只是定時發而已哈哈spa

官網已經說明,要是想在組件上綁定原生事件,須要加上 native 修飾符prototype

公衆號


怎麼解析

這裏同樣,解析不是本文重點,只給出結果3d

如今,我有這麼一個模板code

公衆號

被解析成這樣的渲染函數
公衆號
而後生成這樣的 VNodeblog

公衆號

這個VNode 是 外殼vnode,咱們已經知道外殼 vnode 是保存 父子組件關聯的數據事件

好比 props,事件之類的rem

因此你在組件上綁定的原生事件,天然而然就是保存在 外殼vnode 上啦

綁定在 外殼vnode 的數據,是要在解析組件內部模板時,纔會拿出來使用的

而後!

你能夠看到,nativeOn 和 on 都保存有事件

其實解析的時候,只保存在了 nativeOn,on 是 後面 從 nativeOn 直接賦值過去的

打印組件實例能夠看到

公衆號

耶!Vnode 相關又能夠看這篇哦

【Vue原理】VNode - 源碼版


怎麼綁定

綁定的流程千篇一概,可是有少少出入

能夠參考我這篇,綁定原生事件的文章

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

相同的地方簡單提一下,不一樣的地方再仔細說

一、綁定事件發生在 掛載DOM的階段,從 Vue.prototype._update 開始

二、_update 其中會調用 createElm 來生成DOM

三、createElm 碰到組件,會轉去解析組件

function createElm(vnode) {   

    if (

        createComponent(vnode, parentElm, refElm)

    ) {
        return
    }

    ....普通標籤的DOM生成和掛載

}

進入到 createComponent

function createComponent(vnode, parentElm, refElm) {    

    var i = vnode.data;    

    if (isDef(i)) {        

        // ... 建立組件實例

        if (若是組件實例已經建立成功) {

            initComponent(vnode);            

            return true

        }
    }
}

沒啥好說的,繼續轉到了另外一個函數

function initComponent(vnode) {
    invokeCreateHooks(vnode);
}

而後這個函數仍是爲了調用 invokeCreateHooks 這個函數

invokeCreateHooks 上篇文章也出現過,做用是調用各類數據處理函數,好比處理 prop,class 等,其中還包括處理事件的函數 updateDOMListeners

updateDOMListeners 這個函數在上一篇文章中已經說過啦,你們能夠看一下
Event - 源碼版 之 綁定標籤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]
            );

        }
    }
}

公衆號

相關文章
相關標籤/搜索