事件流
定義:
1.事件流
描述的是從頁面中接收事件的順序,也可理解為事件在頁面中傳播的順序钟沛。
2.事件
就是用戶或?yàn)g覽器自身執(zhí)行的某種動(dòng)作。諸如click(點(diǎn)擊)、load(加載)、mouseover(鼠標(biāo)懸停)择浊。
3.事件處理程序
響應(yīng)某個(gè)事件的函數(shù)就叫事件處理程序(或事件偵聽器)檐蚜。
下面所示例子注冊(cè)事件的方式均使用DOM2級(jí)事件定義的事件處理程序進(jìn)行注冊(cè)充尉,兼容性的問題不涉及稠屠。'DOM2級(jí)事件'定義了兩個(gè)方法锤悄,用于處理指定和刪除事件處理程序的操作:addEventListener()
和removeEventListener()
韧骗。所有DOM節(jié)點(diǎn)中都包含這兩個(gè)方法,并且它們都接收3個(gè)參數(shù):要處理的事件名零聚、作為事件處理程序的函數(shù)和一個(gè)布爾值袍暴。當(dāng)這個(gè)布爾值為true
時(shí),表示在捕獲階段調(diào)用事件處理程序隶症;若果是false
政模,表示在冒泡階段調(diào)用事件處理程序。
事件的作用范圍討論
示例1
html
<div id="wrap">
<div id="outer">
<div id="inner"></div>
</div>
</div>
css
#wrap {
width: 200px;
height: 200px;
background: orange;
}
#outer {
position: relative;
top: 50px;
left: 50px;
width: 100px;
height: 100px;
background: #eeddff;
}
#inner {
position: relative;
top: 25px;
left:25px;
width: 50px;
height: 50px;
background: #44ddff;
}
js
var wrap = document.getElementById('wrap');
wrap.addEventListener('click',function(){
alert('789');
},false);
output
問題1:容器元素wrap注冊(cè)了事件蚂会,那么此事件的作用范圍是什么淋样?
思考1:根據(jù)上面例子,當(dāng)點(diǎn)擊橘色塊中(包括被子元素覆蓋的部分)任何一部分時(shí)胁住,都會(huì)彈出789趁猴,點(diǎn)擊橘色塊外面的部分并沒有任何反應(yīng),那么我們是不是就可以得出這這樣結(jié)論彪见,元素注冊(cè)事件的作用范圍為元素自身在頁面中所占的空間大小儡司,但是真的就是這樣嗎?下面我們做個(gè)試驗(yàn)
試驗(yàn)1:
css代碼修改如下,其他部分同上
#wrap {
width: 200px;
height: 200px;
background: orange;
}
#outer {
position: relative;
top: 50px;
left: 50px;
width: 100px;
height: 100px;
background: #eeddff;
}
/*inner中的top被修改*/
#inner {
position: relative;
top: 152px;
left:25px;
width: 50px;
height: 50px;
background: #44ddff;
}
output
結(jié)論1:當(dāng)點(diǎn)擊橘色塊外淺藍(lán)色部分的時(shí)候,同樣的也彈出了789,而淺藍(lán)色部分是嵌套在wrap元素之內(nèi)的元素,故可得出結(jié)論,當(dāng)元素注冊(cè)了事件,此事件的作用范圍為:1.元素自己所占頁面空間部分加嵌套元素所占空間范圍(若嵌套元素覆蓋在容器元素上余指,則事件的作用范圍為容器元素自身所占空間大小)
事件的執(zhí)行順序討論
問題2:根據(jù)上面的示例1
捕犬,那么這里大家可以再思考一個(gè)問題,若容器元素wrap
以及其嵌套元素outer
酵镜,inner
都注冊(cè)了click事件碉碉,根據(jù)試驗(yàn)1
得出的結(jié)論,那么嵌套在最里層的元素inner
所占頁面的空間范圍內(nèi)淮韭,一共有3個(gè)click事件都作用在其上誉裆,那么當(dāng)在inner元素的作用范圍內(nèi)點(diǎn)擊頁面時(shí),3個(gè)事件的事件處理程序執(zhí)行的順序又是如何的缸濒?
要解決上面我提出的問題2,這就涉及到了兩種處理事件流的不同的機(jī)制足丢,事件冒泡和事件捕獲
事件冒泡###
IE的事件流叫事件冒泡粱腻,即事件開始時(shí)由最具體的元素(文檔中嵌套層次最深的節(jié)點(diǎn))接收,然后逐級(jí)向上傳播到較為不具體的節(jié)點(diǎn)斩跌。
示例2
將參數(shù)設(shè)為false绍些,讓元素在冒泡階段調(diào)用事件處理程序
css,html代碼同示例1
js
var wrap = document.getElementById('wrap');
var outer = document.getElementById('outer');
var inner = document.getElementById('inner');
wrap.addEventListener('click',function(){
alert('789');
},false);
outer.addEventListener('click',function(){
alert('456');
},false);
inner.addEventListener('click',function(){
alert('123');
},false);
結(jié)論2:在冒泡階段調(diào)用事件處理程序,上面問題的結(jié)果是這樣的:當(dāng)點(diǎn)擊頁面中心淺藍(lán)色的部分時(shí)耀鸦,先是彈出123柬批,接著彈出456,最后彈出789袖订。因此當(dāng)容器元素及其嵌套元素都在冒泡階段
調(diào)用事件處理程序時(shí):事件按事件冒泡的順序執(zhí)行事件處理程序氮帐。
事件捕獲###
Netscape團(tuán)隊(duì)提出的另一種事件流叫事件捕獲,事件捕獲的思想是不太具體的節(jié)點(diǎn)應(yīng)該更早接收到事件洛姑,而最具體的節(jié)點(diǎn)應(yīng)該最后接收到事件上沐。
示例3
將參數(shù)設(shè)為true,讓元素在捕獲階段調(diào)用事件處理程序
css,html代碼同示例1
js
var wrap = document.getElementById('wrap');
var outer = document.getElementById('outer');
var inner = document.getElementById('inner');
wrap.addEventListener('click',function(){
alert('wrap');
},true);
outer.addEventListener('click',function(){
alert('outer');
},true);
inner.addEventListener('click',function(){
alert('inner');
},true);
結(jié)論3:在捕獲階段調(diào)用事件處理程序楞艾,上面問題的結(jié)果是這樣的:當(dāng)點(diǎn)擊頁面中心淺藍(lán)色的部分時(shí)参咙,先是彈出wrap,接著彈出outer硫眯,最后彈出inner蕴侧。因此當(dāng)容器元素及其嵌套元素都在捕獲階段
調(diào)用事件處理程序時(shí):事件按事件捕獲的順序執(zhí)行事件處理程序。
問題3:根據(jù)思考1两入,思考2得出的結(jié)果净宵,接著又有一個(gè)問題我認(rèn)為需要思考,當(dāng)同一個(gè)元素即在冒泡階段注冊(cè)了事件裹纳,又在捕獲階段注冊(cè)了同一事件塘娶,那么當(dāng)事件被觸發(fā)時(shí),事件的執(zhí)行順序又會(huì)是如何的痊夭?
要解決上面我提出的問題3,這就涉及到了DOM事件流
DOM事件流###
“DOM2級(jí)事件”規(guī)定的事件流包括三個(gè)階段:事件捕獲階段==>處于目標(biāo)階段==>事件冒泡階段。首先發(fā)生的是事件捕獲階段脏里,為截獲事件提供了機(jī)會(huì)她我。然后是實(shí)際的目標(biāo)接收事件。最后一個(gè)階段是冒泡階段迫横,以下圖片來自w3c
示例4
css,html代碼同示例1
js
var wrap = document.getElementById('wrap');
var outet = document.getElementById('outer');
var inner = document.getElementById('inner');
wrap.addEventListener('click',function(){
alert('789');
},false);
outer.addEventListener('click',function(){
alert('456');
},false);
inner.addEventListener('click',function(){
alert('123');
},false);
wrap.addEventListener('click',function(){
alert('wrap');
},true);
outer.addEventListener('click',function(){
alert('outer');
},true);
inner.addEventListener('click',function(){
alert('inner');
},true);
結(jié)論4:當(dāng)點(diǎn)擊頁面中心淺藍(lán)色部分的時(shí)候番舆,先從最不具體的節(jié)點(diǎn)捕獲事件,先彈出wrap,接著彈出outer矾踱。接著處于目標(biāo)階段恨狈,先彈出123,再彈出inner呛讲。緊接著禾怠,事件處于冒泡階段返奉,先彈出456,再彈出789吗氏。因此我們可以得出結(jié)論芽偏,當(dāng)容器元素及嵌套元素,即在捕獲階段
又在冒泡階段
調(diào)用事件處理程序時(shí):事件按DOM事件流的順序執(zhí)行事件處理程序弦讽,且當(dāng)事件處于目標(biāo)階段時(shí)污尉,事件調(diào)用順序決定于綁定事件的書寫順序,按上面的例子為往产,先調(diào)用冒泡階段的事件處理程序被碗,再調(diào)用捕獲階段的事件處理程序。
具體demo
如果把inner.addEventListener('click',function(){alert('inner');},true);
放到inner.addEventListener('click',function(){alert('123');},false);
前任意位置就會(huì)先執(zhí)行捕獲階段再執(zhí)行冒泡階段了仿村。所以處于目標(biāo)階段時(shí)锐朴,是先綁定的事件先發(fā)生。具體見這個(gè)demo---https://jsfiddle.net/levonlin/72tmu6vs/
[1]: /img/bVbDPh
“原文出自http://segmentfault.com/a/1190000003497939奠宜,
本文版權(quán)屬”huangxiulan(饑人谷)“所有包颁,轉(zhuǎn)載須注明出處”