摘要:問題如果一個(gè)元素和它的祖先元素注冊了同一類型的事件函數(shù)例如點(diǎn)擊等那么當(dāng)事件發(fā)生時(shí)事件函數(shù)調(diào)用的順序是什么呢比如考慮如下嵌套的元素
問題
如果一個(gè)元素和它的祖先元素注冊了同一類型的事件函數(shù)(例如點(diǎn)擊等), 那么當(dāng)事件發(fā)生時(shí)事件函數(shù)調(diào)用的順序是什么呢?
比如, 考慮如下嵌套的元素:
----------------------------------- | outer | | ------------------------- | | |inner | | | ------------------------- | | | -----------------------------------
兩個(gè)元素都有onclick的處理函數(shù). 如果用戶點(diǎn)擊了inner, inner和outer上的事件處理函數(shù)都會(huì)被調(diào)用. 但誰先誰后呢?
兩個(gè)模型在剛剛過去的那些糟糕年代, Netscape和M$對(duì)此有不同的看法.
Netscape認(rèn)為outer上的處理函數(shù)應(yīng)該先被執(zhí)行. 這被稱作event capturing.
M$則認(rèn)為inner上的處理函數(shù)具有執(zhí)行優(yōu)先權(quán). 這被叫做event bubbling.
兩種看法針鋒相對(duì)
事件捕獲(event capturing)當(dāng)使用事件捕獲時(shí)
| | ---------------| |----------------- | outer | | | | -----------| |----------- | | |inner / | | | ------------------------- | | Event CAPTURING | -----------------------------------
outer上的事件處理器先觸發(fā), 然后是inner上的
事件冒泡(event bubbling)/ ---------------| |----------------- | outer | | | | -----------| |----------- | | |inner | | | | | ------------------------- | | Event BUBBLING | -----------------------------------
與事件捕獲相反, 當(dāng)使用事件冒泡時(shí), inner上的事件處理器先被觸發(fā), 其后是outer上面的
W3C 模型W3C標(biāo)準(zhǔn)則取其折中方案. W3C事件模型中發(fā)生的任何事件, 先(從其祖先元素window)開始一路向下捕獲, 直到達(dá)到目標(biāo)元素, 其后再次從目標(biāo)元素開始冒泡.
1. 先從上往下捕獲 | | | / -----------------| |--| |----------------- | outer | | | | | | -------------| |--| |----------- | | | inner / | | | | | | | | | | | 2. 到達(dá)目標(biāo)元素后從下往上冒泡| | | -------------------------------- | | W3C event model | ------------------------------------------
而你作為開發(fā)者, 可以決定事件處理器是注冊在捕獲或者是冒泡階段. 如果addEventListener的最后一個(gè)參數(shù)是true, 那么處理函數(shù)將在捕獲階段被觸發(fā); 否則(false), 會(huì)在冒泡階段被觸發(fā).
例如如下的代碼:
var selector = document.querySelector.bind(document); selector("div.outer").addEventListener("click", (e) => { selector("p:first-of-type").textContent += "outer clicked! " }, true) selector("div.inner").addEventListener("click", (e) => { selector("p:first-of-type").textContent += "inner clicked! " }, false) document.addEventListener("click", (e) => { selector("p:first-of-type").textContent += "document clicked! " }, true)
當(dāng)點(diǎn)擊inner元素時(shí), 如下事情發(fā)生了:
點(diǎn)擊事件開始于捕獲階段. 在此階段, 瀏覽器會(huì)在inner的所有祖先元素上查找點(diǎn)擊事件處理函數(shù)(從window開始).
結(jié)果找到了2個(gè), 分別在document和outer上面, 而且這兩個(gè)事件處理函數(shù)的useCapture選項(xiàng)為true, 說明它們是被注冊在捕獲階段的. 于是, document和outer的點(diǎn)擊處理函數(shù)被執(zhí)行了.
繼續(xù)向下尋找, 直到達(dá)到inner元素本身. 捕獲階段就此結(jié)束. 此時(shí)進(jìn)入冒泡階段, inner上的事件處理器得到執(zhí)行.
事件命中目標(biāo)元素后開始向上冒泡, 一路查找是否有注冊了冒泡階段的祖先元素上的事件處理器. 由于沒有找到, 因此什么也沒發(fā)生.
最后的結(jié)果是:
如果我們把祖先元素的事件處理器注冊在冒泡階段的話(addEventListener的useCapture選項(xiàng)為false):
var selector = document.querySelector.bind(document); selector("div.outer").addEventListener("click", (e) => { selector("p:first-of-type").textContent += "outer clicked! " console.log(e); }, false) selector("div.inner").addEventListener("click", (e) => { selector("p:first-of-type").textContent += "inner clicked! " console.log(e); }, false) document.addEventListener("click", (e) => { selector("p:first-of-type").textContent += "document clicked! " }, false)
結(jié)果則是:
傳統(tǒng)模型element.onclick = function(){}
將被注冊在冒泡階段.
事件冒泡的應(yīng)用例如: 當(dāng)點(diǎn)擊時(shí)的默認(rèn)函數(shù)
如果在document上注冊一個(gè)點(diǎn)擊函數(shù):
document.addEventlistener("click", (e) => {}, false)
那么任何元素上的點(diǎn)擊事件最后都會(huì)冒泡到這個(gè)事件處理器上并觸發(fā)函數(shù) - 除非前面的事件處理函數(shù)阻止了冒泡(e.stopPropogation(), 在這種情況下事件不會(huì)繼續(xù)向上冒泡)
注意: e.stopPropagation()只能阻止事件在冒泡階段的向上傳播. 如果被點(diǎn)擊元素的祖先元素有注冊在捕獲階段的事件處理器:
ancestorElem.addEventListner("click", (e) => { // do something... }, true)
那么該祖先元素上的事件處理器照樣會(huì)在捕獲階段被觸發(fā).
因此, 你可以在document上設(shè)置這么一個(gè)處理函數(shù), 當(dāng)頁面上的任何元素被點(diǎn)擊時(shí), 這個(gè)處理函數(shù)就被會(huì)觸發(fā). 一個(gè)實(shí)用的例子就是下拉菜單: 當(dāng)點(diǎn)擊文檔上除下拉菜單本身時(shí)任意一處時(shí), 下拉菜單會(huì)被隱藏.
在冒泡或者捕獲階段, e.currentTarget指向當(dāng)前事件處理函數(shù)所附著的元素. 你也可以用事件處理函數(shù)內(nèi)的this取而代之.
M$模型的麻煩在M$模型中, 沒有對(duì)e.currentTarget的支持, 更糟糕的是, this也不指向當(dāng)前的HTML元素.
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/91135.html
摘要:問題如果一個(gè)元素和它的祖先元素注冊了同一類型的事件函數(shù)例如點(diǎn)擊等那么當(dāng)事件發(fā)生時(shí)事件函數(shù)調(diào)用的順序是什么呢比如考慮如下嵌套的元素 問題 如果一個(gè)元素和它的祖先元素注冊了同一類型的事件函數(shù)(例如點(diǎn)擊等), 那么當(dāng)事件發(fā)生時(shí)事件函數(shù)調(diào)用的順序是什么呢? 比如, 考慮如下嵌套的元素: ----------------------------------- | outer ...
摘要:事件冒泡與事件捕獲事件冒泡和事件捕獲分別由微軟和網(wǎng)景公司提出,這兩個(gè)概念都是為了解決頁面中事件流事件發(fā)生順序的問題。事件冒泡微軟提出了名為事件冒泡的事件流。 事件冒泡與事件捕獲 事件冒泡和事件捕獲分別由微軟和網(wǎng)景公司提出,這兩個(gè)概念都是為了解決頁面中事件流(事件發(fā)生順序)的問題??紤]下面這段代碼,就不寫html->head,body之類的代碼了,自行腦補(bǔ) Click me! ...
摘要:在之前是只支持事件冒泡,包括之后和目前主流的瀏覽器都同時(shí)支持兩種事件。中可以用來取消事件冒泡。 剛接觸 JS 的那個(gè)時(shí)候,啥也不懂,只想著如何利用 Google、百度到的函數(shù)來解決實(shí)際的問題,不會(huì)想到去一探究竟。 漸漸的,對(duì) JS 的語言的不斷深入,有機(jī)會(huì)去了解一些原理性東西。最近在看 JQuery 源碼,感觸很多,總想著用原生的 JS 去實(shí)現(xiàn)自己的一個(gè) JQuery 庫。說實(shí)在的,J...
摘要:面試題的基本數(shù)據(jù)類型和引用數(shù)據(jù)類型基本數(shù)據(jù)類型引用數(shù)據(jù)類型和有何區(qū)別表示一個(gè)對(duì)象被定義了,值為空值表示不存在這個(gè)值。 js面試題 JS的基本數(shù)據(jù)類型和引用數(shù)據(jù)類型 基本數(shù)據(jù)類型:undefined、null、boolean、number、string、symbol引用數(shù)據(jù)類型:object、array、function null 和 undefined 有何區(qū)別? null 表示一個(gè)對(duì)...
摘要:事件冒泡與事件捕獲事件冒泡和事件捕獲分別由微軟和網(wǎng)景公司提出,這兩個(gè)概念都是為了解決頁面中事件流事件發(fā)生順序的問題。如下假設(shè)三層都有事件監(jiān)聽,這時(shí)我們點(diǎn)擊的小的藍(lán)方框,事件執(zhí)行的順序是怎么樣的呢紅黃藍(lán)事件冒泡微軟提出了名為事件冒泡的事件流。 事件冒泡與事件捕獲 事件冒泡和事件捕獲分別由微軟和網(wǎng)景公司提出,這兩個(gè)概念都是為了解決頁面中事件流(事件發(fā)生順序)的問題。 如下:假設(shè)三層div都...
閱讀 2894·2021-11-24 09:38
閱讀 3518·2021-11-23 09:51
閱讀 987·2021-09-09 11:52
閱讀 4039·2021-08-11 11:18
閱讀 1115·2019-08-30 14:05
閱讀 3235·2019-08-30 11:23
閱讀 1773·2019-08-29 17:02
閱讀 1132·2019-08-26 13:49