事件模块的演变
上一篇中的add有个问题,对同一类型事件添加多个hanlder时,IE6/7/8下会无序,如:
<div id="d1" style="width:200px;height:200px;background:gold;"></div>
<script type="text/javascript">
var el = document.getElementById('d1');
function handler1(){alert('1');}
function handler2(){alert('2');}
function handler3(){alert('3');}
function handler4(){alert('4');}
function handler5(){alert('5');}
E.add(el, 'click', handler1);
E.add(el, 'click', handler2);
E.add(el, 'click', handler3);
E.add(el, 'click', handler4);
E.add(el, 'click', handler5);
</script>
IE9/Firefox/Safari/Chomre/Opera会依次输出1,2,3,4,5。但IE6/7/8中则不一定。为解决所有浏览器中多个事件handler有序执行,我们需要一个队列来管理所有的handler。
这次,把所有的内部细节封装在一个匿名函数中,该函数执行完毕后返回如上一篇接口相同的方法。另外
1,把真正的事件handler挂在el上,即el.listeners,其为一个对象,每一个类型的事件为一个数组,如click为el.listeners["click"] = []。
2,所有的handler存在在对于的数组中
3,删除一个hanlder,将从数组中将其删除
E = function(){
function _isEmptyObj(obj){
for(var a in obj){
return false;
}
return true;
}
function _each(ary, callback){
for(var i=0,len=ary.length; i<len;){
callback(i, ary[i]) ? i=0 : i++;
}
}
function _remove(el, type){
var handler = el.listeners[type]['_handler_'];
el.removeEventListener ?
el.removeEventListener(type, handler, false) :
el.detachEvent('on'+type, handler);
delete el.listeners[type];
if(_isEmptyObj(el.listeners)){
delete el.listeners;
}
}
// 添加事件
function add(el, type, fn){
el.listeners = el.listeners || {};
var listeners = el.listeners[type] = el.listeners[type] || [];
listeners.push(fn);
if(!listeners['_handler_']){
listeners['_handler_'] = function(e){
var evt = e || window.event;
for(var i=0,fn; fn=listeners[i++];){
fn.call(el, evt);
}
}
el.addEventListener ?
el.addEventListener(type, listeners['_handler_'], false) :
el.attachEvent('on' + type, listeners['_handler_']);
}
}
// 删除事件
function remove(el, type, fn){
if(!el.listeners) return;
var listeners = el.listeners && el.listeners[type];
if(listeners) {
_each(listeners, function(i, f){
if(f==fn){
return listeners.splice(i, 1);
}
});
if(listeners.length == 0){
_remove(el,type);
}
}
}
//主动触发事件
function dispatch(el ,type){
try{
if(el.dispatchEvent){
var evt = document.createEvent('Event');
evt.initEvent(type,true,true);
el.dispatchEvent(evt);
}else if(el.fireEvent){
el.fireEvent('on'+type);
}
}catch(e){};
}
return {
add: add,
remove: remove,
dispatch: dispatch
};
}();