問(wèn)題引入
首先看一個(gè)相關(guān)問(wèn)題秋度,點(diǎn)擊span
元素,輸出什么?
<div id="yeyeELe">
爺爺在此
<p id="parEle">
我是父元素
<span id="sonEle">我是子元素</span>
</p>
</div>
var sonEle = document.getElementById('sonEle');
var parEle = document.getElementById('parEle');
var yeyeELe = document.getElementById('yeyeELe');
yeyeELe.addEventListener('click', function () {
console.log('爺爺 冒泡');
}, false);
sonEle.addEventListener('click', function () {
console.log('子級(jí) 捕獲');
}, true);
parEle.addEventListener('click', function () {
console.log('父級(jí) 捕獲');
}, true);
yeyeELe.addEventListener('click', function () {
console.log('爺爺 捕獲');
}, true);
parEle.addEventListener('click', function () {
console.log('父級(jí) 冒泡');
}, false);
sonEle.addEventListener('click', function () {
console.log('子級(jí) 冒泡');
}, false);
想搞清楚最終的輸出順序翠勉,就不得不從事件流
說(shuō)起妖啥。
事件流
事件流需要從事件講起。
JavaScript 與 HTML 之間的交互是通過(guò)事件實(shí)現(xiàn)的对碌。
事件
就是文檔或者瀏覽器窗口中發(fā)生的一些特定的交互瞬間荆虱。可以使用偵聽器
(或處理程序)來(lái)預(yù)訂事件朽们,以便事件發(fā)生時(shí)執(zhí)行相應(yīng)代碼怀读。
而事件流描述的是從頁(yè)面接收事件的順序。
有意思的是华坦,當(dāng)時(shí)不同的開發(fā)團(tuán)隊(duì)對(duì)于事件流提出了完全相反的概念愿吹,主要分為IE事件流——冒泡不从,Netscape Communicator事件流——捕獲惜姐。
1. 事件冒泡
IE的事件流叫做事件冒泡,即時(shí)間最開始由最具體的元素接收椿息,然后逐級(jí)向上傳播到較為不具體的節(jié)點(diǎn)(文檔)歹袁。
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>事件流</title>
</head>
<body>
<div id="ele">Click Me</div>
</body>
</html>
當(dāng)你點(diǎn)擊了頁(yè)面中的 div
元素,那么這個(gè) click 事件的傳播順序如下:
- div
- body
- html
- document
也就是說(shuō)寝优,click 事件首先在元素 div
上發(fā)生条舔,然后 click 事件沿 DOM 樹向上傳播,每一級(jí)的節(jié)點(diǎn)上都會(huì)發(fā)生乏矾,直至傳播到 document 對(duì)象孟抗。如下圖:
2. 事件捕獲
Netscape Communicator 團(tuán)隊(duì)提出的事件流則為事件捕獲,事件捕獲的思想是不太具體的節(jié)點(diǎn)更早的收到事件钻心,而最具體的節(jié)點(diǎn)最后接收到事件凄硼。
事件捕獲的用意在于事件達(dá)到預(yù)定目標(biāo)之前捕獲它。
如 1.
中所述案例捷沸,則單擊 div
元素后摊沉,事件觸發(fā)順序如下:
- document
- html
- body
- div
也就是在事件捕獲過(guò)程中,document 對(duì)象首先接收到 click 事件痒给,然后事件沿 DOM 樹向下依次傳播说墨,直到傳播事件的實(shí)際目標(biāo),即 div 元素苍柏。過(guò)程如圖:
提示
雖然事件捕獲是 Netscape Communicator 唯一支持的事件流模型尼斧,但是 IE9、Safari试吁、Chrome突颊、Opera 和 Firefox 等目前也都支持這種事件流模型。由于版本兼容性問(wèn)題,事件捕獲還是較少使用律秃。當(dāng)然爬橡,建議依然是 放心使用事件冒泡,在有特殊需要時(shí)再使用事件捕獲棒动。
3. DOM 事件流
“DOM2級(jí)事件”規(guī)定的事件流包括三個(gè)階段:
- 事件捕獲階段
- 處于目標(biāo)階段
- 事件冒泡階段
首先發(fā)生的是事件捕獲糙申,為截獲事件提供了機(jī)會(huì),然后實(shí)際目標(biāo)接收到事件船惨,最后階段是冒泡階段柜裸,此階段可以對(duì)事件作出響應(yīng)。
還以上述代碼為例粱锐,單擊 div
元素后的觸發(fā)順序則是:
在 DOM 事件流中疙挺,實(shí)際目標(biāo)(div)在捕獲階段不會(huì)接收到事件,意味著在捕獲階段事件從 document 到 html 再到 body 就會(huì)停止怜浅。下一階段是處于目標(biāo)階段铐然,于是事件在 div 上發(fā)生,并在事件處理中被看成冒泡的一部分恶座。最后搀暑,冒泡階段發(fā)生,事件傳播回文檔跨琳。
回顧問(wèn)題
開篇提出的問(wèn)題自点,仿佛在此可以得出結(jié)論:
可是,當(dāng)我們將子級(jí)的冒泡和捕獲在js中位置調(diào)換后脉让,輸出的則是……子級(jí)先冒泡桂敛,再捕獲!如下:
這是什么原因呢溅潜?术唬?
下期——事件處理順序,進(jìn)一步揭曉伟恶。