Professional javascript For Web Developers 第2版读书笔记第5集event事件2

IE环境下的event对象

当以DOM0的方式指派事件处理函数时,event对象是作为window的属性存在的



var  btn  =  document.getElementById(“myBtn”);
btn.onclick 
=   function (){
    
var  event  =  window.event;
    alert(event.type);    
// ”click”
}; 


而如果使用attachEvent方法,则与DOM2下的event一样作为一个单独的参数传入函数中
var btn = document.getElementById(“myBtn”);
btn.attachEvent(“onclick”, function(event){
alert(event.type); //”click” });
 
此种方式下,window.event对象仍然存在,把它作为参数传入是为了使用的方便,IE环境下的event对象依然定义了
一些属性和方法,如下表

 

image


returnValue属性类似与DOM2中的preventDefault(),都可以用来取消事件的默认行为

var  link  =  document.getElementById(“myLink”);
link.onclick 
=   function (){
    window.event.returnValue 
=   false ;
}; 
 

cancelBubble属性对应DOM2中的stopPropagation()方法,来阻止事件冒泡

 

var  btn  =  document.getElementById(“myBtn”);
btn.onclick 
=   function (){
    alert(“Clicked”);
    window.event.cancelBubble 
=   true ;
};
            
document.body.onclick 
=   function (){
    alert(“Body clicked”);
}; 

 

 

Mouse事件类型的执行顺序

1.    mousedown
2.    mouseup
3.    click
4.    mousedown
5.    mouseup
6.    click
7.    dblclick

 

 

click和dbclick都受其他mouse事件的影响,如果取消了事件冒泡则可能会是这些事件无法触发

 

事件的性能问题

每个事件处理函数其实都是对象,它们会占用一定内存;大量的为DOM元素指定事件处理函数会推迟页面的交互。

解决此问题的一种途径是事件代理(event delegation)

 

<  ul  id =”myLinks”  >
    
<   li  id =”goSomewhere”   >   Go somewhere   <  /li  >
    
<   li  id =”doSomething”   >   Do something   <  /li  >
    
<   li  id =”sayHi”   >   Say hi   <  /li  >
<  /ul  >  


 

 

var  item1  =  document.getElementById(“goSomewhere”);
var  item2  =  document.getElementById(“doSomething”);
var  item3  =  document.getElementById(“sayHi”);
EventUtil.addHandler(item1, “click”, 
function (event){
    location.href 
=   " http://www.wrox.com  " ;
});
EventUtil.addHandler(item2, “click”, 
function (event){
    document.title 
=  “I changed the document ’ s title”;
});
EventUtil.addHandler(item3, “click”, 
function (event){
    alert(“hi”);
}); 


此例中ul的每个list元素都被绑定了事件处理函数,这种方式不仅代码很中,而且会多占用内存空间。

事件代理的方式如下

 

var  list  =  document.getElementById(“myLinks”);
EventUtil.addHandler(list, “click”, 
function (event){
    event 
=  EventUtil.getEvent(event);
    
var  target  =  EventUtil.getTarget(event);
    
switch (target.id){
        
case  “doSomething”:
            document.title 
=  “I changed the document ’ s title”;
            
break ;
        
case  “goSomewhere”:
            location.href 
=  “http: // www.wrox.com”;
             break ;
        
case  “sayHi”:
            alert(“hi”);
            
break ;
    }
}); 


 

只指派一个处理函数给ul,函数内部进行判断,因为li都是ul的后代,当后代的事件触发后,会冒泡到父节点,这种方式只访问一个对象,并只注册了一个事件处理函数。

 

借助与这种思想,如果将事件处理函数绑定在document对象上那是最好不过的了,因为

1.document对象是dom中最先被构造的,事件处理函数可以绑定在任何事件中而不需要等(DOMContentLoaded  or   load)

2.花费更少的时间绑定事件处理函数,只绑定一个事件处理函数占用较小的DOM对象引用和花费更少的时间

3.对页面来说占用很少的内存

最好的使用事件代理方式的候选事件有click , mousedown , mouseup , keydown , keyup  and keypress

 

处理性能问题的另外一种途径是当不再需要的时候移除事件处理程序。

因为当DOM中某个元素绑定一个事件处理程序,而这个元素又被移除掉的话,这个对于事件处理程序的引用却一直存在,一般是调用removeChild()  or   replaceChild(),但最常见的是使用innerHtml属性替换,指派了事件处理程序后又被innerHTML替换后的元素常常不能正确的被垃圾回收

 

<  div  id =”myDiv”  >  
     
<  input  type =”button”  value =”Click  Me” id =”myBtn”  >  
 
<  /div  >  
 
<  script  type =”text/javascript”  >  
    var btn = document.getElementById(“myBtn”);
    btn.onclick = function(){
            
        //do something
            
        document.getElementById(“myDiv”).innerHTML = “Processing...”;  //Bad!!!
    };
 
<  /script  >  


此例中button会被移除,但是button的onclick处理函数间的引用关系仍然存在,这种情况对IE浏览器来说是很不好的情况,因为IE会在内存在为元素和处理函数都分配内存,因此当发生这种情况时,最好手动移除事件处理程序

 

<  div  id =”myDiv”  >
    
<  input  type =”button”  value =”Click  Me” id =”myBtn”  >
<  /div  >
<  script  type =”text/javascript”  >
   var btn = document.getElementById(“myBtn”);
   btn.onclick = function(){
       //do something
       btn.onclick = null;   //remove event handler
       document.getElementById(“myDiv”).innerHTML = “Processing...”;
   };
<  /script  >  


 

如果一直悬挂着事件处理函数,那么在页面unload时可能会有问题,如果事件处理函数在页面unload前没有被清理,有可能一直驻留内存,每次由于点击浏览器导航栏中前进,后退或者刷新可能会频繁的让页面load与unload,这样大量的对象会在内存中创建而得不到释放,因为事件处理程序所占用的内存没有被收回。因此一个好的解决方案是在每次onunload事件中移除所有的事件处理函数,但是需要住的是,用这种方式时,对firefox来说onunload会使页面不会保存在bfcache(这是ff的一个页面缓存机制),因此要小心使用.

 

 

事件模拟

1.DOM2事件模拟

首先调用createEvent接受一个参数表示事件类型,可以是以下值

  UIEvents   —  Generic UI event. Mouse events and keyboard events inherit from UI events.
  MouseEvents   —  Generic mouse event.
  MutationEvents   —  Generic DOM mutation event.
  HTMLEvents   —  Generic HTML event.  

然后对返回的event对象附加相应的事件信息

 

最后是调用dispatchEvent()方法触发事件,这时就和正常触发的效果一样了。

 

模拟鼠标事件的话首先创建事件对象,然后返回的对象有个initMouseEvent()方法来附加event对象信息,这个方法有15个参数:

  type  (string)  —  The type of event to fire, such as    “ click ”   .
  bubbles  (Boolean)  —  Indicates if the event should bubble. This should be set to   true  for
accurate mouse event simulation.
  cancelable  (Boolean)  —  Indicates if the event can be canceled. This should be set to   true  for
accurate mouse event simulation.
  view  (AbstractView)   —  The view associated with the event. This is almost always   document
.defaultView .
  detail  (integer)  —  Additional information for the event. This is used only by event handlers,
though it’s typically set to 0.
  screenX  (integer)  —  The x - coordinate of the event relative to the screen.
  screenY  (integer)  —  The y - coordinate of the event relative to the screen.
  clientX  (integer)  —  The x - coordinate of the event relative to the viewport.

clientY  (integer)  —  The y - coordinate of the event relative to the viewport.
ctrlKey  (Boolean)  —  Indicates if the Ctrl key is pressed. The default is   false .
altKey  (Boolean)  —  Indicates if the Alt key is pressed. The default is   false .
shiftKey  (Boolean)  —  Indicates if the Shift key is pressed. The default is   false .
metaKey  (Boolean)  —  Indicates if the Meta key is pressed. The default is   false .
button  (Integer)  —  Indicates the button that was pressed. The default is 0.
relatedTarget  (Object)  —  An object related to the event. This is used only when simulating
mouseover  or   mouseout . 

其中前面的4个最关键,因为它们是由浏览器使用的,其他的信息只有事件处理函数使用到,target参数

当调用dispatchEvent会自动设置,如:

 

var  btn  =  document.getElementById(“myBtn”);
// create event object
var  event  =  document.createEvent(“MouseEvents”);
// initialize the event object
event.initMouseEvent(“click”,  true true , document.defaultView,  0 0 0 0 0 ,
                     
false false false false 0 null );
// fire the event
btn.dispatchEvent(event); 


 

 

Safari在3版之前不是完全支持鼠标事件initEvent3个参数分别为:事件类型,是否支持冒泡,冒泡能否取消,此时用UIEvent模拟


// hack for Safari 2.x
var  btn  =  document.getElementById(“myBtn”);
// create event object
var  event  =  document.createEvent(“UIEvents”);
// initialize the event object
event.initEvent(“click”,  true true );
// assign additional information

event.view 
=  document.defaultView;
event.detail 
=   0 ;
event.screenX 
=   0 ;
event.screenY 
=   0 ;
event.clientX 
=   0 ;
event.clientY 
=   0 ;
event.ctrlKey 
=   false ;
event.altKey 
=   false ;
event.metaKey 
=   false ;
event.shiftKey 
=   false ;
event.button 
=   0 ;
event.relatedTarget 
=   null ;
// fire the event
btn.dispatchEvent(event); 


 

键盘事件在DOM2的草图版本中是有的,可是最终版却移除了,但是firefox却实现了起初的草图版本

模拟的方式为创建一个KeyEvent类型的event对象,然后调用initKeyEvent(),此方法接受10个参数

  type  (string)  —  The type of event to fire, such as    “ click ”   .
  bubbles  (Boolean)  —  Indicates if the event should bubble. This should be set to   true  for
accurate mouse event simulation.
  cancelable  (Boolean)  —  Indicates if the event can be canceled. This should be set to   true  for
accurate mouse event simulation.
  view  (AbstractView)   —  The view associated with the event. This is almost always   document
.defaultView .
  ctrlKey  (Boolean)  —  Indicates if the Ctrl key is pressed. The default is   false .
  altKey  (Boolean)  —  Indicates if the Alt key is pressed. The default is   false .

    shiftKey  (Boolean)  —  Indicates if the Shift key is pressed. The default is   false . 
    metaKey  (Boolean)  —  Indicates if the Meta key is pressed. The default is   false . 
    keyCode  (integer)  —  The key code of the key that was pressed or released. This is used for
  keydown  and   keyup . The default is 0. 
    charCode  (integer)  —  The ASCII code of the character generated from the key press. This is
used for   keypress . The default is 0.

 

因此火狐模拟的方式为:

// for Firefox only
var  textbox  =  document.getElementById(“myTextbox”);
// create event object
var  event  =  document.createEvent(“KeyEvents”);
// initialize the event object
event.initKeyEvent(“keypress”,  true true , document.defaultView,  false false ,
                   
false false 65 65 );
// fire the event
textbox.dispatchEvent(event); 


 

 

对于其他如safari的浏览器要创建一个更宽泛的event对象,然后指定相应的键盘信息
var  textbox  =  document.getElementById(“myTextbox”);
// create event object
var  event  =  document.createEvent(“Events”);
// initialize the event object
event.initEvent(type, bubbles, cancelable);
event.view 
=  document.defaultView;
event.altKey 
=   false ;
event.ctrlKey 
=   false ;
event.shiftKey 
=   false ;
event.metaKey 
=   false ;
event.keyCode 
=   65 ;
event.charCode 
=   65 ;
// fire the event
textbox.dispatchEvent(event); 


 

 

 

2.IE环境下的事件模拟

没有initEvent方法,因此需要手动附加信息,因此可以添加额外的信息,同时IE下创建的是一个更宽泛的event对象,可以用来对任意的事件类型进行模拟,fireEvent被调用时,  srcElement和 type属性自动附加到event对象上

var  btn  =  document.getElementById(“myBtn”);
// create event object
var  event  =  document.createEventObject();
// initialize the event object
event.screenX  =   100 ;
event.screenY 
=   0 ;
event.clientX 
=   0 ;
event.clientY 
=   0 ;
event.ctrlKey 
=   false ;
event.altKey 
=   false ;
event.shiftKey 
=   false ;
event.button 
=   0 ;
// fire the event
btn.fireEvent(“onclick”, event); 


 

你可能感兴趣的:(JavaScript)