您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關如何進行JS中的事件冒泡與捕獲,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
剛接觸 JS 的那個時候,啥也不懂,只想著如何利用 Google、百度到的函數來解決實際的問題,不會想到去一探究竟。
漸漸的,對 JS 的語言的不斷深入,有機會去了解一些原理性東西。最近在看 JQuery 源碼,感觸很多,總想著用原生的 JS 去實現自己的一個 JQuery 庫。說實在的,JQuery 里面很多函數和思路,是千百開源工作者長期的貢獻,哪能是短時間就能消化的了。
最近再次碰到 addEventListener函數(MDN 上關于 addEventListener 的介紹,很詳細),由于之前并沒有弄懂第三個參數的含義,要么默認值,要么手動設置成 false。這次看了不少文章,徹底把事件冒泡和捕獲弄懂。
什么事件冒泡與捕獲
事件冒泡與捕獲是 DOM 中事件傳播的兩種方式,比如說對于注冊了相同事件的兩個 DOM 元素(簡單點就是兩個 div,一里一外),當點擊里層 div 的時候,這兩個事件誰先執行。
冒泡事件,由里向外,最里層的元素先執行,然后冒泡到外層。
捕獲事件,由外向里,最外層的元素先執行,然后傳遞到內部。
在 IE 9 之前是只支持事件冒泡,IE 9(包括 IE 9) 之后和目前主流的瀏覽器都同時支持兩種事件。
如何設置,只需修改 addEventListener的第三個參數,true 為捕獲,false 為冒泡,默認為冒泡。
舉個簡單的例子,
<div> <span class="out"> <span class="in"></span> </span> </div> <script type="text/javascript"> var dom_out = document.getElementsByClassName('out')[0]; var dom_in = document.getElementsByClassName('in')[0]; dom_out.addEventListener('click',function(){ alert('out'); },false); dom_in.addEventListener('click',function(){ alert('in'); },false); </script>
在上面這個例子中,事件是按照冒泡來執行的,點擊里層的 in,會看到先 alert 的順序是先 "in" 后 "out",如果把事件改成捕獲,alert 的順序又不一樣了。
<script type="text/javascript"> var dom_out = document.getElementsByClassName('out')[0]; var dom_in = document.getElementsByClassName('in')[0]; dom_out.addEventListener('click',function(){ alert('out'); },true); dom_in.addEventListener('click',function(){ alert('in'); },true); </script>
上面這個例子是捕獲事件的例子,點擊 in效果是不是不一樣呢?
之所以會有冒泡和捕獲事件(像 IE 9 之前的瀏覽器不支持捕獲事件,還真是反程序員),畢竟在實際中處理事情肯定有個先后順序,要么由里向外,要么由外向里,兩者都是必須的。
但有時候為了兼容 IE 9 以下版本的瀏覽器,都會把第三個參數設置成 false 或者默認(默認就是 false)。
進一步理解冒泡和捕獲
現在已經說清楚冒泡和捕獲,那么如果同時出現冒泡和捕獲會出現什么結果?
原來瀏覽器處理時間分為兩個階段,捕獲階段和冒泡階段,
先執行捕獲階段,如果事件是在捕獲階段執行的(true 情況),則執行;
然后是冒泡階段,如果事件是在冒泡階段執行的(false 情況),則執行;
來看一看例子就知道了:
<div> <span class="s1">s1 <span class="s2">s2 <span class="s3">s3 </span> </span> </span> </div>
這次我們設置三個 span,分別是 s1, s2, s3,然后設置 s1,s3 為冒泡執行,s2 為捕獲執行:
<script type="text/javascript"> var s1 = document.getElementsByClassName('s1')[0]; var s2 = document.getElementsByClassName('s2')[0]; var s3 = document.getElementsByClassName('s3')[0]; s1.addEventListener('click',function(){ alert('s1'); },false); s2.addEventListener('click',function(){ alert('s2'); },true); s3.addEventListener('click',function(){ alert('s3'); },false); </script>
從運行的效果來看,點擊 s3,依次 alert s2 => s3 => s1,說明:
捕獲事件和冒泡事件同時存在的,而且捕獲事件先執行,冒泡事件后執行;
如果元素存在事件且事件的執行時間與當前邏輯一致(冒泡或捕獲),則執行。
默認事件取消與停止冒泡
當然,有時候我們只想執行最內層或最外層的事件,根據內外層關系來把范圍更廣的事件取消掉(對于新手來說,不取消冒泡,很容易中招的出現 bug)。event.stopPropagation()(IE 中window.event.cancelBubble = true)可以用來取消事件冒泡。
有時候對于瀏覽器的默認事件也需要取消,這時候用到的函數則是 event.preventDefault()(IE 中window.event.returnValue = false)。
那么默認事件取消和停止冒泡有什么區別呢?我的理解:瀏覽器的默認事件是指瀏覽器自己的事件(這不廢話嗎),比如 a 標簽 的點擊,表單的提交等,取消掉就不會執行啦;冒泡則取消的是由外向里(捕獲)、由里向外(冒泡),stop 之后,就不會繼續遍歷了。stackoverflow 上的解答
看下例子,依舊是上面那個例子,不過每個函數都加了 停止冒泡:
s1.addEventListener('click',function(e){ e.stopPropagation(); alert('s1'); },false); s2.addEventListener('click',function(e){ e.stopPropagation(); alert('s2'); },true); s3.addEventListener('click',function(e){ e.stopPropagation(); alert('s3'); },false);
點擊的結果是:當點擊 s2 或 s3 的時候,都會 alert s2,點擊 s1,彈出 s1。因為事件被取消的緣故,點擊 s3,執行 s2后就不會在向下執行了。
在看一個 preventDefault 的例子。
<div> <a href="/">點我回主頁</a> </div> <div> <a href="/" class="back">點我不回主頁</a> </div> <script type="text/javascript"> var back = document.getElementsByClassName('back')[0]; back.addEventListener('click', function(e){ e.preventDefault(); }); </script>
第二個鏈接是不是回不了主頁,因為瀏覽器的默認事件被取消了。
總結就補充兩個兼容 IE 的函數吧:
function stopBubble(e) { //如果提供了事件對象,則這是一個非IE瀏覽器 if ( e && e.stopPropagation ) //因此它支持W3C的stopPropagation()方法 e.stopPropagation(); else //否則,我們需要使用IE的方式來取消事件冒泡 window.event.cancelBubble = true; } //阻止瀏覽器的默認行為 function stopDefault( e ) { //阻止默認瀏覽器動作(W3C) if ( e && e.preventDefault ) e.preventDefault(); //IE中阻止函數器默認動作的方式 else window.event.returnValue = false; return false; }
上述就是小編為大家分享的如何進行JS中的事件冒泡與捕獲了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。