JavaScript事件冒泡和事件委託

JavaScript中事件流是開發過程中常用到的知識,我們需要理解熟練掌握其基本原理和使用場景。
JavaScript可以監控頁面上元素的各種事件,常用的事件有很多,例如點擊,鼠標移入、移出,元素改變等等。這次主要說一下事件冒泡及其一個比較酷的應用,事件委託。不做特殊說明,以下都在jQuery框架內執行。

事件冒泡

什麼是“事件冒泡”呢?假設這裏有一杯水,水被用某種神奇的方式分成不同顏色的幾層。這時,從最底層冒出了一個氣泡,氣泡會一層一層地上升,直到最頂層。而你不管在水的哪一層觀察都可以看到並捕捉到這個氣泡。好了,把“水”改成“DOM”,把“氣泡”改成“事件”。這就是“事件冒泡”。

爲了可以直觀地觀察到這一現象,我寫了一個小程序。這個頁面中一共有4個嵌套的正方形。最大的那個在最頂層,最小的那個在最底層。我爲每一層都單獨綁定了一個點擊事件,當這一層被點擊時,會爲這層塗色。試試看,點擊最小的正方形會發生什麼?點擊其他的又會發生什麼呢?

CSS

.white{background-color:#fff;}
#d1{width:400px;height:400px;border:1px solid #000;margin:50px50px;}
#d2{width:300px;height:300px;border:1px solid #000;margin:50px50px;}
#d3{width:200px;height:200px;border:1px solid #000;margin:50px50px;}
#d4{width:100px;height:100px;border:1px solid #000;margin:50px50px;}

HTML

<div id="d1"class="white">
 <div id="d2"class="white">
 <div id="d3"class="white">
 <div id="d4"class="white"></div>
</div>
</div>
</div>
<button id="reset1">重置</button>

Javascript

jQuery('#d4').click(function(){jQuery(this).css('background-color','yellow')});
jQuery('#d3').click(function(){jQuery(this).css('background-color','green')});
jQuery('#d2').click(function(){jQuery(this).css('background-color','blue')});
jQuery('#d1').click(function(){jQuery(this).css('background-color','red')});
jQuery('#reset1').click(function(){jQuery('.white').css('background-color','#fff')});

沒錯,點擊最小的那個,外面所有的都會被上色。你會發現,點擊裏層的正方形,外層所有的正方形都會被上色。因爲它們也都捕捉到了點擊事件。看,他們抓到“氣泡”了!

事件委託

上一節的例子我們做一點小小的修改。氣泡帶上了某種信息,會告訴其經過的每一層自己是在哪一層產生的。JavaScript的事件確實會帶着這個屬性。當程序捕獲一個事件的時候,它會知道這個事件來自於頁面上哪個元素。修改上面的程序,使用事件委託來處理點擊事件。當最頂層捕獲點擊事件時,查看事件來源於哪一層,然後只將那一層塗色。再次點擊每一層,查看實際效果。只有當前點擊的正方形變色了,其他的都毫無反應。

jQuery('#d1').click(function(e){
vart=jQuery(e.target);
varid=t.attr('id');
if(id==='d4'){
t.css('background-color','yellow');
}elseif(id==='d3'){
t.css('background-color','green');
}elseif(id==='d2'){
t.css('background-color','blue');
}else{
t.css('background-color','red');
}
});

當然,如果你有這樣嵌套的頁面元素,使用了事件委託,委託到了最頂層,這時需要注意:如果其中某個元素,你不希望它的事件冒泡,那麼可以使用某種方式阻止事件的冒泡。在jQuery框架中,可以使用stopPropagation()方法來實現而不必關心瀏覽器兼容性。

$('#bind').click(function(){
if($(this).is(':checked')){
$('#d4').bind('click',function(e){
e.stopPropagation();
alert('冒泡被阻止,這塊將不會改變顏色');
});
}else{
$('#d4').unbind('click');
}
});

重置後選中“阻止最小的方塊的事件冒泡”,再點擊最小的方塊,看是否變色。顯然是不會變色,阻止了冒泡,父層將無法接收到點擊事件。

注意事項

事件委託是事件冒泡的一個應用,可以減少綁定元素的個數,也不必擔心子節點被替換後可能需要進行重新的事件綁定。因爲事件的捕獲和後續代碼的執行已經完全委託給了其父節點。如果頁面中含有大量元素需要綁定事件,這樣做會減少事件綁定數量,爲瀏覽器減負,無疑會提高頁面性能。

但也有些需要注意的。如果用於捕獲事件的節點會在某些情況下return false,而你的一個點擊事件未委託給父節點,那麼,你可能需要阻止這個節點的事件冒泡來達到正確的目的。例如:我在一個div裏面有一些按鈕和其他元素。利用事件委託來處理這些按鈕的點擊,如果不是按鈕則return false。這時,錯誤就出現了。如果其他元素中含有鏈接,那麼鏈接的點擊事件也會被委託給div。然而點擊鏈接,會沒有任何反應。解決辦法一是在委託的代碼中對鏈接進行處理,二是阻止鏈接的事件冒泡。

發佈了38 篇原創文章 · 獲贊 12 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章