自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

JS中的事件冒泡與捕獲

開發(fā) 前端
事件冒泡與捕獲是 DOM 中事件傳播的兩種方式,比如說對于注冊了相同事件的兩個(gè) DOM 元素(簡單點(diǎn)就是兩個(gè) div,一里一外),當(dāng)點(diǎn)擊里層 div 的時(shí)候,這兩個(gè)事件誰先執(zhí)行。冒泡事件,由里向外,最里層的元素先執(zhí)行,然后冒泡到外層。捕獲事件,由外向里,最外層的元素先執(zhí)行,然后傳遞到內(nèi)部。

剛接觸 JS 的那個(gè)時(shí)候,啥也不懂,只想著如何利用 Google、百度到的函數(shù)來解決實(shí)際的問題,不會(huì)想到去一探究竟。

漸漸的,對 JS 的語言的不斷深入,有機(jī)會(huì)去了解一些原理性東西。最近在看 JQuery 源碼,感觸很多,總想著用原生的 JS 去實(shí)現(xiàn)自己的一個(gè) JQuery 庫。說實(shí)在的,JQuery 里面很多函數(shù)和思路,是千百開源工作者長期的貢獻(xiàn),哪能是短時(shí)間就能消化的了。

最近再次碰到 addEventListener函數(shù)(MDN 上關(guān)于 addEventListener 的介紹,很詳細(xì)),由于之前并沒有弄懂第三個(gè)參數(shù)的含義,要么默認(rèn)值,要么手動(dòng)設(shè)置成 false。這次看了不少文章,徹底把事件冒泡和捕獲弄懂。

什么事件冒泡與捕獲

事件冒泡與捕獲是 DOM 中事件傳播的兩種方式,比如說對于注冊了相同事件的兩個(gè) DOM 元素(簡單點(diǎn)就是兩個(gè) div,一里一外),當(dāng)點(diǎn)擊里層 div 的時(shí)候,這兩個(gè)事件誰先執(zhí)行。

冒泡事件,由里向外,最里層的元素先執(zhí)行,然后冒泡到外層。

捕獲事件,由外向里,最外層的元素先執(zhí)行,然后傳遞到內(nèi)部。

在 IE 9 之前是只支持事件冒泡,IE 9(包括 IE 9) 之后和目前主流的瀏覽器都同時(shí)支持兩種事件。

如何設(shè)置,只需修改 addEventListener的第三個(gè)參數(shù),true 為捕獲,false 為冒泡,默認(rèn)為冒泡。

舉個(gè)簡單的例子,

  1. <div> 
  2.   <span class="out"
  3.     <span class="in"></span> 
  4.   </span> 
  5. </div> 
  6. <script type="text/javascript"
  7.   var dom_out = document.getElementsByClassName('out')[0]; 
  8.   var dom_in = document.getElementsByClassName('in')[0]; 
  9.   dom_out.addEventListener('click',function(){ 
  10.     alert('out'); 
  11.   },false); 
  12.   dom_in.addEventListener('click',function(){ 
  13.     alert('in'); 
  14.   },false); 
  15. </script> 

   

 在上面這個(gè)例子中,事件是按照冒泡來執(zhí)行的,點(diǎn)擊里層的 in,會(huì)看到先 alert 的順序是先 "in" 后 "out",如果把事件改成捕獲,alert 的順序又不一樣了。

  1. <script type="text/javascript"
  2.   var dom_out = document.getElementsByClassName('out')[0]; 
  3.   var dom_in = document.getElementsByClassName('in')[0]; 
  4.   dom_out.addEventListener('click',function(){ 
  5.     alert('out'); 
  6.   },true); 
  7.   dom_in.addEventListener('click',function(){ 
  8.     alert('in'); 
  9.   },true); 
  10. </script> 

 

上面這個(gè)例子是捕獲事件的例子,點(diǎn)擊 in效果是不是不一樣呢?

