事件模块的演变(3)

上一篇中的add有个问题,对同一类型事件添加多个hanlder时,IE6/7/8下会无序,如

<div id="d1" style="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
	};
}();

相关:

仅IE6/7/8下同一个类型事件的多个handler执行无序 

原文地址:https://www.cnblogs.com/snandy/p/2009530.html