摘要:事件流與事件委托事件,即文檔或瀏覽器中發(fā)生的一些特定交互的瞬間,我們可以利用事件監(jiān)聽來預(yù)定事件,當事件發(fā)生的時候執(zhí)行相應(yīng)的處理程序。本文主要討論事件流的三個階段,及利用事件委托機制進行性能優(yōu)化。
事件流與事件委托
DOM事件流事件,即文檔或瀏覽器中發(fā)生的一些特定交互的瞬間,我們可以利用事件監(jiān)聽來預(yù)定事件,當事件發(fā)生的時候執(zhí)行相應(yīng)的處理程序。當事件發(fā)生在某個DOM節(jié)點上時,事件在DOM結(jié)構(gòu)中進行一級一級的傳遞,這便形成了“流”,事件流便描述了從頁面中接收事件的順序。本文主要討論事件流的三個階段,及利用事件委托機制進行性能優(yōu)化。
關(guān)于事件流的理解,《JS高程三》中有個形象的比喻:
可以想象畫在一張紙上的一組同心圓,如果你把手指放在圓心上,那么你的手指指向的其實不是一個圓,而是紙上所有的圓。...>換句話說,在單擊按鈕的同時,你也單擊了按鈕的容器元素,甚至也單擊了整個頁面。
————《JavaScript高級程序設(shè)計(第三版)》page 345
DOM2級事件中規(guī)定事件流包含3個階段:
捕獲階段
處于目標階段
冒泡階段
首先發(fā)生的是事件捕獲階段,此時事件還沒有傳遞到目標節(jié)點對象上,所以我們就有機會在這個階段進行事件的截。然后是目標節(jié)點接收到事件,最后是事件冒泡階段,可以在這個階段對事件做出處理和響應(yīng)。
我們先定義一段簡單的html結(jié)構(gòu):
事件捕獲階段
在事件捕獲階段中,先由不具體的節(jié)點(即上層節(jié)點)接收到事件,然后一級一級往下傳遞,直到最具體的目標節(jié)點接收到事件。
在DOM2級事件規(guī)范中,要求事件從document對象開始傳遞,但是諸如Chrome,F(xiàn)irefox等主流瀏覽器卻是從window開始傳遞的。
addEventListener方法的第三個參數(shù)是一個布爾值(可選),指定事件處理程序是否在捕獲或冒泡階段執(zhí)行。 當為true時,則事件處理程序?qū)⒃诓东@階段執(zhí)行。
誤區(qū):無論addEventListener的第三個參數(shù)是否為true,三個階段都會走一遍,這里的第三個參數(shù),指的是處理程序?qū)诓东@或者冒泡階段執(zhí)行,好比是你想買菜,你可以在上班路上,或者下班路上完成買菜,但無論什么時候買菜,你都要把這兩段路程走完。
document.querySelector("#btn").addEventListener("click", function () { console.log("btn was clicked"); },true); document.querySelector("body").addEventListener("click", function () { console.log("body was clicked"); },true); document.querySelector(".box").addEventListener("click", function () { console.log("box was clicked"); },true); document.addEventListener("click", function () { console.log("document was clicked"); },true); window.addEventListener("click", function () { console.log("window was clicked"); },true);
點擊click me按鈕后,控制臺依次打印出執(zhí)行結(jié)果:
window was clicked document was clicked body was clicked box was clikced btn was clicked
很明顯可以看出,在捕獲階段,事件由window對象開始,一級一級地向下傳遞,直到傳遞到最具體的button對象上。
事件冒泡階段事件冒泡階段與捕獲階段恰好相反,冒泡階段是從最具體的目標對象開始,一層一層地向上傳遞,直到window對象。
addEventListener方法默認就是從冒泡階段執(zhí)行事件處理程序。
document.querySelector("#btn").addEventListener("click", function () { console.log("btn was clicked"); }); document.querySelector("body").addEventListener("click", function () { console.log("body was clicked"); }); document.querySelector(".box").addEventListener("click", function () { console.log("box was clicked"); }); document.addEventListener("click", function () { console.log("document was clicked"); }); window.addEventListener("click", function () { console.log("window was clicked"); });
點擊click me按鈕后,控制臺依次打印出執(zhí)行結(jié)果:
btn was clicked box was clikced body was clicked document was clicked window was clicked
上述過程示意圖:
我們可以使用event.stopPropagation()方法阻止事件冒泡過程,以防止事件冒泡而帶來不必要的錯誤和困擾。
示例:
document.querySelector("#btn").addEventListener("click", function (event) { console.log("btn was clicked"); event.stopPropagation(); }); document.querySelector("body").addEventListener("click", function () { console.log("body was clicked"); }); document.querySelector(".box").addEventListener("click", function () { console.log("box was clicked"); }); document.addEventListener("click", function () { console.log("document was clicked"); }); window.addEventListener("click", function () { console.log("window was clicked"); });
點擊click me按鈕后,控制臺打印出執(zhí)行結(jié)果顯示,事件沒有再向上冒泡傳遞給其他節(jié)點對象:
btn was clicked事件委托
每個函數(shù)都是對象,都會占用內(nèi)存,所以當我們的頁面中所包含的事件數(shù)量較多時,如果給每個節(jié)點綁定一個事件,加上事件處理程序,就會造成性能很差。還有一個問題是,某個元素節(jié)點是后來通過JavaScript動態(tài)添加進頁面中的,這時候我們?nèi)绻崆皩λM行綁定,但此時該元素并不存在,所以會綁定事件會失敗。解決上述兩個問題的一個常用方案,就是使用事件委托。
舉例來說:
document.querySelector(".box").addEventListener(function (event) { switch (event.target.id) { case "btn": console.log("btn was clicked"); break; case "btn-2": console.log("btn-2 was clicked"); break; default: console.log("box was clicked"); break; } }); $(".box").append("");
簡單說,事件委托就是把本來該自己接收的事件委托給自己的上級(父級,祖父級等等)的某個節(jié)點,讓自己的“長輩們”幫忙盯著,一旦有事件觸發(fā),再由“長輩們”告訴自己:“喂,孫子,有人找你~~”。
恩,差不多就是這么個意思,可憐天下父母心。
水平有限,歡迎大家不吝指正。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/80503.html
摘要:前言之前不太明白事件委托??戳诉@個帖子,跟著代碼操作了一遍,終于明白了事件委托。推薦理由一步一步,漸進式分析來說明事件委托。為簽收快遞,有兩種辦法一是三個人在公司門口等快遞二是委托給前臺代為簽收。 前言:之前不太明白事件委托。 看了這個帖子,跟著代碼操作了一遍,終于明白了事件委托。所以轉(zhuǎn)載。 推薦理由:一步一步,漸進式分析來說明事件委托。 什么叫事件委托呢?它還有一個名字叫事件代理 ...
摘要:事件委托事件代理高級程序設(shè)計上解釋事件委托就是利用事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件。事件委托原理事件委托是利用事件的冒泡原理來實現(xiàn)的,事件冒泡就是事件從最深的節(jié)點開始,然后逐級向上傳播事件。 js 事件委托 事件代理 JavaScript高級程序設(shè)計上解釋:事件委托就是利用事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件。 通過例子類比: 有...
摘要:見下圖更直觀在事件流中,事件的目標在捕獲階段不會接受到事件,這意味著在捕獲階段,事件從到后就停止了。下一個階段是目標階段,于是事件在上發(fā)生,并在事件處理中被看成是冒泡階段的一部分,然后,冒泡階段發(fā)生,事件又傳回。 CONTENTS DOM事件流 事件冒泡 阻止冒泡 事件捕獲 事件委托 DOM事件流 1.什么是事件流? 事件流所描述的是從頁面中接受事件的順序 2.DOM事件流的三個階...
摘要:見下圖更直觀在事件流中,事件的目標在捕獲階段不會接受到事件,這意味著在捕獲階段,事件從到后就停止了。下一個階段是目標階段,于是事件在上發(fā)生,并在事件處理中被看成是冒泡階段的一部分,然后,冒泡階段發(fā)生,事件又傳回。 CONTENTS DOM事件流 事件冒泡 阻止冒泡 事件捕獲 事件委托 DOM事件流 1.什么是事件流? 事件流所描述的是從頁面中接受事件的順序 2.DOM事件流的三個階...
摘要:見下圖更直觀在事件流中,事件的目標在捕獲階段不會接受到事件,這意味著在捕獲階段,事件從到后就停止了。下一個階段是目標階段,于是事件在上發(fā)生,并在事件處理中被看成是冒泡階段的一部分,然后,冒泡階段發(fā)生,事件又傳回。 CONTENTS DOM事件流 事件冒泡 阻止冒泡 事件捕獲 事件委托 DOM事件流 1.什么是事件流? 事件流所描述的是從頁面中接受事件的順序 2.DOM事件流的三個階...
閱讀 1644·2021-10-09 09:44
閱讀 2805·2021-10-08 10:04
閱讀 2475·2021-09-26 09:55
閱讀 3854·2021-09-22 10:02
閱讀 3315·2019-08-29 17:08
閱讀 1075·2019-08-29 15:08
閱讀 2963·2019-08-26 13:52
閱讀 3279·2019-08-26 13:34