写事件处理的时候总是不规范,而且情况不同遇到各种细节问题。把看到的东西记忆整理一下。
事件触发和监听
javascript中将事件和触发的句柄连接起来,有多种方法。
1)onclick/onmouseover……
这种方法一般比较简单,通过
或者js中为对象添加onclick属性
a.οnclick=function(){do something};
IE8.0以上和chrome/firefox中可以使用addEventListener来管理事件的触发
除此之外则使用attachEvent
addEventListener(type,handler,method)接收三个值,type为“click,"mouseover"之流,handler为需要运行的函数,method是一个boolean值,false表示冒泡型(bubble),true表示捕获型(capture)。
attachEvent("onclick",handler),因此需要在上面的type前加上字符串“on”
这两个概念就涉及到了js的事件流了。
事件流的概念比较简单。如图所示。
一共有三个阶段:捕获-处理-冒泡。捕获从外层往内,从上往下。而冒泡从下往上,从里往外。
通过以下例子可以看出addEventListener中两种事件流的区别。
设置为获取型(true),则点击图中间的小框,会发现先提示外框再提示里框
当把true改成false之后,则变成冒泡型。
See the Pen eventlistener with bubble by jfc555 (@focusj) on CodePen.
上述两种方法,addEventListener可以对同一个对象反复使用,一个按键添加多个不同的事件触发。而onclick后者相当于对前面的重写,会覆盖掉。
2.evnet和target
一个表格每行末位都添加一个删除按键。如果for循环一个一个添加,效率低而且容易出问题。
而通过监听触发事件的对象,可以将删除按键和该行绑定在一起.
这里要用到event来获取操作触发的事件,target获取操作所在的target对象
function handler(e){
e=window.event||e;
target=e.target||e.srcElement;
if(target.nodeName.toLowerCase==="input"||target.id==="aaa"){
//do something
}
}
得到target之后对触发的节点进行判定,执行命令。
实际应用中,假设div元素a中有一个元素b。如果不使用target监测事件对象,则点击b的时候也会触发a的点击事件。跟上面例子一样,点击内部框,外部的框架绑定的handler也会触发。
而用target限制以后,只有点击精确的元素才会触发handler。如假设置外部target.id==="box1"时弹出窗口,则点击box1内部的box2,并不会有什么效果。
3.游览器兼容性处理
首先是addevent的游览器兼容问题,实际上就是addEventListener和attachEvent。
//跨浏览器添加事件
function addHandler(target, eventType, handler) {
if(target.addEventListener) { //DOM2 events
target.addEventListener(eventType, handler, false);
} else if(target.attachEvent){ //IE
target.attachEvent("on" + eventType, handler);
}else{
target["on"+eventType]=handler;//实际上这句并不需要,没有这种情况
}
}
但是这种处理方式每次调用addHandler的时候都要判定一次,比较浪费资源
因此有两种更好的解决方法。
两种方法都是在判定后重写addHandler,只要调用一次,之后直接使用重写的新函数无需判断。
推荐这种方法(在上面的codepen代码里面就是用这种实现的):
var addEvent=document.body.addEventListener?
function(type,handler,method,obj){
obj.addEventListener(type,handler,method);
console.log("addEventListener");
}:
function(type,handler,method,obj){
obj.attachEvent("on"+type,handler);
console.log("attachEvent");
}
通过判定document.body上是否存在addEventListener方法来确定使用哪种方法。然后重写addEvent
另一种方法道理上是一样的,但是稍微麻烦一点,借用别人的代码:
//添加事件
function addHandler(target, eventType, handler) {
//检测浏览器类型,并且重写addHanler方法
if(target.addEventListener) { //DOM2
addHandler = function(target, eventType, handler) {
target.addEventListener(eventType, handler, false);
};
} else { //IE
addHandler = function(target, eventType, handler) {
target.attachEvent("on" + eventType, handler);
};
}
//调用新的函数
addHandler(target, eventType, handler);
}
最后重写完了调用新函数这个比较容易漏掉。而且效率也不如上面推荐的。
removeEventListener方法也是同理
参考资料:
[1]JavaScript跨浏览器绑定事件函数的优化
[ 2 ]理解DOM中的事件流