《JavaScript高级程序设计 第三版》学习笔记 (十一)事件详解

来源:互联网 发布:免费刷超级会员软件 编辑:程序博客网 时间:2024/05/01 10:38

一、事件流

1.事件冒泡:事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。最早使用事件冒泡的是IE,现在绝大多数浏览器都使用冒泡。IE9、Firefox、Chrome、Safari都将事件冒泡到window。
2.事件捕获:事件捕获是由不太具体的节点先接收事件,而最具体的节点最后接收事件。顺序与事件冒泡刚好相反。IE9、Safari、Chrome、Opera都支持这种事件类型。
3.DOM2级事件:DOM2规定事件流包括三个阶段,捕获阶段,为截获事件提供了机会;实际目标接收处理阶段;冒泡阶段,可以在这个阶段对事件做响应。如果在捕获阶段,上层DOM把事件拦下,那么实际DOM的事件就不能触发。具体流程见下图。

二、事件处理程序

1.DOM1级,只能通过element.onclick=function(){}这种形式添加处理,也就是说,只能像一个事件上绑定一个处理程序。
2.DOM2级,可以使用addEventListener和removeEventListener添加或删除事件处理程序。addEventListener有三个参数:事件类型、处理程序、是否在捕获阶段调用事件处理程序(默认false)。下面例子说明了第三个参数的作用。设置为true时,控制台依次输出box1到box4,说明事件处理是在捕获阶段执行的,div1先捕获到click,执行处理程序,然后div2再捕获到。设置为false时,依次输出box4到box1,即捕获阶段谁都不处理事件,最内层的div4捕获后,没有下一层了,开始处理,然后事件开始冒泡,div3开始处理。DOM2级可以在一个事件上绑定多个处理程序。removeEventListener如果第二个参数是新函数而不是之前添加的函数引用,则完全不其作用。所以如果想把事件remove掉,add的时候只能传函数引用进去。
[html] view plain copy
  1. //小实验,事件关于addEventListener的第三个参数。  
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  3. <html xmlns="http://www.w3.org/1999/xhtml">  
  4. <head>  
  5. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
  6. <title>addEventListener</title>  
  7. <style>  
  8. div{position:absolute;}  
  9. #box1{left:50px;top:60px;height:50px;width:500px;height:500px;background-color:#00F;}  
  10. #box2{left:50px;top:50px;height:50px;width:400px;height:400px;background-color:#09C;}  
  11. #box3{left:50px;top:50px;height:50px;width:300px;height:300px;background-color:#393;}  
  12. #box4{left:50px;top:50px;height:50px;width:200px;height:200px;background-color:#9C6;}  
  13. </style>  
  14. </head>  
  15. <body>  
  16. <div id="box1">  
  17.     <div id="box2">  
  18.         <div id="box3">  
  19.             <div id="box4"></div>  
  20.         </div>  
  21.     </div>  
  22. </div>  
  23. <script language="javascript">  
  24.     var boxes=document.getElementsByTagName("div");  
  25.     var useCapture=true;  
  26.     var clickHandler=function(){  
  27.         console.log(this.id);  
  28.     }  
  29.     for(var n=0;n<boxes.length;n++){  
  30.         boxes[n].addEventListener("click",clickHandler,useCapture);  
  31.     }  
  32. </script>  
  33. </body>  
  34. </html>  
3.老版本IE,使用attachEvent和detachEvent来添加和删除事件处理程序,因为老IE(<9)只支持事件冒泡,不支持事件捕获,所以没有第三个参数。attachEvent和addEventListener还有一个重要区别是,前者的事件类型必须含有on,而后者没有,如onclick对应click。

三、事件对象

