有3中事件注册方式,传统的行内方式,IE方式和W3C方式。
传统绑定
传统绑定为需要绑定的DOM元素绑定一个函数,作为它的属性。例如:
// 查找
元素并为它绑定 submit 事件处理函数document.getElementsByTagName("form")[0].onsubmit = function(e){
// 阻止表单的默认行为
return stopDefault( e );
};
// 为文档的 body 元素绑定键盘事件
document.body.onkeypress = myKeyPressHandler;
// 为window绑定加载事件处理函数
window.onload = function(){ … };
传统绑定的优点:
⑴ 简单和文档;
⑵ 处理事件时,this关键字引用的是当前元素
传统绑定的缺点:
⑴ 传统方法只在事件冒泡阶段运行,而非捕获和冒泡;
⑵ 一个元素一次只能绑定一个事件处理函数;
⑶ 事件对象参数仅非IE浏览器可用
传统绑定的事件处理函数会相互覆盖:
// 绑定初始化函数
window.onload = myFirstHandler;
// 初始化函数被覆盖
window.onload = mySecondHandler;
W3C的绑定方式
现代浏览器除了IE之外都支持这种绑定方式。它使用addEventListener函数,带有3个参数:事件的名称(比如click)、事件处理函数和一个是否启用事件捕获的布尔标记。例如:
// 查找
元素并为它绑定 submit 事件处理函数document.getElementsByTagName("form")[0].addEventListener('click',function(e){
// 阻止表单的默认行为
return stopDefault( e );
}, false);
// 为文档的 body 元素绑定键盘事件
document.body.addEventListener('keypress', myKeyPressHandler, false);
// 为window绑定加载事件处理函数
window.addEventListener('load', function(){ … }, false);
W3C绑定方式的优点:
⑴ 同时支持事件处理的捕获和冒泡阶段;
⑵ 在事件处理函数内部,this关键字引用当前元素;
⑶ 事件对象可以通过处理函数的参数获取;
⑷ 可以为同一元素绑定多个事件
缺点:IE不支持,必须使用IE的 attachEvent 函数替代
IE的绑定方式
// 查找
元素并为它绑定 submit 事件处理函数document.getElementsByTagName("form")[0].attachEvent('onclick',function(){
// 阻止表单的默认行为
return stopDefault( e );
}, false);
// 为文档的 body 元素绑定键盘事
document.body.attachEvent('onkeypress', myKeyPressHandler);
// 为window绑定加载事件处理函
window.attachEvent('onload', function(){ … });
优点:可以为同一元素绑定多个事件
缺点:
⑴ 仅支持冒泡阶段;
⑵ 事件侦听函数内的this关键字指向window,而不是当前元素;
⑶ 事件对象仅存在与 window.event 参数中;
⑷ 事件必须以 ontype 的形式命名,比如 onclick 而非 click;
⑸ 仅IE可用
Dean Edwards的addEvent和removeEvent函数
对于操作DOM事件,addEvent函数提供了一个简单但很强大的方式,可以作为处理事件的一个稳定可靠的方式。它可以在所有浏览器中工作、不会内存泄漏、正确处理this关键字与事件对象并合乎普通事件对象函数的标准:
// addEvent/removeEvent written by Dean Edwards, 2005
// http://dean.edwards.name/weblog/2005/10/add-event/
function addEvent(element, type, handler) {
// 为每个事件处理函数赋予一个唯一的id
if (!handler.$$guid) handler.$$guid = addEvent.guid++;
// 为元素建立一个事件类型的哈希表
if (!element.events) element.events = {};
// 没元素/事件对建立一个事件处理函数的哈希表
var handlers = element.events[type];
if (!handlers) {
handlers = element.events[type] = {};
// 存储已有的事件处理函数
if (element["on" + type]) {
handlers[0] = element["on" + type];
}
}
// 在哈希表中存储事件处理函数
handlers[handler.$$guid] = handler;
// 赋予一个全局处理函数来处理所有工作
element["on" + type] = handleEvent;
};
// 创建独立id的计数器
addEvent.guid = 1;
function removeEvent(element, type, handler) {
// 从哈希表中删除事件处理函数
if (element.events && element.events[type]) {
delete element.events[type][handler.$$guid];
}
};
function handleEvent(event) {
var returnValue = true;
// 获取事件对象
event = event || fixEvent(window.event);
// 获取事件处理函数哈希表的引用
var handlers = this.events[event.type];
// 依次执行每个事件处理函数
for (var i in handlers) {
this.$$handleEvent = handlers[i];
if (this.$$handleEvent(event) === false) {
returnValue = false;
}
}
return returnValue;
};
function fixEvent(event) {
// W3C标准事件方法
event.preventDefault = fixEvent.preventDefault;
event.stopPropagation = fixEvent.stopPropagation;
return event;
};
fixEvent.preventDefault = function() {
this.returnValue = false;
};
fixEvent.stopPropagation = function() {
this.cancelBubble = true;
};
使用addEvent函数的代码片段:
// 等待页面完成载入
addEvent( window, "load", function(){
// 监听用户的键盘事件
addEvent( document.body, "keypress", function(e){
// 如果按下了 空格 + Ctrl 键
if ( e.keyCode == 32 && e.ctrlKey ) {
this.getElementsByTagName("form")[0].style.display = 'block';
e.preventDefault();
}
});
});
优点:
⑴ 可以在所有浏览器中工作;
⑵ this关键字在所有的绑定函数中可用,且指向当前元素;
⑶ 综合了所有防止浏览器默认行为和阻止事件冒泡的各种浏览器特定函数;
⑷ 不管浏览器类型,事件对象总是作为第一个对象传入
缺点: 仅工作在冒泡阶段