zoukankan      html  css  js  c++  java
  • 事件流,事件处理程序,事件对象

    1.事件流

    事件流描述的是从页面接收事件的顺序。

    1.1 事件冒泡:即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。

    1.2 事件捕获:事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件,事件捕获的用意在于在时间到达预定目标之前捕获它。

    1.3 DOM事件流

    DOM2级事件规定的事件流包括三个阶段:事件捕获阶段,处理目标程序阶段和事件冒泡阶段。

    IE9,Opera,Firefox,Chorme和Safari都支持DOM事件流;IE8及更早版本不支持DOM事件流。

    2.事件处理程序

    事件就是用户或浏览器自身执行的某种动作。

    而响应某个时间的函数就叫做事件处理程序(或事件侦听器)。

    2.1 HTML事件处理程序

      某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的HTML特性来指定。这个特性的值应该是能够执行的JavaScript代码。

    1 <!--Clicked不能用双引号-->
    2     <input type="button" value="Click Me" onclick="alert('Clicked')"></input>

    在HTML中定义的事件处理程序可以包含要执行的具体动作,也可以调用在页面其他地方定义的脚本,如下代码所示:

    1 <script type="text/javascript">
    2         function showMessage(){
    3             alert("Hello world!");
    4         }
    5     </script>
    6     <input type="button" value="Click Me" onclick="showMessage()" />

    在HTML中指定事件处理程序有三个缺点

     (1)时差问题。因为用户可能会在HTML元素一出现在页面上就触发相应的事件,当时的事件处理程序可能不具备执行的条件(此时会引发错误)。为此,很多HTML事件处理程序都会封装在一个try-catch块中,此时错误就可以被捕获了。前面的代码可改进如下:

    1 <input type="button" value="Click Me" onclick="try{showMessage();}catch(ex){}" />

     (2)这样扩展事件处理程序的作用域链在不同浏览器中会导致不同结果。

     (3)HTML与JavaScript代码紧密耦合。如果要更换事件处理程序,就要改动两个地方。

    2.2 DOM0级事件处理程序

    通过JavaScript指定事件处理程序的传统方法,就是将一个函数赋值给一个事件处理程序属性。

    每个元素(包括window和document)都有自己的事件处理程序属性,这些属性通常全部小写,如onclick。将这种属性的值设为一个函数,就可以指定事件处理程序。

    1 var btn=document.getElementById("myBtn");
    2         btn.onclick=function(){
    3             alert("Clicked");
    4         };

    注意:在这些代码运行前不会指定事件处理程序,因为如果这些代码在页面中位于按钮后面,就有可能在一段时间内怎么点击都没有反应。

    使用DOM0级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行;换句话说,程序的this引用当前元素。

    1 var btn=document.getElementById("myBtn");
    2         btn.onclick=function(){
    3             alert(this.id);//"myBtn"
    4         };

    也可以删除通过DOM0级方法指定的事件处理程序:

    1 btn.onclick=null;  //删除事件处理程序

    如果使用的是HTML指定时间处理程序,那么onclick属性的值就是一个包含着在同名HTML特性中指定的代码的函数。将相应的属性设为null,也可以删除以这种方式指定的事件处理程序。

    2.3 DOM2级事件处理程序

    DOM2级事件定义了两个方法。用于处理指定和删除事件处理程序的操作:addEventListener()和removeEventListener()。所有DOM节点都包含这两个方法,并且他么都接受3个参数。要处理的事件名、作为事件处理程序的函数和一个布尔值。布尔值中true表示在捕获阶段调用事件处理程序;false表示在冒泡阶段调用事件处理程序。

    用DOM2级方法添加事件处理程序的好处是可以添加多个事件处理程序:

    1 var btn=document.getElementById("myBtn");
    2         btn.addEventListener("click",function(){
    3             alert(this.id);
    4         },false);
    5         btn.addEventListener("click",function(){
    6             alert("Hello world!");
    7         },false);

    通过addEventListener()添加的事件处理程序只能通过removeEventListener()方法移除。移除是传入的参数与添加时传入的参数要相同。这也意味中通过addEventListener()添加的匿名函数无法移除。

    1 var btn=document.getElementById("myBtn");
    2         btn.addEventListener("click",function(){
    3             alert(this.id);
    4         },false);
    5         btn.removeEventListener("click",function(){
    6             alert(this.id);
    7         },false);//没用用!看似传入了相同的参数,其实这里的第二个参数与addEventListener()中的第二个参数是完全不同的函数

    因此应该像下面这种写法:

    1 var btn=document.getElementById("myBtn");
    2        var handler=function(){
    3            alert(this.id);
    4        };
    5         btn.addEventListener("click",handler,false);
    6         btn.removeEventListener("click",handler,false);


    IE9,Opera,Firefox,Chorme和Safari支持DOM2级事件处理程序。

    2.4 IE事件处理程序

    IE实现了与DOM中类似的两个方法:attachEvent()和detachEvent()。这两个方法接收相同的两个参数:事件处理程序名称和事件处理程序函数。由于IE8及更早版本只支持事件冒泡,所以通过attachEvent()添加的事件处理程序都会被添加到冒泡阶段。

     var btn=document.getElementById("myBtn");
            btn.attachEvent("onclick",function(){
                 alert(this.id);
             });

    在IE中使用attachEvent()与使用DOM0级方法的主要区别是事件处理陈旭的作用域。DOM0中是在元素的作用域内运行;在attachEvent()中是在全局作用域内运行,因此this=window。

    1 var btn=document.getElementById("myBtn");
    2         btn.attachEvent("onclick",function(){
    3              alert(this===window);  //true
    4          });

    与addEventListener()类似,attachEvent()也可以用来为一个元素添加多个事件处理程序。不同的是attachEvent()不是以添加事件的顺序执行,而是以相反的顺序执行。同样的用attachEvent()添加的时间如果是匿名函数则不能移除,否则可以用detachEvent()方法移除。

    2.5 跨浏览器的事件处理程序

    使用能力检测来隔离浏览器的差异。要保证处理事件的代码能在大多数浏览器下一致的运行,只需关注冒泡阶段。

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

    可以用像如下代码这样使用以上两个方法:

    1  var btn=document.getElementById("myBtn");
    2     var handler=function(){
    3         alert("Clicked");
    4     };
    5     EventUtil.addHandler(btn,click,handler);
    6     //其他代码
    7     EventUtil.removeHandler(btn,click,handler);

    addHandler()和removeHandler()没有考虑到所有的浏览器问题,例如IE中的作用域问题。不过,使用它们添加和移除事件处理程序还是足够了。此外还要注意,DOM0级对每个事件只支持一个事件处理。好在支持DOM0级的浏览器已经不多了。

      

    3. 事件对象

    在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。

    3.1 DOM中的事件对象

    event对象包含与创建它的特定事件有关的属性和方法。出发的事件类型不一样,可用的属性和方法也不一样。

    属性/方法 类型 读/写 说明
    bubbles Boolean 只读 表明事件是否冒泡
    cancelable Boolean 只读 表明是否可以取消事件的默认行为
    currentTarget Element 只读 其事件处理程序当前正在处理时间的那个元素
    defaultPrevented Boolean 只读 为true表示已经调用了preventDefault()(DOM3级事件新增)
    detail Integer 只读 与事件相关的细节信息
    eventPhase Integer 只读 调用事件处理程序的阶段:1表示捕获阶段,2表示"处于目标",3.表示冒泡阶段
    preventDefault() Function 只读 取消事件的默认行为。如果cancelable是true,则可以使用这个方法
    stopImmediatePropagation() Function 只读 取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用(DOM3级事件新增)
    stopPropagation() Function 只读 取消事件的进一步捕获或冒泡,同如果bubbles为true,则可以使用这个方法。
    target Element 只读 事件的目标
    trusted Boolean 只读 为true表示事件是浏览器生成的。为false表示事件是由开发人员通过JavaScript创建的(DOM3级事件中新增)
    type String 只读 被触发的事件的类型
    view AbstractView 只读 与事件关联的抽象视图。等同于发生事件的window对象

    在事件处理程序内部,对象this始终等于currentTarget的值,而target则只包含事件的实际目标。

    1  document.body.onclick=function(event){//表示点击按钮时冒泡到Body中后的效果
    2         alert(event.currentTarget===document.body);  //true
    3         alert(this===document.body);         //true
    4         alert(event.target===document.getElementById("myBtn"));    //true
    5     }

     当单机到这个例子中的按钮时,this和currentTarget都等于document.body,因为事件处理程序是注册到这个元素上的。然而,target元素却等于按钮元素,因为它是click事件真正的目标。

    在需要通过一个函数处理多个事件时,可以使用type属性。如下:

     1  var btn=document.getElementById("myBtn");
     2     var handler=function(event){
     3         switch(event.type){
     4             case "click":
     5             alert("Clicked");
     6             break;
     7 
     8             case "mouseover":
     9             event.target.style.backgroundColor="red";
    10             break;
    11 
    12             case "mouseout":
    13             event.target.style.backgroundColor="";
    14             break;
    15         }
    16     };
    17 
    18     btn.onclick=handler;
    19     btn.onmouseover=handler;
    20     btn.onmouseout=handler;

    要阻止特定事件的默认行为,可以使用preventDefault()方法。例如,链接的默认行为就是在被单击时会导航到其href特性指定的URL。如果你想阻止链接导航这一默认行为,那么通过链接的onclick事件处理程序可以取消它

    1 var link=document.getElementById("myLink");
    2     link.onclick=function(event){
    3         event.preventDefault();
    4     }

    只有cancelable属性设置为true的事件,才可以使用preventDefault()来取消其默认行为。

    stopPropagation()方法用于立即停止事件在DOM层次中的传播,即取消进一步的事件捕获或冒泡。

    var btn=document.getElementById("myBtn");
        btn.onclick=function(event){
        	alert("Clicked");
        	event.stopPropagation();
        };
        document.body.onclick=function(event){
        	alert("Body clicked");
        };
    

      对于这个例子而言,因为调用了stopPropagation(),所以在单价按钮时click事件不会传播到document.body。

    事件对象的eventPhase属性,可以用来确定事件当前正位于事件流的哪个阶段。

    var btn=document.getElementById("myBtn");
        btn.onclick=function(event){
            alert(event.eventPhase);  //2
        };
        document.body.addEventListener("click",function(event){
            alert(event.eventPhase);   //1
        },true);
        document.body.onclick=function(event){
            alert(event.eventPhase);   //3
        };

    当单击按钮时,首先执行的事件处理程序是在捕获阶段触发的添加到document.body中的那一个,所以会先弹出表示eventPhase的1 。接着会触发按钮上注册的事件处理程序,此时的eventPhase的值为2。最后一个被触发的事件处理程序,是在冒泡阶段执行的添加到document.body上的那一个,显示的值是3。当eventPhase的值为2时,this、target、和currentTarget始终是相等的。

    3.2 IE中的事件对象

     在使用DOM0级方法添加事件处理程序时,event对象作为window对象的一个属性存在。 

    var btn=document.getElementById("myBtn");
        btn.onclick=function(){
            var event=widnow.event;
            alert(event.type);  //"click"
        };

    IE事件对象会包含下表所列的属性和方法

    属性/方法 类型 读/写 说明
    cancelBubble Boolean 读/写 默认值为false,但将其设置为true就可以取消事件冒泡(与DOM中的stopPropagation()方法的作用相同)
    returnValue Boolean 读/写 默认值为true,但假期设置为false就可以取消事件的默认行为(与DOM中的preventDefault()方法的作用相同)
    srcElement Element 只读 事件的目标(与DOM中的target属性相同)
    type String 只读 被触发的事件的类型

    因为事件处理程序的作用域是根据指定它的方式来确定的,所以不能认为this会始终等于事件目标,最好使用event.srcElement比较保险 。

    1 var btn=document.getElementById("myBtn");
    2     btn.onclick=function(){
    3         alert(window.event.srcElement===this);   //true
    4     };
    5     btn.attachEvent("onclick",function(event){
    6       alert(event.srcElement===this);     //false
    7     });

    3.3 跨浏览器的事件对象

     1  var EventUtil={
     2 
     3         addHandler:function(element,type,handler){
     4             //省略,上面代码有
     5         },
     6 
     7         getEvent:function(event){
     8             return event?event:window.event;
     9         },
    10         getTarget:function(event){
    11             return event.target||event.srcElement;
    12         },
    13         preventDefault:function(event){
    14             if(event.preventDefault){
    15                 event.preventDefault();
    16             }else{
    17                 event.returnValue=false;
    18             }
    19         },
    20 
    21         removeHandler:function(element,type,handler){
    22             //省略
    23         },
    24 
    25         stopPropagation:function(event){
    26             if(event.stopPropagation){
    27                 event.stopPropagation();
    28             }else{
    29                 event.cancelBubble=true;
    30             }
    31         }
    32     };
  • 相关阅读:
    二进制位运算
    Leetcode 373. Find K Pairs with Smallest Sums
    priority_queue的用法
    Leetcode 110. Balanced Binary Tree
    Leetcode 104. Maximum Depth of Binary Tree
    Leetcode 111. Minimum Depth of Binary Tree
    Leetcode 64. Minimum Path Sum
    Leetcode 63. Unique Paths II
    经典的递归练习
    案例:java中的基本排序
  • 原文地址:https://www.cnblogs.com/luoyanan/p/5470213.html
Copyright © 2011-2022 走看看