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