之所以會(huì)有冒泡和捕獲事件(像 IE 9 之前的瀏覽器不支持捕獲事件,還真是反程序員),畢竟在實(shí)際中處理事情肯定有個(gè)先后順序,要么由里向外,要么由外向里,兩者都是必須的。

但有時(shí)候?yàn)榱思嫒?IE 9 以下版本的瀏覽器,都會(huì)把第三個(gè)參數(shù)設(shè)置成 false 或者默認(rèn)(默認(rèn)就是 false)。

進(jìn)一步理解冒泡和捕獲

現(xiàn)在已經(jīng)說清楚冒泡和捕獲,那么如果同時(shí)出現(xiàn)冒泡和捕獲會(huì)出現(xiàn)什么結(jié)果?

原來瀏覽器處理時(shí)間分為兩個(gè)階段,捕獲階段和冒泡階段,

  • 先執(zhí)行捕獲階段,如果事件是在捕獲階段執(zhí)行的(true 情況),則執(zhí)行;
  • 然后是冒泡階段,如果事件是在冒泡階段執(zhí)行的(false 情況),則執(zhí)行;

來看一看例子就知道了:

  1. <div> 
  2.   <span class="s1">s1 
  3.     <span class="s2">s2 
  4.       <span class="s3">s3 
  5.       </span> 
  6.     </span> 
  7.   </span> 
  8. </div>  

這次我們設(shè)置三個(gè) span,分別是 s1, s2, s3,然后設(shè)置 s1,s3 為冒泡執(zhí)行,s2 為捕獲執(zhí)行:

  1. <script type="text/javascript"
  2.   var s1 = document.getElementsByClassName('s1')[0]; 
  3.   var s2 = document.getElementsByClassName('s2')[0]; 
  4.   var s3 = document.getElementsByClassName('s3')[0]; 
  5.   s1.addEventListener('click',function(){ 
  6.     alert('s1'); 
  7.   },false); 
  8.   s2.addEventListener('click',function(){ 
  9.     alert('s2'); 
  10.   },true); 
  11.   s3.addEventListener('click',function(){ 
  12.     alert('s3'); 
  13.   },false); 
  14. </script> 

 

從運(yùn)行的效果來看,點(diǎn)擊 s3,依次 alert s2 => s3 => s1,說明:

  • 捕獲事件和冒泡事件同時(shí)存在的,而且捕獲事件先執(zhí)行,冒泡事件后執(zhí)行;
  • 如果元素存在事件且事件的執(zhí)行時(shí)間與當(dāng)前邏輯一致(冒泡或捕獲),則執(zhí)行。

默認(rèn)事件取消與停止冒泡

當(dāng)然,有時(shí)候我們只想執(zhí)行最內(nèi)層或最外層的事件,根據(jù)內(nèi)外層關(guān)系來把范圍更廣的事件取消掉(對于新手來說,不取消冒泡,很容易中招的出現(xiàn) bug)。event.stopPropagation()(IE 中window.event.cancelBubble = true)可以用來取消事件冒泡。

有時(shí)候?qū)τ跒g覽器的默認(rèn)事件也需要取消,這時(shí)候用到的函數(shù)則是 event.preventDefault()(IE 中window.event.returnValue = false)。

那么默認(rèn)事件取消和停止冒泡有什么區(qū)別呢?我的理解:瀏覽器的默認(rèn)事件是指瀏覽器自己的事件(這不廢話嗎),比如 a 標(biāo)簽 的點(diǎn)擊,表單的提交等,取消掉就不會(huì)執(zhí)行啦;冒泡則取消的是由外向里(捕獲)、由里向外(冒泡),stop 之后,就不會(huì)繼續(xù)遍歷了。stackoverflow 上的解答

看下例子,依舊是上面那個(gè)例子,不過每個(gè)函數(shù)都加了 停止冒泡:

  1. s1.addEventListener('click',function(e){ 
  2.   e.stopPropagation(); 
  3.   alert('s1'); 
  4. },false); 
  5. s2.addEventListener('click',function(e){ 
  6.   e.stopPropagation(); 
  7.   alert('s2'); 
  8. },true); 
  9. s3.addEventListener('click',function(e){ 
  10.   e.stopPropagation(); 
  11.   alert('s3'); 
  12. },false);  

 

 

