JS冒泡事件和捕獲事件

一塊:

事件流描述的是從頁面接收事件的順序。 
IE的事件是冒泡事件流, 
而firefox的事件流是捕獲事件流。 
1.事件冒泡 
IE的事件流叫做事件冒泡,即事件從最具體的元素到不具體的元素。 
好比氣泡從水底下一直向上冒泡,像dom樹一樣,一直到根元素。 
2.事件捕獲 
即從不具體的元素到具體的元素

事件傳遞有兩種方式:冒泡與捕獲。

事件傳遞定義了元素事件觸發的順序。 如果你將 <p> 元素插入到 <div> 元素中,用戶點擊 <p> 元素, 哪個元素的 "click" 事件先被觸發呢?

在 冒泡 中,內部元素的事件會先被觸發,然後再觸發外部元素,即: <p> 元素的點擊事件先觸發,然後會觸發 <div> 元素的點擊事件。

在 捕獲 中,外部元素的事件會先被觸發,然後纔會觸發內部元素的事件,即: <div> 元素的點擊事件先觸發 ,然後再觸發 <p> 元素的點擊事件。

第一種:事件冒泡

       IE提出的事件流叫做事件冒泡,即事件開始時由最具體的元素接收,然後逐級向上傳播到較爲不具體的節點,看一下以下示例:

接下來我們點擊一下頁面上的p元素,看看會發生什麼:

   正如上面我們所說的,它會從一個最具體的的元素接收,然後逐級向上傳播, p=>button=>div=>body..........事件冒泡可以形象地比喻爲把一顆石頭投入水中,泡泡會一直從水底冒出水面。

 

 第二種:事件捕獲

         網景公司提出的事件流叫事件捕獲流。

          事件捕獲流的思想是不太具體的DOM節點應該更早接收到事件,而最具體的節點應該最後接收到事件,針對上面同樣的例子,點擊按鈕,那麼此時click事件會按照這樣傳播:(下面我們就借用addEventListener的第三個參數來模擬事件捕獲流)

 

同樣我們看一下後臺的打印結果:

react有專屬的阻止事件冒泡方法,e.nativeEvent.stopImmediatePropagation()

handleBarDisplay(e){

       e.nativeEvent.stopImmediatePropagation();

       this.setState({barDisplay:false})

}

二塊:

事件捕獲和事件冒泡屬於兩個相反的過程,這裏可以有一個我感覺十分恰當的比喻,當你把一個可以漂浮在水面上的物品,使勁向水裏砸下去,它會首先有一個下降的過程,這個過程就可以理解爲從最頂層向事件發生的最具體元素(目標點)的捕獲過程;之後由於浮力大於物體自身的重力,物體會在到達最低點( 最具體元素)之後漂浮到水面上,這個過程相對於事件捕獲是一個回溯的過程,即事件冒泡。 
好了,對於事件捕獲和事件冒泡有了一個概念上的理解,那我們就可以開始考慮實際的編碼過程中的實際應用了。先貼上本文所需要的代碼

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>event</title>
  5. </head>
  6. <body>
  7. <div id="obj1">
  8. welcome
  9. <h5 id="obj2">hello</h5>
  10. <h5 id="obj3">world</h5>
  11. </div>
  12. <script type="text/javascript">
  13. var obj1=document.getElementById('obj1');
  14. var obj2=document.getElementById('obj2');
  15. obj1.addEventListener('click',function(){
  16. alert('hello');
  17. },false);
  18. obj2.addEventListener('click',function(){
  19. alert('world');
  20. })
  21. </script>
  22. </body>
  23. </html>

如上所示,這是一個十分簡單地文檔結構:document > html > body > div > h5 
並且分別在obj1,obj2上綁定了一個點擊事件,由於addEventListener的第三個參數爲false,所以頁面是在冒泡階段處理綁定事件。此時整個頁面可以有三種行爲出現

  1. 點擊文字welcome時,彈出hello。 
    此時就只觸發了綁定在obj1上的點擊事件。具體冒泡實現過程如下:welcome 屬於文本節點,點擊後,開始從文本節點查找,當前文本節點沒有綁定點擊事件,繼續向上找,找到父級(id爲obj1的div),有綁定的點擊事件,執行,再向上找,body,沒有綁定點擊事件,再到html,document,都沒再有綁定的點擊事件,好,整個冒泡過程結束。
  2. 點擊文字hello時,先彈出world,再彈出hello。 
    具體冒泡的過程如下圖所示

冒泡過程
3. 點擊world時,彈出hello。 
具體冒泡過程和第二種情況類似,如下圖 
這裏寫圖片描述

理解了以上的內容,我們可以接着來討論事件代理機制。 
比如上面的代碼,我們想要在點擊每個h5標籤時,彈出對應的innerHTML 。常規做法是遍歷每個h5,然後在每個h5上綁定一個點擊事件,這種做法在h5較少的時候可以使用,但如果有一萬個h5,那就會導致性能降低。這時就需要事件代理出場了。 
先貼代碼

  1. obj1.addEventListener('click',function(e){
  2. var e=e||window.event;
  3. if(e.target.nodeName.toLowerCase()=='h5'){
  4. alert(e.target.innerHTML);
  5. }
  6. },false);

由於事件冒泡機制,點擊了h5後會冒泡到div,此時就會觸發綁定在div上的點擊事件,再利用target找到事件實際發生的元素,就可以達到預期的效果。

三塊:

 

採用事件代理,爲頁面中的所有a標籤綁定click事件。

  1. document.addEventListener("click", function(e) {

  2. if (e.target.nodeName == "A")

  3. console.log("a");

  4. }, false);

問題:若a標籤裏面仍有span、img等其他元素,上述代碼中,單擊span、img等其他元素不能觸發click事件。

原因:單擊span、img等其他元素時,e.target指向的是觸發click事件的元素(span、img等其他元素),而不是a標籤。

解決方法:從觸發click事件的元素開始,逐級向上查找,直到找到a標籤爲止。

  1. document.addEventListener("click", function(e) {

  2. var node = e.target;

  3. while (node.parentNode.nodeName != "BODY") {

  4. if (node.nodeName == "A") {

  5. console.log("a");

  6. break;

  7. }

  8. node = node.parentNode;

  9. }

  10. }, false);

        <div class="person-messagebox">
            <div class="left-message"><a href="https://blog.csdn.net/weixin_41646716">
                <img src="https://profile.csdnimg.cn/5/7/E/3_weixin_41646716" class="avatar_pic" username="weixin_41646716">
            </a></div>
            <div class="middle-message">
                                    <div class="title"><span class="tit "><a href="https://blog.csdn.net/weixin_41646716" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;,&quot;ab&quot;:&quot;new&quot;}" target="_blank">歪歪100</a></span>
                    <!-- 等級,level -->
                                            <img class="identity-icon" src="https://csdnimg.cn/identity/blog6.png">                                            </div>
                <div class="text"><span>原創文章 49</span><span>獲贊 158</span><span>訪問量 70萬+</span></div>
            </div>
                            <div class="right-message">
                                        <a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;,&quot;ab&quot;:&quot;new&quot;}">關注</a>
                                                            <a href="https://im.csdn.net/im/main.html?userName=weixin_41646716" target="_blank" class="btn btn-sm bt-button personal-letter">私信
                    </a>
                                </div>
                        </div>
                    
    </div>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章