事件注册
事件注册有哪些方法
on + “event”
例如:onclick/onmouseover…支持最广。但是要在一个元素上多次添加同一事件,此时就无能为力了,只能以最后一次绑定的事件为准。
addEventListener
W3C 标准方法,功能也最强大,支持添加多个事件
//element.addEventListener(type,listener,useCapture);
obj.addEventListener('click', method1, false)
obj.addEventListener('click', method2, false)
obj.addEventListener('click', method3, false)
执行顺序为 method1 -> method2 -> method3,第三个参数是指以“冒泡”还是“捕获”的标准绑定事件,一般为false(冒泡)。
并且可以使用 removeEventListener() 方法移除由 addEventListener() 方法添加的事件句柄。
事件句柄:又称事件处理函数 event handlers
- 指事件发生时要进行的操作。
- 将相应的函数或语句指定给事件句柄,则在该事件发生时,浏览器便执行指定的函数或语句,从而实现网页内容与用户操作的交互。
注意:如果要移除事件句柄,addEventListener() 的执行函数必须使用外部函数,如上述实例所示(method 1/2/3)。
匿名函数,类似“windows.removeEventListener(“event”,function(){ myScript});”该事件是无法移除的。
如果浏览器不支持 removeEventListener() 方法,你可以使用 detachEvent() 方法实现。
var x = window.getElementById('myDIV')
if (x.removeEventListener) {
// 所有浏览器,除了 IE 8 及更早IE版本
x.removeEventListener('mousemove', myFunction)
} else if (x.detachEvent) {
// IE 及更早IE版本
x.detachEvent('onmousemove', myfunction)
}
attachEvent
IE 家的方法,火狐与其他家浏览器都不支持,attachEvent——兼容:IE7、IE8;不兼容 firefox、chrome、IE9、IE10、IE11、safari、opera.尽量不要用,支持绑定多个事件,与 addEventListener()执行顺序相反,即 method3->method2->method1
进行兼容性处理
1. 简单通过 if 判断
if (window.addEventListener) {
// 功能最强大
div.addEventListener('click', function() {
alert('hello, world')
})
} else if (window.attachEvent) {
// 非标准特性 尽量不要使用
div.attachEvent('click', function() {
alert('hello, world')
})
} else {
// 支持度最好
div['onclick'] = function() {
alert('hello, world')
}
}
2. 封装成函数
function registeEvent(el, type, handler, useCapture) {
if (window.addEventListener) {
// 功能最强大
el.addEventListener(type, handler, useCapture)
} else if (window.attachEvent) {
// 非标准特性 尽量不要使用
el.attachEvent(type, handler)
} else {
el['on' + type] = handler
}
}
到这里,我们每次注册事件时都通过 registeEvent 注册,很明显,每次注册都要判断浏览器的能力是否支持,每一次都要检测,这不是我们想要的。
3. 使用立即执行函数进行优化
var registeEvent = (function creatEventRegister() {
if (window.addEventListener) {
return function(el, type, handler, useCapture) {
el.addeventListener(type, handler, useCapture)
}
} else if (window.attachEvent) {
return function(el, type, handler) {
el.attachEvent(type, function() {
handler.call(el, window.event) // 注:attachEvent内部this指向window而不是触发对象,使用call方法修改this
})
}
} else {
return function(el, type, handler) {
el['on' + type] = handler
}
}
})()
call() 方法第一个参数覆盖函数里的 this, 第二个参数作为函数的函数传进去
此后只用通过 registeEvent 方法注册事件即可,且只在最开始的时候进行一次能力检测。
registeEvent(divm 'click', function() {
alert('hello world')
})
此时依旧存在一个缺点,如果我们从头到尾没有绑定过事件,即使用 registerEvent 函数,那么立即执行函数白白执行了一次完全是多余的,我们可以使用惰性载入函数来进行优化。
4. 惰性载入函数方案
此时 registerEvent 依然被声明为一个普通函数,在函数里依然有一些分支判断。但是在第一次进入条件分支后,在函数内部会重写这个函数,重写之后的函数就是我们期待的 registerEvent 函数,在下一次进入 registerEvent registerEvent 函数里不再存在条件分支语句:
var registerEvent = function(el, type, handler, useCapture) {
if(window.addEventListener) {
registerEvent = function(el, type, handler, useCapture) {
el.addEventListener(type, handler, useCapture)
}
} else if (window.attachEvent) {
registerEvent = function(el, type, handler) {
el.attachEvent(type, handler) {
handler.call(el, window.event)
}
}
} else {
registerEvent = function(el, type, handler) {
el['on' + type] = handler
}
}
}
阿里笔试题
if (window.addEventListener) {
var addListener = function(el, type, listener, useCapture) {
el.addEventListener(type, listener, useCapture);
};
} else if (document.all) {
addListener = function(el, type, listener) {
el.attachEvent("on" + type, function() {
listener.apply(el);
});
};
}
请阐述 :
a) 代码的功能;
b) 代码的优点和缺点;
c) listener.apply(el) 在此处的作用;
d) 如果有可改进之处,请给出改进后的代码,并说明理由。
参考答案:
a) 功能:事件注册
b) 优点:跨浏览器,特性探测,性能优化。缺点:document.all
c) 作用:使得IE中listener的this 为 el,与其它浏览器一致
d) 改进:document.all改成window.attachEvent; useCapture的默认