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>

一块:

猜你喜欢

转载自blog.csdn.net/WXB_gege/article/details/105920521
今日推荐