事件的侦听、移除和事件对象解析

Javascript的事件处理模型依据不同的浏览器而有所区别,主要分两种:
1.Firefox,Chrome,Safira支持的DOM Level 2事件模型;
2.IE自己的事件处理模型。
而 DOM Level 0 则是所有浏览器都支持的事件机制,但是在IE以及其它支持DOM Level 2的浏览器中,表现仍然有不同。以下代码在IE6,Firefox 3.0中运行通过。

[size=large][b]一。DOM Level 0的事件模型:[/b][/size]
1.事件的注册方式为使用 on + 事件名=function(){};
2.事件的移除方式为 on + 事件名 = null;
3.处理函数中,this 指向目标对象本身;
4.同一个事件只支持一个处理函数;
5.浏览器差别:
(1)在FF中,事件本身会作为参数传递给处理函数;
(2)在IE中,事件是作为window的一个变量存在,处理函数里面可以通过window.event访问;
(3)event对象所具有的属性随浏览器的不同而不同:IE拥有自己的事件属性,其它浏览器则使用DOM Level 2的事件属性


var btn = document.getElementById('btn');
btn.onclick=function(e){
//FF中的输出:[object MouseEvent],undefined
//IE中的输出:undefined,object
alert(e);
alert(window.event);
alert(this == btn);//true
}
//事件的移除
btn.onclick = null;


[size=large][b]二。DOM Level 2 的事件模型[/b][/size]

1.支持捕获阶段和冒泡阶段的事件处理。 事件流程如下图:

[img]http://dl.iteye.com/upload/attachment/264346/feddfcfa-699d-3050-95ba-966481a9b76c.gif[/img]
2.事件的注册、移除分别使用addEventListener和removeEventListener

/* HTML 片段
<button id='btn'>go</button>
*/

var btn = document.getElementById('btn');
//addEventListener的第三个参数设置为 true,则侦听器只在捕获阶段处理事件,
//如果为false,则侦听器只在目标或冒泡阶段处理事件。
btn.addEventListener('click',function(event){
alert(event.eventPhase);//2
},false);
document.body.addEventListener('click',function(event){
alert('document.body.addEventListener: True:' + event.eventPhase);//1

},true);
document.body.addEventListener('click',function(event){
alert('document.body.addEventListener: ' + event.eventPhase);//3
},false);

3.尽管目标对象处在冒泡阶段,但是它的eventPhase值为2。
4.取消事件的进一步传递,可以在任一阶段使用
event.stopPropagation();
5.通过 addEventListener方法添加的事件,只能通过removeEventListener进行消除,也就是说,不能通过on + 事件名取消
6.支持对同一事件注册多个事件函数;
7.removeEventListener不能消除匿名事件函数。

btn.removeEventListener('click', function(){ //won ’ t work!
alert(this.id);
}, false);

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

8.事件本身将作为参数传递给处理函数。
9.在事件处理函数里面,this 恒等于属性currentTarget,target则指向触发事件的最终对象.

//当body中的一个button被单击的时候
document.body.addEventListener('click',function(event){
alert(event.currentTarget === document.body); //true
alert(this === document.body); //true
alert(event.target === document.getElementById('btn')); //true
},false);

10.常用事件对象属性列表:

[img]http://dl.iteye.com/upload/attachment/264344/8de67c62-3e4e-3480-a4b3-31c1e4db9a93.jpg[/img]

[size=large][b]三。IE的事件模型[/b][/size]
1.IE仅支持冒泡阶段的事件处理;
2.事件的注册、移除分别使用attachEvent和detachEvent;
3.处理函数的作用域为window。

btn.attachEvent('onclick',function(event){
alert(event.type);//"click"
alert(this === window); //true
alert(window.event.type);//"click"
});

4.取消事件的进一步传递,可以使用
[window.]event.cancelBubble = true;

5.常用事件对象属性列表:

[img]http://dl.iteye.com/upload/attachment/264350/43851a98-3f5a-3925-91bc-7768834cff91.jpg[/img]

[size=large][b]四。由于事件模型的不同,我们使用以下简单代码,用于跨浏览器的处理。[/b][/size]

var EventUtil = {
addHandler: function(element, type, handler){
if (element.addEventListener){
element.addEventListener(type, handler, false);
} else if (element.attachEvent){
element.attachEvent('on' + type, handler);
} else {
element['on' + type] = handler;
}
},
removeHandler: function(element, type, handler){
if (element.removeEventListener){
element.removeEventListener(type, handler, false);
}
else if (element.detachEvent){
element.detachEvent('on' + type, handler);
}
else {
element['on' + type] = null;
}
},
getEvent: function(event){
return event ? event : window.event;
},
getTarget: function(event){
return event.target || event.srcElement;
},
preventDefault: function(event){
if (event.preventDefault){
event.preventDefault();
} else {
event.returnValue = false;
}
},
stopPropagation: function(event){
if (event.stopPropagation){
event.stopPropagation();
} else {
event.cancelBubble = true;
}
},
getRelatedTarget: function(event){
if (event.relatedTarget){
return event.relatedTarget;
} else if (event.toElement){
return event.toElement;
} else if (event.fromElement){
return event.fromElement;
} else {
return null;
}
},
getButton: function(event){
if (document.implementation.hasFeature('MouseEvents', '2.0')){
return event.button;
}
else {
switch(event.button){
case 0:
case 1:
case 3:
case 5:
case 7:
return 0;
case 2:
case 6:
return 2;
case 4:
return 1;
}
}
},
getCharCode: function(event){
if (typeof event.charCode == 'number' && event.charCode > 0){
return event.charCode;
}
else {
return event.keyCode;
}
}
};