1.每个事件处理程序,其实都是一个回调函数,回调时默认传入一个event参数,这是一个保存了事件各种信息的对象。
2.event.type表示事件的类型;event.target表示事件的对象,相当于this;这两个最为常用,尤其是在写通用事件处理程序时。
3.event.preventDefault()可以阻止事件的默认行为,比如链接在点击的时候会跳转到href标明的地址,用这个方法可以阻止这种跳转。4.event.stopPropagation()可以阻止事件在事件流中传播,下面这个例子,div3和div4的click都不会触发。
[javascript] view plain copy
  1. //小实验,阻止事件传播  
  2. var boxes=document.getElementsByTagName("div");  
  3. var useCapture=true;  
  4. var clickHandler=function(){  
  5.     console.log(this.id);  
  6.     if(this.id=="box2"){  
  7.         event.stopPropagation();      
  8.     }  
  9. }  
  10. for(var n=0;n<boxes.length;n++){  
  11.     boxes[n].addEventListener("click",clickHandler,useCapture);  
  12. }  
5.在老版本IE中,如果使用element.onclick=function(){}这种形式注册处理事件,可以通过window.event获取事件对象;使用attachEvent则和addEventListener一样,在回调函数中添加一个event形参即可。老版本IE中,event.srcElement相当于event.target;event.returnValue=false相当于event.preventDefault();event.cancelBubble=false相当于event.stopPropagation()。

四、事件类型

1.一些标准的标签有load事件,表示已经加载完成,如body、image;还有一些标签以非标准形式支持load,如script。因此,可以用这个事件判断js脚本是不是动态加载完成了。
2.焦点事件blur、focus与其他事件有一定差异,因为他们不会冒泡。focusin是focus的通用版本、focusout是blur的通用版本。
3.DOM3级将mouseenter和mouseleave纳入了规范,这两个事件不会冒泡,而且鼠标移动到后代元素上不会出发。jQuery很早就支持了这两个事件。相比mouseover和mouseout,这两个事件简直太有用、太方便了。
4.关于鼠标事件中的鼠标位置:clientX/Y是相对于可视区域左上角的坐标(不算滚动条);pageX/Y是相对于页面左上角的坐标(包含了滚动条);screenX/Y是相对于显示器左上角的坐标;offsetX/Y是相对与触发元素的左上角的坐标。

五、内存与性能

1.绑定过多是事件处理程序,必然会消耗内存,延迟整个页面响应时间。
2.解决事件过多的问题,可以使用“事件委托”。比如所有的click最终都会冒泡的document,那么理论上只要在document绑定一个click事件,整个页面的类似事件就都能处理了。这样能减少很多内存占用。不是所有事件都能使用委托,只有冒泡的才能使用,最合适做委托的有:click、mousedown、mouseup、keydown、keyup、keypress。
[javascript] view plain copy
  1. //小实验 事件委托  
  2. document.body.addEventListener("click",function(event){  
  3.     console.log(event.target.id);     
  4. });  
3.在不需要事件处理程序的时候,把它移除,是比较好的选择。比如一个按钮控制是否可以在canvas上通过鼠标画图,那么完全可以在按钮的click中为canvas添加或删除各种鼠标事件,而不是在canvas的鼠标事件中判断一个boolean开关是否为true。

六、自定义事件

1.可以通过event=document.createEvent(eventName)自定义事件类型,创建后会产生一个initEventName方法。
2.通过event.initEventName()初始化事件对象。
3.通过element.dispatchEvent(event)触发事件。
[javascript] view plain copy
  1. //小实验 自定义事件  
  2. var div=document.getElementById("box1");  
  3. div.addEventListener("mousemove",function(event){//触发自定义事件  
  4.     if(event.offsetX<10 && event.offsetY<10){  
  5.         var myevent=document.createEvent("CustomEvent");  
  6.         myevent.initCustomEvent(  
  7.             "MyEvent",//type  
  8.             true,//bubbles  
  9.             true,//cancelable  
  10.             {text:"hello"}//detail  
  11.         );    
  12.         this.dispatchEvent(myevent);  
  13.     }  
  14. })  
  15. div.addEventListener("MyEvent",function(event){//处理自定义事件  
  16.     console.log(event.detail.text);  
  17. });  
4.上面的例子,自定义了MyEvent事件,当鼠标移动到某个div的左上角10*10像素内时触发。
0 0
原创粉丝点击