给dom元素绑定事件监听,刚入门的javascript编程人员都可以办到,比如obj.onclick = fn
obj.onclick = fn1; obj.onclick = fn2; ...
可如果这么做,fn2会把fn1覆盖,也就是说在单击obj时只会执行fn2中的代码片段,fn1则会被忽略,很显然这样不能满足我们的需求。
在考虑到这个问题的时候,JS已经为我们准备了像attachEvnet、addEventListener这样的方法来满足我们的需求,利用对能力检测还是可以轻松的实现一个兼容的方法:
function bindEvent(elem,type,fn){ if(elem.addEventListener){ elem.addEventListener(type,fn,false); }else{ elem.attachEvent("on"+type,fn); } bindEvent(obj,"click",fn1); bindEvent(obj,"click",fn2);
这样目的就达到了,当单击obj时,依次执行fn1、fn2。
解决了这个问题后,细心的淫们会发现在用attachEvent添加事件处理函数,执行的function中this执行是有问题的,始终指向window,又不是一个不小的麻烦。
那么有没有办法,来解决这个棘手的问题呢,答案是肯定的,这正是我写这篇文章的意义所在,废话!
其实只需对bindEvent稍作加工即可,如下:
function bindEvent(elem,type,fn){ if(elem.addEventListener){ elem.addEventListener(type,fn,false); }else{ elem.attachEvent("on"+type,function(){ fn.apply(elem,arguments); }); } } bindEvent(obj,"mouseover",function(){alert(this)})
理论上,这样的解决方案近乎完美了,但是还有一个问题亟待解决,因为在attachEvent中使用了匿名函数来执行fn,导致在无法使用 detachEvent来删除绑定的某个代码片段,也许obj["on"+type] = null可以解决,清空绑定的代码片段,这很粗暴邪恶,同时也违背我们的业务需求。
我想要从根本上解决这些问题,就一定抛弃attachEvent这个方法,事实上我也是这样做的,如下:
(function(win,doc){ var Event = {}; Event.add = function(elem,type,fn){ if(doc.addEventListener){ elem.addEventListener(type,fn,false); }else{ var typeRef = "_" + type; if(!elem[typeRef]){ elem[typeRef] = []; } var len = elem[typeRef].length; while(len-->0){ if(elem[typeRef][len] === fn)return; } elem[typeRef].push(fn); elem["on"+type] = function(){ len = this[typeRef].length; this[typeRef].reverse(); while(len-->0){ this[typeRef][len].apply(this,arguments); } this[typeRef].reverse(); } } }; Event.remove = function(elem,type,fn){ if(doc.addEventListener){ elem.removeEventListener(type,fn,false); }else{ var typeRef = "_" + type; if(elem[typeRef]){ var len = elem[typeRef].length; while(len-->0){ if(elem[typeRef][len] === fn){ elem[typeRef].splice(len,1); break; }; } } } }; Event.getEve = function(e){ return e || win.event; }; Event.target = function(e){ e = this.getEve(e); return e.target || e.srcElement; }; Event.preventDefault = function(e){ //阻止默认事件 e = this.getEve(e); e.preventDefault ? e.preventDefault() : e.returnValue = false; }; Event.stopPropagation = function(e){ //阻止冒泡 e = this.getEve(e); e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true; }; win.Event = Event; })(window,document);