美文网首页
Javascript中的事件流(IE和W3C的区别)和事件委托

Javascript中的事件流(IE和W3C的区别)和事件委托

作者: 胡拉圈 | 来源:发表于2019-02-27 13:56 被阅读0次

    事件流是用来描述页面接收事件的顺序。目前存在的两种基本的事件流为事件冒泡和事件捕获

    事件冒泡

    即事件应该从嵌套层次最深的节点(目标元素节点)冒泡到较为不具体的节点(Document对象),所有的现代浏览器都支持事件冒泡,但是在IE5.5以及之前的版本事件冒泡会跳过html标签,也就是说会直接从body冒泡到Document,而在IE9,firefox,chrome和safari浏览器则会将事件一直冒泡到window对象上。

           <!DOCUMENT html>
           <html>
               <head>
                   <title>HTML</title>
               </head>
               <body>
                   <p id="click">Click</p>
               </body>  
           </html>
    

    如果点击了p标签的元素,事件就会向上冒泡,依次为<p>,<body>,<html>,<Document>

    事件捕获

    即事件应该从不具体的节点先接收,然后再向更深层次的节点传播,以上述代码为例,如果是事件捕获,则Document对象会先捕获到事件,然后再沿着DOM树向下到html标签,body标签,最后到达p标签

    IE事件流

    1、IE事件流只支持事件冒泡,不支持事件捕获
    2、IE事件流可以通过可以通过attachEvent()和detachEvent()来添加和删除事件,这两个方法只接受两个参数,依次为 (target,handler),事件类型("on"+事件类型),事件处理函数,需要注意的一点是在使用detachEvent()方法删除事件时,参数要和创建事件时的参数相同,即第二个参数不支持通过匿名函数来创建,否则会被视为不是同一个方法。
        const btn = document.getElementById("button");
        btn.attachEvent("onclick",function(){
              console.log("click");
        })
    
         btn.detachEvent("onclick",function(){
               console.log("click");
         })
         //删除失败,尽管两个匿名函数一样,但是在处理时会被识别为两个不同的函数对象
    
    3、IE事件中的this指向的是window对象而不是目标元素对象,是因为在使用attachEvent()创建事件时,事件处理程序运行的作用于不是目标元素所在的作用域,而是在全局作用域中运行,所以this指向的是window而不是目标元素
    4、在IE事件流中,如果为一个元素顺序绑定多个事件,事件执行的顺序是按照逆序执行的。
          const btn = document.getElementById("button");
          btn.attachEvent("onclick",function(){
              console.log("one");
          })
    
          btn.attachEvent("onclick",function(){
              console.log("two");
          })
    
           btn.attachEvent("onclick",function(){
              console.log("three");
          })
    
          //出发事件的运行结果为
          //three
          //two
          //one
    
    5、IE事件中可以通过returnValue属性来阻止事件的默认行为,即将window.event.returnValue设置为false就可以阻止事件的默认行为,可以通过cancelBubble属性来停止事件的进一步传播,由于IE事件流只支持事件冒泡,所以该属性只能停止事件冒泡行为。

    W3C事件流

    1、W3C事件流支持事件捕获和事件冒泡
    2、W3C事件流可以通过可以通过addEventListener()和removeEventListener()来添加和删除事件,这两个方法接受三个参数,依次为 (target,handler,boolean),事件类型,事件处理函数,布尔值(如果设置为false,表示该事件处理函数在事件冒泡阶段触发,如果设置为true,表示该事件处理函数在事件捕获阶段触发,事件冒泡阶段不再触发)需要注意的一点是在使用removeEventListener()方法删除事件时,参数要和创建事件时的参数相同,即第二个参数不支持通过匿名函数来创建,否则会被视为不是同一个方法(同IE事件流规则相同)。
    3、W3C事件流中this指向的是目标元素的作用域,不同于IE事件处理程序的作用域为全局作用域,W3C事件流中的事件处理程序的作用域为目标元素所在的作用域,所以this指向的是目标元素。
    4、在W3C事件流中,如果为一个元素顺序绑定多个事件,事件执行的顺序是按照顺序执行的。
          const btn = document.getElementById("button");
          btn.attachEvent("onclick",function(){
              console.log("one");
          })
    
          btn.attachEvent("onclick",function(){
              console.log("two");
          })
    
           btn.attachEvent("onclick",function(){
              console.log("three");
          })
    
          //出发事件的运行结果为
          //one
          //two
          //three
    
    5、W3C事件中可以通过preventDefault()方法阻止事件的默认行为,可以通过stopPropagation()方法停止事件在DOM结构中进行传播,即停止事件继续冒泡或者捕获。
    6、还可以通过event对象的eventPhase属性来判断事件处于哪一个阶段,调用event.eventPhase,如果返回值为1,则事件处于捕获阶段,如果返回值为2,则事件处于目标阶段,如果返回值为3,则事件处于冒泡阶段。

    跨浏览器事件

       var EventUtil = {
    
            add:function(node,target,handler){
                if(node.addEventListener){
                    node.addEventListener(target,handler,false);
                }else if(node.attachEvent){
                    node.attachEvent("on"+target,handler);
                }else{
                    node["on"+target] = handler;
                }
            },
    
            remove:function(node,target,handler){
                if(node.removeEventListener){
                    node.removeEventListener(target,handler,false);
                }else if(node.detachEvent){
                    node.detachEvent("on"+target,handler);
               }else{
                   node["on"+target] = handler;
              }
            }
       }
    
       const btn = document.getElementById("button");
       EventUtil.add(btn,"click",function(){
           console.log("click");
       });
    

    可以通过调用对象EventUtil中的属性来实现添加事件和删除事件,每个属性中通过if-else 来判断浏览器兼容的事件处理程序实现简单的跨浏览器事件调用。

    事件委托

    事件委托是为处理过多的事件处理程序而设计的,事件委托采用事件冒泡,也就是说,如果想要为一个元素的所有子节点都添加一个事件处理程序的话,只需要获取该父节点的DOM即可,如果想要冒泡到document,也可以直接在document对象上添加事件,而不需要给每一个子节点一个一个添加事件处理程序,以下以W3C事件为例子

             var btn = document.getElementById("button");
             btn.addEventListener("click",function(event){
                      let target = event.target;              
                      switch(target.innerHTML){
                           case  "one":
                               console.log("one");
                               break;
                           case "two":
                               alert("two");
                               break;
                           case:"three":
                               localtion.href = "www.jianshu.com";
                               break;
                           default:
                               alert("undefined");
                                
             },false)
    

    使用事件委托,首先可以减少DOM操作,只需要获取最外层元素的节点即可,其次如果要对每一个元素都一一添加事件,会占用大量的内存,影响整个页面运行的性能,同时通过事件委托也可以提高添加事件的效率,上述实例仅通过switch-case语句就可以实现对于每一个子节点事件的添加,避免了使用一个个addEventListener()或者attachEvent()方法来为每一个子节点添加事件处理程序。

    相关文章

      网友评论

          本文标题:Javascript中的事件流(IE和W3C的区别)和事件委托

          本文链接:https://www.haomeiwen.com/subject/rputuqtx.html