zoukankan      html  css  js  c++  java
  • js中事件冒泡的理解与分析

    一. 事件

    1. 事件的三个阶段:事件捕获 -> 事件目标 -> 事件冒泡
    • 捕获阶段:先由文档的根节点document往事件触发对象,从外向内捕获事件对象;
    • 目标阶段:到达目标事件位置(事发地),触发事件;
    • 冒泡阶段:再从目标事件位置往文档的根节点方向回溯,从内向外冒泡事件对象
    1. 事件捕获:事件发生时首先发生在document上,然后依次传递给body,最后到达目的节点(即事件目标),事件流模型:div →body→ html→ document

    2. 事件冒泡:事件到达事件目标之后不会结束,会逐层向上冒泡,直至document对象,跟事件捕获相反。

    3. onclick 事件冒泡,重写onlick会覆盖之前属性,没有兼容性问题

    • addEventListener(event.type, handle, boolean); IE8及以下不支持,属于DOM2级的方法,可添加多个方法不被覆盖。事件类型没有on,第三个参数false,表示在事件第三阶段(冒泡)触发,true表示在事件第一阶段(捕获)触发。如果绑定同一个事件同一个方法,只会执行一次,所以如果handle是同一个方法,只执行一次。
    • attachEvent(event.type, handle ); IE特有,兼容IE8及以下,可添加多个事件处理程序,只支持冒泡阶段,可以多次进行绑定,所以如果handle是同一个方法,绑定几次执行几次,同时事件类型要加on。
    • 默认事件行为:href=""链接,submit表单提交等
    1. 阻止默认事件
    • return false; 阻止独享属性(通过on这种方式)绑定的事件的默认事件,阻止浏览器对事件的默认处理,只在当前函数有效,不会影响其他外部函数的执行
    • event.preventDefault( );
    • 阻止通过 addEventListener( ) 添加的事件的默认事件 event.returnValue = false; 阻止通过 attachEvent( ) 添加的事件的默认事件
    1. 事件的绑定与事件的解绑

      事件的绑定

      代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function addEvent(element,eType,handle,bol){
           //  支持addEventListener
           if(element.addEventListener){
               element.addEventListener(eType,handle,bol);
           //  支持attachEvent
           }else if(element.attachEvent){
               element.attachEvent("on"+eType,handle);
           //  兼容的onclick的绑定
           }else{
               element["on"+eType] = handle;
           }
       }

      

     

    事件的解绑

    代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function removeEvent(element,eType,handle,bol){
            // 支持addEventListener
            if(element.addEventListener){
                element.addEventListener(eType,handle,bol);
           //  支持attachEvent
            }else if(element.attachEvent){
                element.detachEvent("on"+eType,handle);
           //  兼容的onclick的绑定
            }else{
                element["on"+eType] = null;
            }
        }

      

     

    封装函数:通过事件冒泡的方式,兼容事件捕获只需要添加个bool参数

    代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    var EventUtil = {
            addEvent: function(element,type,handle){
                if(element.addEventListener){
                    element.addEventListener(type,handle,false);
                }else if(element.addEvent){
                    element.addEvent("on"+type,handle);
                }else{
                    element["on"+type] =  handle;
                }
            },
     
           removeEvent:function(element,type,handle){
               if(element.removeEventListener){
                   element.removeEventListener(type,handle,false);
               }else if(element.removeEvent){
                   element.removeEvent("on"+type,handle);
               }else{
                   element["on"+type] = null;
               }
           }
            
       }

      

     
    1. 常见的事件绑定

    1)bind()

    • 只能给调用它的时候已经存在的元素绑定事件,不能给未来新增的元素绑定事件
    • bind()不能使用的情况:为DOM中的很多元素绑定相同的事件,为DOM中的尚不存在的元素绑定事件

    2)live()

    • 方法会把click事件绑定到$(document)对象,而且只需要给$(document)绑定一次,然后就能够处理后续动态加载的节点的事件
    • 在接收到任何事件时,$(document)对象都会检查事件类型和事件目标,如果是click事件且事件目标是td,那么就执行委托给它的处理程序

    3)delegate()

    • 直接将目标元素选择符("td")、事件("click")及处理程序与“受拖方”$("#info_table")绑定,不额外收集元素、事件传播路径缩短、语义明确
    • 支持在连缀的DOM遍历方法后面调用,即支持$("table").find("#info").delegate...,支持精确控制
    1. 事件冒泡、事件捕获阻止
    • event.stopPropagation( ); 阻止事件的进一步传播,包括(冒泡,捕获),无参数
    • event.cancelBubble = true; true 为阻止冒泡
    1. W3C事件模型中发生的任何事件,先从其祖先元素window开始一路向下捕获, 直到达到目标元素,其后再次从目标元素开始冒泡。可以决定事件处理器是注册在捕获或者是冒泡阶段。

    注意:如果addEventListener的最后一个参数是true, 那么处理函数将在捕获阶段被触发; 否则(false), 会在冒泡阶段被触发,默认false。

    二、事件冒泡

    1. 事件冒泡:当一个元素接收到事件的时候 会把他接收到的事件传给自己的父级,一直到window。从事件源,自下而上的过程中,阻止向上冒泡,即阻止触发上级元素的事件触发,上级元素做事件触发时,在此事件源上无效。在事件传播的过程中,当事件在一个元素上出发之后,事件会逐级传播给先辈元素,直到document为止,有的浏览器可能到window为止。

    2. 事件冒泡的实例

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      代码如下:
       
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>事件冒泡</title>
      </head>
      <body>
       
      <div id="div1">div1
          <div id="div2">div2</div>
      </div>
       
      </body>
      <script>
       
          var div1 = document.getElementById("div1");
          var div2 = document.getElementById("div2");
       
          div1.onclick = function(){
              console.log("我是div1");
          };
       
          div2.onclick = function(){
              console.log("我是div2");
          };
       
      </script>
      </html>

        

    说明:两个父子关系的div1和div2,分别给div1和div2绑定了点击事件。当点击div1的时候,控制台打印输出 我是div1。当点击div2的时候,控制台打印输出 我是div2 和 我是div1,在这个时候就说明了当我们子点击div2的时候,div1的事件也被触发了,父级事件被触发,这种现象相当于就是冒泡事件。

    1. 取消事件冒泡的方式
    • 标准的W3C 方式:e.stopPropagation();这里的stopPropagation是标准的事件对象的一个方法,调用即可
    • 非标准的IE方式:ev.cancelBubble=true; 这里的cancelBubble是 IE事件对象的属性,设为true就可以了

    封装取消事件冒泡的函数

    代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function stopBubble(env){
            // 如果提供事件对象,说明为非IE浏览器
            if(env && env.stopPropagation){
                env.stopPropagation();
            }else{
             // IE浏览器
                window.event.cancelBubble = true;
            }
        }

      

     
    1. 取消事件冒泡的实例

      代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>事件冒泡2</title>
        <style>
            .d1 {
                 300px;
                height: 300px;
                background-color: skyblue;
                display: none;
            }
     
        </style>
    </head>
    <body>
     
    <button id="btn">按钮</button>
    <div class="d1"></div>
     
    </body>
    <script>
     
        // 单击动作会从btn传到document中,发生事件冒泡
     
        var btn = document.getElementById("btn");
        var d1 = document.getElementsByClassName("d1")[0];
     
        // 点击按钮的时候,元素d1显示
        btn.onclick = function(e){
            d1.style.display = "block";
            // 阻止冒泡
            stopBubble(e);
        };
     
        // 点击网页其它地方的时候,元素d1隐藏
        document.onclick = function(){
            d1.style.display = "none";
        };
     
        // 阻止浏览器的默认行为函数,事件冒泡
        //  event.stopPropagation   阻止事件冒泡的方法
        function stopBubble(e) {
            // 非IE浏览器阻止冒泡
            if( e && e.stopPropagation )
                e.stopPropagation();
            else
            // IE浏览器阻止冒泡
               window.event.cancelBubble = true;
        }
     
    </script>
    </html>

      

     

    说明:定义一个按钮,在按钮下面有一个div的元素d1,默认为隐藏。点击按钮的时候,元素d1显示。在点击按钮的时候,调用了阻止事件冒泡的发生函数stopBubble()。点击docume网页其它地方的时候,元素d1隐藏。

    三、跨浏览器的事件对象

    1. 跨浏览器的事件对象

      代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    var EventUtil={
       getEvent:function(event){
           return event||window.event;
       },
       getTarget:function(event){
           return event.target||event.srcElement;
       },
       preventDefault:function(){
           if(event.preventDefault){
               event.preventDefault();
           }else{
               event.returnValue=false;
           }
       },
       stopPropagation:function(){
           if(event.stopPropagation){
               event.stopPropagation();
           }else{
               event.cancelBubble=true;
           }
       },
       addEvent:function(element,type,handler){
           if(element.addEventListener){
               element.addEventListener(type,handler,false);
           }else if(element.attachEvent){
                element["e"+type]=function(){
                 handler.call(element)
             }
               element.attachEvent("on"+type,element["e"+type]);
           }else{
               element["on"+type]=handler;
           }
       },
       removeEvent:function(element,type,handler){
           if(element.removeEventListener){
               element.removeEventListener(type,handler,false);
           }else if(element.detachEvent){
               element.detachEvent("on"+type,element["e"+type]);
               element["e"+type]=null;   
           }else{
               element["on"+type]=null;
           }
       }
     
     };
  • 相关阅读:
    Android 解决小米手机Android Studio安装app 报错的问题It is possible that this issue is resolved by uninstalling an existi
    Android Unresolved Dependencies
    Android studio 自定义打包apk名
    Android Fragment与Activity交互的几种方式
    魅族和三星Galaxy 5.0webView 问题Android Crash Report
    Android几种常见的多渠道(批量)打包方式介绍
    Android批量打包 如何一秒内打完几百个apk渠道包
    上周热点回顾(9.30-10.6)团队
    上周热点回顾(9.23-9.29)团队
    上周热点回顾(9.16-9.22)团队
  • 原文地址:https://www.cnblogs.com/dkjf/p/12295842.html
Copyright © 2011-2022 走看看