摘要:這種解決方式也是相當(dāng)優(yōu)雅,值得學(xué)習(xí)源碼解析系列源碼解析一準(zhǔn)備工作源碼解析二函數(shù)源碼解析三對象源碼解析四方法源碼解析五鉤子源碼解析六模塊源碼解析七事件處理個人博客地址
事件處理
我們在使用 vue 的時候,相信你一定也會對事件的處理比較感興趣。 我們通過 @click 的時候,到底是發(fā)生了什么呢!
雖然我們用 @click綁定在模板上,不過事件嚴格綁定在 vnode 上的 。
eventlisteners 這個模塊,就是定義了一些鉤子,在 patch 的時候,能夠進行事件的綁定以及解綁。
建議閱讀這個篇章之前,先閱讀 模塊 了解簡單的模塊之后,再回來eventlisteners 模塊
首先我們看下暴露出來的內(nèi)容:
// 導(dǎo)出時間監(jiān)聽模塊,創(chuàng)建、更新、銷毀 export const eventListenersModule = { create: updateEventListeners, update: updateEventListeners, destroy: updateEventListeners } as Module;
這里我們能夠知道,在 create 、 update 、 destroy 的時候,便會觸發(fā) ,調(diào)用 updateEventListeners;
接下來我們來詳細了解下 updateEventListeners;
updateEventListenersvnode.data.on : 這個保存了一系列的綁定事件。 例如 on["click"] ,里面保存了綁定的 click 事件
vnode.listener : 作為實際綁定到元素上的回調(diào) 。 elm.addEventListener(name, listener, false);。所有的事件觸發(fā)后都是先回調(diào)到 listener ,再分發(fā)給不同的事件處理器
刪除新事件列表上不存在的事件
添加新增的事件
/** * 更新事件監(jiān)聽器 */ function updateEventListeners(oldVnode: VNode, vnode?: VNode): void { var oldOn = (oldVnode.data as VNodeData).on, oldListener = (oldVnode as any).listener, oldElm: Element = oldVnode.elm as Element, on = vnode && (vnode.data as VNodeData).on, elm: Element = (vnode && vnode.elm) as Element, name: string; // optimization for reused immutable handlers if (oldOn === on) { return; } // remove existing listeners which no longer used // 刪除多余的事件 if (oldOn && oldListener) { // if element changed or deleted we remove all existing listeners unconditionally if (!on) { // 如果新的節(jié)點沒有綁定事件,則刪除所有的事件 for (name in oldOn) { // remove listener if element was changed or existing listeners removed // 刪除監(jiān)聽器 oldElm.removeEventListener(name, oldListener, false); } } else { for (name in oldOn) { // remove listener if existing listener removed // 刪除在新事件列表上不存在的監(jiān)聽器 if (!on[name]) { oldElm.removeEventListener(name, oldListener, false); } } } } // add new listeners which has not already attached if (on) { // reuse existing listener or create new // 重用老的監(jiān)聽器 var listener = ((vnode as any).listener = (oldVnode as any).listener || createListener()); // update vnode for listener listener.vnode = vnode; // if element changed or added we add all needed listeners unconditionally if (!oldOn) { for (name in on) { // add listener if element was changed or new listeners added elm.addEventListener(name, listener, false); } } else { for (name in on) { // add listener if new listener added // 添加新增的監(jiān)聽器 if (!oldOn[name]) { elm.addEventListener(name, listener, false); } } } } }createListener
這里我們看到,事件觸發(fā)之后都會先回調(diào)到 listener ,那它是怎么回調(diào)的呢。
首先看下創(chuàng)建 listener
/** * 創(chuàng)建監(jiān)聽器 */ function createListener() { // 事件處理器 return function handler(event: Event) { handleEvent(event, (handler as any).vnode); }; }handleEvent
當(dāng)事件觸發(fā)的時候,會調(diào)用 handleEvent(event, (handler as any).vnode);
handleEvent 主要負責(zé)轉(zhuǎn)發(fā) , 去除 on 里面對應(yīng)的事件處理函數(shù),進行調(diào)用
// 處理事件 function handleEvent(event: Event, vnode: VNode) { var name = event.type, on = (vnode.data as VNodeData).on; // call event handler(s) if exists // 如果存在回調(diào)函數(shù),則調(diào)用對應(yīng)的函數(shù) if (on && on[name]) { invokeHandler(on[name], vnode, event); } }invokeHandler
執(zhí)行響應(yīng)的事件處理程序。
主要是處理幾種情況:
handler 為函數(shù)的情況
handler 為 object , 但是第一個元素為 function 的情況 ,eg: handler = [fn,arg1,arg2] ;
handler 為 object ,第一個元素不為 function 的情況 , eg: handler = [[fn1,arg1],[fn2]]
/** * 調(diào)用事件處理 */ function invokeHandler(handler: any, vnode?: VNode, event?: Event): void { if (typeof handler === "function") { // call function handler // 函數(shù)情況下直接調(diào)用 handler.call(vnode, event, vnode); } else if (typeof handler === "object") { // call handler with arguments if (typeof handler[0] === "function") { // handler為數(shù)組的情況。 eg : handler = [fn,arg1,arg2] // 第一項為函數(shù)說明后面的項為想要傳的參數(shù) // special case for single argument for performance if (handler.length === 2) { // 當(dāng)長度為2的時候,用call,優(yōu)化性能 handler[0].call(vnode, handler[1], event, vnode); } else { // 組裝參數(shù),用 apply 調(diào)用 var args = handler.slice(1); args.push(event); args.push(vnode); handler[0].apply(vnode, args); } } else { // call multiple handlers // 處理多個handler的情況 for (var i = 0; i < handler.length; i++) { invokeHandler(handler[i]); } } } }小結(jié)
這里通過 listener 來作為統(tǒng)一的事件接收, 更方便的對事件綁定以及解綁進行處理 ,在元素創(chuàng)建的時候綁定事件, 在銷毀的時候解綁事件,防止內(nèi)存泄露。 這種解決方式也是相當(dāng)優(yōu)雅,值得學(xué)習(xí) :)
snabbdom源碼解析系列snabbdom源碼解析(一) 準(zhǔn)備工作
snabbdom源碼解析(二) h函數(shù)
snabbdom源碼解析(三) vnode對象
snabbdom源碼解析(四) patch 方法
snabbdom源碼解析(五) 鉤子
snabbdom源碼解析(六) 模塊
snabbdom源碼解析(七) 事件處理
個人博客地址
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/100418.html
摘要:對象是一個對象,用來表示相應(yīng)的結(jié)構(gòu)代碼位置定義類型定義類型選擇器數(shù)據(jù),主要包括屬性樣式數(shù)據(jù)綁定時間等子節(jié)點關(guān)聯(lián)的原生節(jié)點文本唯一值,為了優(yōu)化性能定義的類型定義綁定的數(shù)據(jù)類型屬性能直接用訪問的屬性樣式類樣式數(shù)據(jù)綁定的事件鉤子創(chuàng)建對象根據(jù)傳入的 vnode 對象 vnode 是一個對象,用來表示相應(yīng)的 dom 結(jié)構(gòu) 代碼位置 :./src/vnode.ts 定義 vnode 類型 /** ...
介紹 這里是 typescript 的語法,定義了一系列的重載方法。h 函數(shù)主要根據(jù)傳進來的參數(shù),返回一個 vnode 對象 代碼 代碼位置 : ./src/h.ts /** * 根據(jù)選擇器 ,數(shù)據(jù) ,創(chuàng)建 vnode */ export function h(sel: string): VNode; export function h(sel: string, data: VNodeData...
摘要:元素從父節(jié)點刪除時觸發(fā),和略有不同,只影響到被移除節(jié)點中最頂層的節(jié)點在方法的最后調(diào)用,也就是完成后觸發(fā)源碼解析系列源碼解析一準(zhǔn)備工作源碼解析二函數(shù)源碼解析三對象源碼解析四方法源碼解析五鉤子源碼解析六模塊源碼解析七事件處理個人博客地址 文件路徑 : ./src/hooks.ts 這個文件主要是定義了 Virtual Dom 在實現(xiàn)過程中,在其執(zhí)行過程中的一系列鉤子。方便外部做一些處理 /...
摘要:閱讀源碼的時候,想了解虛擬結(jié)構(gòu)的實現(xiàn),發(fā)現(xiàn)在的地方。然而慢慢的人們發(fā)現(xiàn),在我們的代碼中布滿了一系列操作的代碼。源碼解析系列源碼解析一準(zhǔn)備工作源碼解析二函數(shù)源碼解析三對象源碼解析四方法源碼解析五鉤子源碼解析六模塊源碼解析七事件處理個人博客地址 前言 虛擬 DOM 結(jié)構(gòu)概念隨著 react 的誕生而火起來,之后 vue2.0 也加入了虛擬 DOM 的概念。 閱讀 vue 源碼的時候,想了解...
摘要:模塊在里面,定義了一系列的模塊,這些模塊定義了相應(yīng)的鉤子。主要接受兩個參數(shù),。傳送門事件模塊待續(xù)。。。源碼解析系列源碼解析一準(zhǔn)備工作源碼解析二函數(shù)源碼解析三對象源碼解析四方法源碼解析五鉤子源碼解析六模塊源碼解析七事件處理個人博客地址 模塊 在 ./src/modules 里面,定義了一系列的模塊 , 這些模塊定義了相應(yīng)的鉤子 。這些鉤子會在 patch 的不同階段觸發(fā),以完成相應(yīng)模塊的...
閱讀 9053·2021-11-18 10:02
閱讀 2602·2019-08-30 15:43
閱讀 2663·2019-08-30 13:50
閱讀 1382·2019-08-30 11:20
閱讀 2712·2019-08-29 15:03
閱讀 3633·2019-08-29 12:36
閱讀 933·2019-08-23 17:04
閱讀 624·2019-08-23 14:18