點(diǎn)擊的結(jié)果是:當(dāng)點(diǎn)擊 s2 或 s3 的時(shí)候,都會(huì) alert s2,點(diǎn)擊 s1,彈出 s1。因?yàn)槭录蝗∠木壒剩c(diǎn)擊 s3,執(zhí)行 s2后就不會(huì)在向下執(zhí)行了。

在看一個(gè) preventDefault 的例子。

  1. <div> 
  2.   <a href="/">點(diǎn)我回主頁</a> 
  3. </div> 
  4. <div> 
  5.   <a href="/" class="back">點(diǎn)我不回主頁</a> 
  6. </div> 
  7. <script type="text/javascript"
  8.   var back = document.getElementsByClassName('back')[0]; 
  9.   back.addEventListener('click'function(e){ 
  10.     e.preventDefault(); 
  11.   }); 
  12. </script> 

[[174022]]

第二個(gè)鏈接是不是回不了主頁,因?yàn)闉g覽器的默認(rèn)事件被取消了。

以上所有例子請?jiān)诜堑桶姹?IE 瀏覽器的環(huán)境下瀏覽 O_o

總結(jié)

總結(jié)就補(bǔ)充兩個(gè)兼容 IE 的函數(shù)吧:

  1. function stopBubble(e) { 
  2.   //如果提供了事件對象,則這是一個(gè)非IE瀏覽器 
  3.   if ( e && e.stopPropagation ) 
  4.       //因此它支持W3C的stopPropagation()方法 
  5.       e.stopPropagation(); 
  6.   else 
  7.       //否則,我們需要使用IE的方式來取消事件冒泡 
  8.       window.event.cancelBubble = true
  9. //阻止瀏覽器的默認(rèn)行為 
  10. function stopDefault( e ) { 
  11.   //阻止默認(rèn)瀏覽器動(dòng)作(W3C) 
  12.   if ( e && e.preventDefault ) 
  13.       e.preventDefault(); 
  14.   //IE中阻止函數(shù)器默認(rèn)動(dòng)作的方式 
  15.   else 
  16.       window.event.returnValue = false
  17.   return false
  18.  

共勉!

參考

stackoverflow 什么是事件冒泡和捕捉

stackoverflow stopPropagation 和 preventDefault 的區(qū)別

MDN addEventListener

javascript阻止事件冒泡和瀏覽器的默認(rèn)行為

責(zé)任編輯:龐桂玉 來源: segmentfault
相關(guān)推薦

2013-09-13 13:15:28

AndroidWebViewJavaScript

2022-07-28 08:34:59

事件委托JS

2024-01-05 08:49:15

Node.js異步編程

2021-08-03 06:57:36

Js事件節(jié)流

2009-08-18 11:08:24

.Net Framew

2024-05-16 13:36:04

C#委托事件

2009-12-30 14:28:06

Silverlight

2013-05-21 14:22:29

Android游戲開發(fā)捕獲屏幕雙擊事件

2023-01-31 16:43:31

?Node.js事件循環(huán)

2015-05-19 11:11:29

JavaScript事件使用指南

2024-05-15 09:11:51

委托事件C#

2021-05-21 09:36:42

開發(fā)技能代碼

2021-10-22 08:29:14

JavaScript事件循環(huán)

2016-10-14 14:32:58

JavascriptDOMWeb

2019-10-30 08:53:46

JavaScript冒泡排序選擇排序

2013-04-22 15:40:00

Android開發(fā)觸摸事件與點(diǎn)擊事件區(qū)別

2010-08-04 13:23:29

Flex事件

2011-06-30 10:28:50

C#開發(fā)

2024-02-01 12:38:22

事件流事件溯源系統(tǒng)

2019-05-09 09:42:12

蜜罐網(wǎng)絡(luò)攻擊漏洞
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)