眾所周知(假裝是這樣的),在IE(支持冒泡)和NetScape(支持捕獲)兩者打完之后,W3C給了個折中的結果“先捕獲再冒泡,就這么定了”。
所以事件的觸發會經歷三個階段:
- 事件捕獲階段(
e.eventPhase==1
)從document開始,一層層往里面捕獲,遇到捕獲事件立即觸發執行; - 處于目標階段(
e.eventPhase==2
)到達事件位置,觸發事件; - 事件冒泡階段(
e.eventPhase==3
)從事件位置一層層往外冒泡,直到返回到document,遇到冒泡事件立即觸發執行。
obj.addEventListener(“click”,func, true);
//捕獲方式
obj.addEventListener(“click”,func, false);
//冒泡方式
再來看下event.stopPropagation()到底是個什么鬼。
說是阻止冒泡,然而并不嚴謹昂~,因為它不只是阻止冒泡,還阻止事件的繼續捕獲,說白了就是不讓事件繼續傳播了呢。當然不傳播不代表當前節點的其他事件也不執行,如果想要接下來綁定在該節點的其他事件也阻止的話,就要用event.stopImmediatePropagation()
來阻止(這么多額,真是煩躁)。
還有更煩躁的,捕獲和冒泡的順序是嚴格的,所以事件之間的執行順序和事件注冊的順序是沒關系的。
但是!如果一個節點既綁定了捕獲事件,又綁定了冒泡事件,并且都處于eventPhase==2 && e.target==e.currentTarget
的階段,那么就和注冊順序保持一致。這個時候就要看事件發生的位置和階段了,不要忽略不要忽略不要忽略,點擊一個div的時候最先進行的處理是判斷e.target
和e.currentTarget
是否相等。
比如我按照這樣的順序寫了代碼:
<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('父節點捕獲:' + e.eventPhase);
alert('父節點捕獲:' + e.currentTarget);
alert('父節點捕獲:' + (e.currentTarget == e.target));
alert('父節點捕獲');
}, true);
p.addEventListener('click', function (e) {
alert('父節點冒泡:' + e.eventPhase);
alert('父節點冒泡:' + e.currentTarget);
alert('父節點冒泡:' + (e.currentTarget == e.target));
alert('父節點冒泡');
}, false);
c.addEventListener('click', function (e) {
alert('子節點冒泡:' + e.eventPhase);
alert('子節點冒泡:' + e.currentTarget);
alert('子節點冒泡:' + (e.currentTarget == e.target));
alert('子節點冒泡');
}, false);
c.addEventListener('click', function (e) {
alert('子節點捕獲:' + e.eventPhase);
alert('子節點捕獲:' + e.currentTarget);
alert('子節點捕獲:' + (e.currentTarget == e.target));
alert('子節點捕獲');
}, true);
</script>
我點擊child的時候,控制臺輸出的是什么呢。。。
所以點擊child的時候父元素不處于phase2,所以父元素身上的事件就是最先捕獲,最后冒泡。但對于child元素來說,event的currentTarget就是child本身,而我先注冊了冒泡后注冊的捕獲,所以child就得乖乖先冒泡后捕獲。。。
是不是覺得很暈的說。。。
further more 瀏覽器寶寶為我們提供了一個獲取節點事件數的方法(如論是什么方式的綁定,addEventListener
也算,onclick=‘func()’
也算):getEventListeners(node)
,返回一個事件數組。
如果注冊事件類型不一樣,返回不同數組:
比如這里有三個click事件和一個
mousedown
事件。