addEventListener()和attachEvent()相同点和不同点
相同点:
① 它们都是dom对象的方法,可以实现一种事件绑定多个事件处理函数;
② 相对于普通的DOM事件处理element.event = fun();的写法来说,使用attachEvent和addEventListener时则可以实现多个事件处理函数的调用;
不同点:
① attachEvent是IE有的方法,它不遵循W3C标准,而其他的主流浏览器如FF等遵循W3C标准的浏览器都使用addEventListener,所以实际开发中需分开处理 — 涉及兼容;
② 多次绑定后执行的顺序是不一样的,attachEvent是后绑定先执行,addEventListener是先绑定先执行;
③ 绑定时间时,attachEvent必须带on,如onclick,onmouseover等,而addEventListener不能带on,如click,mouseover ;
④ attachEvent仅需要传递两个参数,而addEventListener需要传递三个参数,这里牵扯到“事件流”的概念。侦听器在侦听时有三个阶段:捕获阶段、目标阶段和冒泡阶段。顺序为:捕获阶段(根节点到子节点检查是否调用了监听函数)→目 标阶段(目标本身)→冒泡阶段(目标本身到根节点)。此处的参数确定侦听器是运行于捕获阶段、目标阶段还是冒泡阶段。 如果将 useCapture 设置为 true,则侦听器只在捕获阶段处理事件,而不在目标或冒泡阶段处理事件。 如果useCapture 为 false,则侦听器只在目标或冒泡阶段处理事件。 要在所有三个阶段都侦听事件,请调用两次 addEventListener,一次将 useCapture 设置为 true,第二次再将useCapture 设置为 false;
关于 ④ 的理解可以转至:点这里(讲解一下这两个参数顺便补一下事件冒泡和事件捕获的概念理解)
例子:
// 普通事件处理函数 --- 只执行最后一个事件绑定函数(只执行最后绑定的事件回调 >>> 3)
btn.onclick = function(){alert(1);}
btn.onclick = function(){alert(2);}
btn.onclick = function(){alert(3);}
// attachEvent事件处理函数调用 --- 后绑定先执行(IE8- >>> 3 2 1)
btn1.attachEvent("onclick",function(){ alert(1); })
btn1.attachEvent("onclick",function(){ alert(2); })
btn1.attachEvent("onclick",function(){ alert(3); })
// addEventListener事件处理函数 --- 先绑定先执行(IE9+/主流浏览器 >>> 1 2 3)
btn2.addEventListener("click",function(){ alert(1); },false)
btn2.addEventListener("click",function(){ alert(2); },false)
btn2.addEventListener("click",function(){ alert(3); },false)
封装 – 不同浏览器监听事件和清除事件的方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<button id="btn">点我</button>
</body>
<script type="text/javascript">
/**对监听事件做兼容处理
* 参数解释:
* element: 监听事件源
* type: 为监听事件名,如click,submit等
* handler: 为监听事件所执行的函数
* 调用: EventUtil.addHandler(添加事件)/removeHandler(移除事件)
*/
var EventUtil = {
addHandler : function(type, handler, element){
this.checked(type, handler, element);
if(element.addEventListener){
element.addEventListener(type, handler, false);
}else if(element.attachEvent){
element.attachEvent('on' + type, handler);
}else{
element['on' + type] = handler;
}
},
removeHandler : function(type, handler, element){
this.checked(type, handler, element);
if(element.removeEventListener){
element.removeEventListener(type, handler, false);
}else if(element.detachEvent){
element.detachEvent('on' + type, handler);
}else{
element['on' + type] = null;
}
},
checked: function(type, handler, element){
if(!(typeof(type) == 'string')) throw new Error("The parameter is required and the parameter type is String");
if(!(handler instanceof Function)) throw new Error("The parameter is required and the parameter type is Function");
return element = element ? element : document;
}
}
var a = 111;
var btn = document.getElementById('btn');
var handler = function(){
console.log('Hello World!');
/* 移除事件 */
// EventUtil.removeHandler(btn,'click',handler);
}
/* 添加事件 */
EventUtil.addHandler('click', handler, btn);
</script>
</html>
使用哈希值-表封装
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;
//抓获事件对象(IE使用全局事件对象)
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;
};
//为IE的事件对象添加一些“缺失的”函数 -- 冒泡兼容IE的处理
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;
};