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