目錄
事件流相關概念
事件捕獲
事件冒泡
事件委托
優點
缺點
事件流相關概念
事件流描述的是從頁面中接受事件的順序
DOM事件流包括三個階段:
1.事件捕獲階段:事件從window對象開始觸發,該階段主要捕獲截取事件
2.處于目标階段:該階段具有雙重範圍--捕獲階段結束、冒泡階段開始
3.事件冒泡階段:将目标元素綁定事件執行結果傳回給浏覽器
事件捕獲
該概念由網景公司提出。事件響應從最外層window開始,逐級向内層傳播,直到具體的事件目标元素。
在上一篇總結事件處理的部落格中,我們有了解到使用事件監聽方式給元素注冊事件處理函數,其中第三個可選參數capture,預設false(事件冒泡階段處理),可填true(事件捕獲階段處理),通過這個參數我們就可以設定事件處理階段采用什麼方式。現在我們可以通過代碼測試來看看事件捕獲與事件冒泡之間的差別:
<div>
<p>
<button>點選</button>
</p>
</div>
<script>
var div = document.querySelector('div');
var p = document.querySelector('p');
var button = document.querySelector('button');
//注冊捕獲事件監聽器
div.addEventListener('click',function(e){
console.log("div元素");
},true);
p.addEventListener('click',function(e){
console.log("p元素");
},true);
button.addEventListener('click',function(e){
console.log("button元素");
},true);
</script>
點選按鈕後console調試接口中各個輸出順序如下:可見是由外到内逐個捕獲
事件冒泡
該概念由微軟公司提出,事件傳播順序與事件捕獲相反,是從事件按開始的具體元素,一級級往上傳播,直至傳回給window。
例如:
<div>
<p>
<button>點選</button>
</p>
</div>
<script>
var div = document.querySelector('div');
var p = document.querySelector('p');
var button = document.querySelector('button');
//注冊冒泡事件監聽器
div.addEventListener('click',function(e){
console.log("div元素");
},false);
p.addEventListener('click',function(e){
console.log("p元素");
},false);
button.addEventListener('click',function(e){
console.log("button元素");
},false);
</script>
點選按鈕後console調試接口中各個輸出順序如下:可見是由内到外逐個捕獲
事件委托
事件委托,也稱事件代理,利用它将事件綁定給父級元素或者更進階元素,讓處理代碼在父級元素或者更進階元素中執行,這樣隻指定一個事件處理程式,就可以管理某一類型的所有事件,提高程式運作效率。舉個例子:一個班的教材,每個人自己去教材科領書會很繁雜,很導緻很多人排隊進度慢,利用事件委托,讓班主任領回全班的書再依次分發給同學們,這樣就會提高效率,減少不必要的程序。
例如,我們想給每個<li>綁定單擊事件,正常方法是使用周遊給每個<li>綁定一個單擊事件
<ul>
<li>content1</li>
<li>content2</li>
<li>content3</li>
<li>content4</li>
<li>content5</li>
</ul>
<script>
var ul = document.querySelector('ul');
var lis = ul.querySelectorAll('li');
for(var i=0;i<lis.length;i++){
lis[i].onclick = function(){
console.log(this.innerText);
}
}
</script>
這個方法在清單項少的時候可以使用,但是當清單項很多的時候,例如成千上萬個<li>,就會導緻性能降低。這個時候我們利用事件委托,隻需要給<ul>綁定一個事件:
<ul>
<li>content1</li>
<li>content2</li>
<li>content3</li>
<li>content4</li>
<li>content5</li>
</ul>
<script>
var ul = document.querySelector('ul');
var lis = ul.querySelectorAll('li');
ul.addEventListener("click",function(e){
var e = e || window.event; //相容性處理
if(e.target.nodeName.toLowerCase() === 'li'){
console.log(e.target.innerText);
}},false);
</script>
它的原理是利用了事件冒泡機制,當點選<li>,會向上冒泡到<ul>,然後就會觸發綁定在<ul>上的事件,再利用event.target屬性找到觸發時間的節點,做出相應動作,就可以達到相同的效果。
使用事件代理不僅可以将多個事件處理函數減少為一個,還可以針對不同的元素做出不同的處理方法。例如上例中,若清單元素中添加其他元素節點,我們可以直接修改事件代裡的事件處理函數,用此來代替循環給元素綁定事件。
綜上我們可以總結一下事件委托的優缺點:
優點
1.減少事件注冊,節省記憶體占用
2.動态綁定事件,當新增子對象時無需再次對其綁定
缺點
1.如果DOM嵌套結構很深,事件冒泡通過大量祖先元素會導緻性能損失
2.事件冒泡過程也需要耗時,越靠近頂層,事件傳播鍊越長,耗時越長(是以使用事件委托時,不是把事件委托給的元素越靠近頂層越好,需要根據代碼要實作的效果均衡考慮)