一个简单的使用例子:

var btn = document.getElementById('myBtn');
var handler = function(){
alert('Clicked');
};
EventUtil.addHandler(btn, 'click', handler);
//other code here
EventUtil.removeHandler(btn, 'click', handler);



[size=large][b]五。以下是常用事件对象的小结[/b][/size]

1.获取事件触发的位置

//相对于页面的横向(从左到右)、纵向(从上到下)坐标
clientX,clientY
//相对于显示屏幕的横向(从左到右)、纵向(从上到下)坐标
screenX,screenY

2.判断是否同时有辅助键按下:

var div = document.getElementById('myDiv');
EventUtil.addHandler(div, 'click', function(event){
event = EventUtil.getEvent(event);
var keys = new Array();
if (event.shiftKey){
keys.push('shift');
}
if (event.ctrlKey){
keys.push('ctrl');
}
if (event.altKey){
keys.push('alt');
}
//IE不支持
if (event.metaKey){
keys.push('meta');
}
alert('Keys: ' + keys.join(','));
});


3.关于鼠标事件:
3.1 对于mouseout以及mouseover事件,事件发生的时候,可以获取到"相关联的对象"。
例如下面的代码:

< html >
< head >
< title > Related Elements Example < /title >
< /head >
< body >
< div id='myDiv' style='background-color:red;height:100px;width:100px;' > < /div >
< /body >
< /html>

当鼠标从myDiv移动到其它区域(body),mouseout事件触发,那么,相关联的对象就是 body.
当鼠标从其它区域(body)移动到myDiv,mouseover事件触发,那么,相关联的对象就是myDiv.
对于支持 DOM Level 2的浏览器,事件的相关联对象可以从 relatedTarget属性获得;IE则是通过fromElement,toElement来获取。


var div = document.getElementById('myDiv');
EventUtil.addHandler(div, 'mouseout', function(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
var relatedTarget = EventUtil.getRelatedTarget(event);
alert('Moused out of ' + target.tagName + ' to ' + relatedTarget.tagName);
});

3.2 对于mousedown和mouseup事件,触发时候,可以获取到button属性。对于支持DOM Level2模型的浏览器,button的取值为:0:左键;1:中键(滚轮);2:右键
对于IE,有自己的许多取值,具体含义如下:

[img]http://dl.iteye.com/upload/attachment/264348/5502c14d-88ed-34db-8517-d9189542c4f7.jpg[/img]

通常,我们只需要区别是鼠标的哪一个按键就已经足够了。
整合以后的代码见EventUtil。

4.键盘事件
4.1 键盘支持3种事件:
keydown:当任一按键被按下的时候;
keypress:当任一字符按键按下的时候(也包括Esc按键);
keyup:当任一按键松开的时候;
4.2 如果一个字符按键一直被按下,那么keydown、keyress事件将重复触发;
如果是一个非字符按键一直被按下,那么keydown事件将重复触发。
通常,keydown、kepress事件将在输入框内容变化之前触发,keyup将在输入框内容变化之后触发。
这也就说明,我们可以在keydown或者keyress事件处理中取消其向后传递,从而实现屏蔽掉一些字符的输入。
键盘上的keyCode的值如下表,对于数字和字母根据ASCII表取值。

[img]http://dl.iteye.com/upload/attachment/264354/e54ac020-dbad-36f8-9cce-8cf02e7ed3e1.jpg[/img]

[img]http://dl.iteye.com/upload/attachment/264356/a385f798-bb66-386e-b6f6-af3a3184e69e.jpg[/img]

[i]注意:[/i]
对于keydown和keyup事件,字母(A~Z)的charCode取值为0,keyCode则是字母(大写)的ASCII值。例如 a 与 A的keyCode相同。
另外,对于分号 ';'Firefox与Safira返回其在ASCII码表里面的值59;IE,Chrome则返回值186。

4.3 当keypress事件触发时候,对于Firefox,Chrome,Safari,通过event的一个属性charCode来获取(此时keyCode值为0),IE和Opera则使用keyCode。
获取到keyCode以后,则可以通过String.fromCharCode()来获取字符

//只允许退格键和数字输入
var textbox = document.getElementById('myText');
EventUtil.addHandler(textbox, 'keypress', function(event){
event = EventUtil.getEvent(event);
/*直接通过event.keyCode返回数字。即字母在ASCII表值。区分大小写。
ff 与 chrome都是返回0.
如果在ff与chrome中返回 event.charCode,将是字母在ASCII表值。区分大小写。*/
var code = EventUtil.getCharCode(event);
//alert(code);
var ch = String.fromCharCode(code);
//alert('Unicode:' + ch);
if(ch != 8 && (ch < '0' || ch > '9')){
EventUtil.preventDefault(event);
}
});
[/size]

4.4 keydown(keyup)事件触发的时候与 keypress有所不同。

EventUtil.addHandler(btn, 'keyup', function(event){
event = EventUtil.getEvent(event);
/*直接通过event.keyCode返回数字,字符A与字符a都返回65,即字母都是ASCII表对应的大写字母的值。
如果在ff与chrome中返回 event.charCode,同样不区分大小写。值为大写字母的值 。*/
var code = EventUtil.getCharCode(event);
alert(code);
var ch = String.fromCharCode(code);
alert(ch);
});

整理自《Professional.JavaScript.for.Web.Developers.2nd.Edition》,有修改。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值