dom事件流

事件捕獲(event capturing)

當使用事件捕獲時javascript

| | ---------------| |----------------- | outer | | | | -----------| |----------- | | |inner \ / | | | ------------------------- | | Event CAPTURING | -----------------------------------

outer上的事件處理器先觸發, 而後是inner上的java

事件冒泡(event bubbling)

/ \
---------------| |----------------- | outer | | | | -----------| |----------- | | |inner | | | | | ------------------------- | | Event BUBBLING | -----------------------------------

與事件捕獲相反, 當使用事件冒泡時, inner上的事件處理器先被觸發, 其後是outer上面的。node

通常來講事件冒泡機制,用的更多一些,因此在IE8以及以前,IE只支持事件冒泡。IE9+/FF/Chrome這2種模型都支持,能夠經過addEventListener((type, listener, useCapture)的useCapture來設定,useCapture=false表明着事件冒泡,useCapture=true表明着採用事件捕獲。默認是false,即事件冒泡。app

DOM事件流函數

DOM事件流:將事件分爲三個階段:捕獲階段、目標階段、冒泡階段。先調用捕獲階段的處理函數,其次調用目標階段的處理函數,最後調用冒泡階段的處理函數。ui

咱們在outC上觸發onclick事件(這個是目標對象),若是咱們在outC上同時綁定捕獲階段/冒泡階段事件處理函數會怎麼樣呢?this

<script>

 window.onload = function(){
 var outA = document.getElementById("outA"); 
 var outB = document.getElementById("outB"); 
 var outC = document.getElementById("outC"); 
 
 // 目標(自身觸發事件,是冒泡仍是捕獲無所謂)
 outC.addEventListener('click',function(){alert("target2");},true);
 outC.addEventListener('click',function(){alert("target1");},true);
 
 // 事件冒泡
 outA.addEventListener('click',function(){alert("bubble1");},false);
 outB.addEventListener('click',function(){alert("bubble2");},false);
 
 // 事件捕獲
 outA.addEventListener('click',function(){alert("capture1");},true);
 outB.addEventListener('click',function(){alert("capture2");},true);

 
 
 };
 
</script>

<body>
 <div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
 <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
  <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div> 
 </div>
 </div>
</body>

點擊outC的時候,打印順序是:capture1-->capture2-->target2-->target1-->bubble2-->bubble1。因爲outC是咱們觸發事件的目標對象,在outC上註冊的事件處理函數,屬於DOM事件流中的目標階段。目標階段函數的執行順序:先註冊的先執行,後註冊的後執行。這就是上面咱們說的,在目標對象上綁定的函數是採用捕獲,仍是採用冒泡,都沒有什麼關係,由於冒泡和捕獲只是對父元素上的函數執行順序有影響,對本身沒有什麼影響。若是不信,能夠將下面的代碼放進去驗證。spa

// 目標(自身觸發事件,是冒泡仍是捕獲無所謂)
outC.addEventListener('click',function(){alert("target1");},false);
outC.addEventListener('click',function(){alert("target2");},true);
outC.addEventListener('click',function(){alert("target3");},true);
outC.addEventListener('click',function(){alert("target4");},false);

至此咱們能夠給出事件函數執行順序的結論了:捕獲階段的處理函數最早執行,其次是目標階段的處理函數,最後是冒泡階段的處理函數。目標階段的處理函數,先註冊的先執行,後註冊的後執行。.net

阻止默認事件

1. 阻止冒泡事件代理

主要是用於阻止事件傳播。阻止它被分派到其餘的DOM節點上,在事件傳播的任何階段都能使用。使用方法以下(兼容IE):

function stopBubble(event){
	if(window.event){//兼容IE
		window.event.cancelBubble=true;
	}else{
		event.stopPropagation();
	}
 

2. 阻止默認事件

像submit這類的表單元素,都會綁定默認事件,若是不阻止默認事件,則綁定的其餘方法也會無效。使用方法以下(兼容IE):

function stopDefaultEvent(event){
	if(window.event){//兼容IE
		window.event.returnValue=false;
	}else{
		event.preventDefault()
	}
	return false;
}

 

事件委託、時間代理

 

上面的例子是要阻止冒泡,有時候冒泡機制也能夠被利用。先看一個問題:

假設要在頁面上放在 10^n(n>=1) 個列表項元素,當我點擊某個元素時,須要輸出點擊的是第幾個。

通常作法是,遍歷時給每一個元素綁定點擊事件:

var li = document.getElementsByTagName('li'); for(var i=0; i<li.length; i++){ li[i].setAttribute('i',i+1); li[i].addEventListener('click', function(e){ var b = this.getAttribute('i'); console.log('這是第' + b + '個<li>元素'); }); } 

另外一種方法是,能夠利用冒泡機制,在父元素只綁定一次點擊事件:

var li = document.getElementsByTagName('li'); for(var i=0; i<li.length; i++){ li[i].setAttribute('i',i+1); } var ul = document.getElementById('wrapper'); ul.addEventListener('click', function(e){ if(e.target && e.target.nodeName.toUpperCase() === 'LI'){ var b = e.target.getAttribute('i'); console.log('這是第' + b + '個<li>元素'); } });

這種事件委託的方式減小了事件處理程序,也能下降程序的複雜性和出錯機率。

參考:

https://www.jb51.net/article/94394.htm

https://blog.csdn.net/michael8512/article/details/77447537

相關文章
相關標籤/搜索