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

事件流(event flow)

如果一张纸上有一组同心圆(我们可以认为是大圆嵌套着小圆),当你用手指放在纸的中间(圆心), 我们应该认为你所碰到的不仅仅是哪一个圆,而是所有的圆,因为你的手指处在所有圆的范围内,也就是说你不光指向了最里面的圆,同时指向了它的容器(大圆认为是容器,小圆嵌套在里面),然后向上递归。

同样的道理,如果你在页面上点击了一个按钮,那就不仅仅是点击了这个按钮,也同时点击了这个按钮所在的容器 。

 

IE和 Netscape Communicator实现事件流的方式不一样。IE是冒泡流(Event Bubbling),而Netscape Communicator是捕捉流(event capturing flow)

 

冒泡流是从最具体的元素开始向上冒泡依次触发相应的事件。如

 < html > 
 
< head > 
     
< title >  Event Bubbling Example  < /title > 
 
< /head > 
 
< body > 
     
<  div id=”myDiv”  >  Click Me  < /div > 
 
< /body > 
 
< /html > 

单击div元素的时候,div元素的click事件会被触发,然后依次按照dom树的顺序向上触发

 

IE5.5及之前的版本会跳过HTML元素,即从body直接跳到Document元素。Firefox,Chrome,Safari均实现冒泡事件流,并按刚才的顺序递归一直到window对象。

 

而捕捉流与冒泡流顺序相反

 Firefox,Chrome,Safari也支持捕捉流,并且从window对象开始捕捉,然而DOM2的标准中事件应该从document开始

 

 DOM事件流

此方式定义在DOM2的规格说明中,包括3个阶段:捕获event capturing,触发目标hit the target,冒泡 Event Bubbling

DOM2中定义捕获阶段不触发目标,拿上面的例子来说从document到body后此截断便停止。

 然而Safari, Chrome, Firefox, and Opera 9.5以及后续版本都在捕获截断会触发目标,意味着有2次机会来和目标交互。同时IE不支持DOM event flow

 

DOM0事件处理

事件处理作为元素element的一种属性存在,可以直接指派处理函数,同时时间处理函数的作用域都是元素本身,因此this指向的是当前元素

如:

var btn = document.getElementById(“myBtn”);
btn.onclick 
= function(){
    alert(“Clicked”);
}; 

 

移除事件处理程序

btn.onclick = null;    //remove event handler 


 DOM2事件处理

 addEventListener() 和 removeEventListener() 方法注册和移除处理函数。它们都接受3个参数分别为:事件名,处理函数,一个bool类型指明是在捕获流中还是在冒泡流中调用事件处理程序,true表示在捕获流,false表示在冒泡流。

 使用addEventListener()还可以为某个事件注册多个处理程序,按照他们注册的顺序一次执行,如

var btn = document.getElementById(“myBtn”);
btn.addEventListener(“click”, 
function(){
    alert(
this.id);
}, 
false);
btn.addEventListener(“click”, 
function(){
    alert(“Hello world
!”);
}, 
false); 


同时用addEventListener()注册的处理函数必须用removeEventListener()才可以移除,但是此处理函数不能是匿名函数,因为没有指针指向此匿名函数,如

var btn = document.getElementById(“myBtn”);
btn.addEventListener(“click”, 
function(){//事件名没有on前缀,这和DOM0不同
    alert(
this.id);
}, 
false);
            
//other code here
            
btn.removeEventListener(“click”, 
function(){   //won ’ t work!
    alert(this.id);
}, 
false); 

虽然这2个匿名函数内容一样,但是它们不是同一个函数。

 

要实现移除

var btn = document.getElementById(“myBtn”);
var handler = function(){
    alert(
this.id);
};
btn.addEventListener(“click”, handler, 
false);
            
//other code here
            
btn.removeEventListener(“click”, handler, 
false);  //works!  


 IE事件处理

 IE通过attachEvent()和detachEvent()来绑定和移除处理函数,ie仅支持冒泡流,这些方法仅2个参数:事件名、处理函数

 

