眾所周知(假裝是這樣的),在IE(支持冒泡)和NetScape(支持捕獲)兩者打完之后尼摹,W3C給了個(gè)折中的結(jié)果“先捕獲再冒泡,就這么定了”。
所以事件的觸發(fā)會(huì)經(jīng)歷三個(gè)階段:
- 事件捕獲階段(
e.eventPhase==1
)從document開(kāi)始石蔗,一層層往里面捕獲,遇到捕獲事件立即觸發(fā)執(zhí)行畅形; - 處于目標(biāo)階段(
e.eventPhase==2
)到達(dá)事件位置养距,觸發(fā)事件; - 事件冒泡階段(
e.eventPhase==3
)從事件位置一層層往外冒泡日熬,直到返回到document棍厌,遇到冒泡事件立即觸發(fā)執(zhí)行。
obj.addEventListener(“click”,func, true);
//捕獲方式
obj.addEventListener(“click”,func, false);
//冒泡方式
再來(lái)看下event.stopPropagation()到底是個(gè)什么鬼竖席。
說(shuō)是阻止冒泡耘纱,然而并不嚴(yán)謹(jǐn)昂~,因?yàn)樗恢皇亲柚姑芭荼霞觯€阻止事件的繼續(xù)捕獲束析,說(shuō)白了就是不讓事件繼續(xù)傳播了呢。當(dāng)然不傳播不代表當(dāng)前節(jié)點(diǎn)的其他事件也不執(zhí)行憎亚,如果想要接下來(lái)綁定在該節(jié)點(diǎn)的其他事件也阻止的話员寇,就要用event.stopImmediatePropagation()
來(lái)阻止(這么多額,真是煩躁)第美。
還有更煩躁的蝶锋,捕獲和冒泡的順序是嚴(yán)格的,所以事件之間的執(zhí)行順序和事件注冊(cè)的順序是沒(méi)關(guān)系的什往。
但是牲览!如果一個(gè)節(jié)點(diǎn)既綁定了捕獲事件,又綁定了冒泡事件,并且都處于eventPhase==2 && e.target==e.currentTarget
的階段第献,那么就和注冊(cè)順序保持一致贡必。這個(gè)時(shí)候就要看事件發(fā)生的位置和階段了,不要忽略不要忽略不要忽略庸毫,點(diǎn)擊一個(gè)div的時(shí)候最先進(jìn)行的處理是判斷e.target
和e.currentTarget
是否相等仔拟。
比如我按照這樣的順序?qū)懥舜a:
<div id="p">
parent
<p id="c">child</p>
</div>
<script type="text/javascript">
window.alert = function(msg){
console.log(msg);
}
p.addEventListener('click', function (e) {
alert('父節(jié)點(diǎn)捕獲:' + e.eventPhase);
alert('父節(jié)點(diǎn)捕獲:' + e.currentTarget);
alert('父節(jié)點(diǎn)捕獲:' + (e.currentTarget == e.target));
alert('父節(jié)點(diǎn)捕獲');
}, true);
p.addEventListener('click', function (e) {
alert('父節(jié)點(diǎn)冒泡:' + e.eventPhase);
alert('父節(jié)點(diǎn)冒泡:' + e.currentTarget);
alert('父節(jié)點(diǎn)冒泡:' + (e.currentTarget == e.target));
alert('父節(jié)點(diǎn)冒泡');
}, false);
c.addEventListener('click', function (e) {
alert('子節(jié)點(diǎn)冒泡:' + e.eventPhase);
alert('子節(jié)點(diǎn)冒泡:' + e.currentTarget);
alert('子節(jié)點(diǎn)冒泡:' + (e.currentTarget == e.target));
alert('子節(jié)點(diǎn)冒泡');
}, false);
c.addEventListener('click', function (e) {
alert('子節(jié)點(diǎn)捕獲:' + e.eventPhase);
alert('子節(jié)點(diǎn)捕獲:' + e.currentTarget);
alert('子節(jié)點(diǎn)捕獲:' + (e.currentTarget == e.target));
alert('子節(jié)點(diǎn)捕獲');
}, true);
</script>
我點(diǎn)擊child的時(shí)候,控制臺(tái)輸出的是什么呢飒赃。利花。。
所以點(diǎn)擊child的時(shí)候父元素不處于phase2载佳,所以父元素身上的事件就是最先捕獲炒事,最后冒泡。但對(duì)于child元素來(lái)說(shuō)蔫慧,event的currentTarget就是child本身挠乳,而我先注冊(cè)了冒泡后注冊(cè)的捕獲,所以child就得乖乖先冒泡后捕獲姑躲。睡扬。。
是不是覺(jué)得很暈的說(shuō)黍析。卖怜。。
further more 瀏覽器寶寶為我們提供了一個(gè)獲取節(jié)點(diǎn)事件數(shù)的方法(如論是什么方式的綁定阐枣,addEventListener
也算马靠,onclick=‘func()’
也算):getEventListeners(node)
,返回一個(gè)事件數(shù)組蔼两。
如果注冊(cè)事件類(lèi)型不一樣虑粥,返回不同數(shù)組:
比如這里有三個(gè)click事件和一個(gè)
mousedown
事件。