var btn = document.getElementById(“myBtn”);
btn.attachEvent(“onclick”, 
function(){
    alert(“Clicked”);
}); 

与DOM0方式不同,attachEvent绑定的函数运行的作用域是全局的即window对象,而不是所绑定给的元素对象。

var btn = document.getElementById(“myBtn”);
btn.attachEvent(“onclick”, 
function(){
    alert(
this === window);   //true
}); 

attachEvent也可以绑定多个处理函数,但是当调用的时候执行的顺序和绑定的顺序相反

var btn = document.getElementById(“myBtn”);
btn.attachEvent(“onclick”, 
function(){
    alert(“Clicked”);
});
btn.attachEvent(“onclick”, 
function(){
    alert(“Hello world
!”);

 //先弹出hello world 然后弹出clicked


 移除处理程序detachEvent,使用方式和DOM中的removeEventListener一样,也是注意不要使用匿名函数

 

注意,要避免使用dom0+dom2或者dom0+ie(attachevent)混合的方式

dom0+dom2混合的方式注册处理函数,那么函数执行的顺序跟它们注册的顺序相同

 

        var obj=document.getElementById('mydiv');
        
        obj.addEventListener(
'mousedown',Func2,false);
        
        obj.addEventListener(
'mousedown',Func3,false);
     obj.onmousedown=Func1;


如果是IE+DOM0,始终先执行DOM0方式注册的函数,然后attachEvent中注册的函数按照逆序(类似桟的后进先出)执行

var obj=document.getElementById('mydiv');
       
//obj.onmousedown=Func1;
        obj.attachEvent(
'onmousedown',Func2);
        //obj.onmousedown=Func1;
        obj.attachEvent(
'onmousedown',Func3);
        obj.onmousedown
=Func1;//无论DOM0方式在哪注册,最后都是在事件触发的时候最先执行


 因此要避免这种混合使用的方式,它会给浏览器兼容性带来很大的麻烦

 

 

 Event对象

不论DOM0还是DOM2中事件处理函数都能传递一个event参数,此参数包括了关于此事件的相关信息,需要注意的事,必须显式的才处理函数中声明event,代码才可以访问到event的属性和函数,当然参数的名不一定非要是"event",任何符合规范的参数名都可以

 

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


与event相关的函数和 (此表显示的是所有类型元素再触发事件时event对象拥有的)

 

 如果事件处理程序是直接指派给相应的元素,那么event对象的target和currentTarget指向触发此事件的元素,同时this在函数内部也指向同样的元素,如:

var btn = document.getElementById(“myBtn”);
btn.onclick 
= function(event){
    alert(event.currentTarget 
=== this);   //true
    alert(event.target === this);          //true
}; 


如果处理处理函数被注册到触发元素的父节点上,情况有所不同

document.body.onclick = function(event){
    alert(event.currentTarget 
=== document.body);   //true
    alert(this === document.body);                  //true
    alert(event.target === document.getElementById(“myBtn”)); //true
}; 

this和currentTarget指向了注册此事件的元素document.body,而target指向真正触发此事件的元素button,因为此button没有指派事件处理程序,因此单击事件被冒泡到了document.body来处理。

 

 preventDefault用来阻止默认的行为,如链接元素a被单击的时候会导向一个新页面,如果要阻止这样的行为

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

 那些 cancelable为true的元素才可以通过preventDefault来取消默认行为

 

 stopPropagation()函数用来取消事件流的扩散,可以取消捕获流或者冒泡流

 

 eventPhase表示处理程序处于哪个事件流中,1标识捕获流,2标识at the target,3标识事件流,值得注意的是尽管"at the target"处于冒泡阶段,但它的eventPhase=2

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
}; 


event仅在事件处理函数中存在,当处理函数执行完毕,event对象偏会销毁

 

 

 

posted on 2010-08-04 10:34  MoonWalker  阅读(236)  评论(0编辑  收藏  举报

导航