引用来自:http://www.cnblogs.com/yupeng/archive/2012/03/15/2395316.html
本质:不同的库或者工具中总是封装了不同的事件绑定形式,但是究其根源,还是IE事件模型和W3C事件模型不同的处理方式
1)W3C事件模型:支持事件捕捉和冒泡 addEventListener('type',function(){},bool) removeEventListener ('type',function(){},bool)
2)IE事件模型:仅支持事件冒泡 attachEvent('type',function(){}); detachEvent('type',fucntion(){});
*如何统一:设置W3C事件绑定函数的第三个参数为false,那么就不支持事件捕捉了。
*原生的绑定形式:
obj.addEventListener('type',function(){},false);
obj.attachEvent('type',function(){});
*是否有注意的:
当然有,IE对同一个事件绑定2次会重复绑定2次,但是W3C只会绑定一次,会忽略后面的一个事件。这个要特别注意,特别是在开发的时候
在处理事件绑定顺序的问题上,参考了jquery的事件绑定原理,写出了一个自己用的简单的框架,解决了以下几个问题:
1. 修正IE下先绑定的事件后执行的BUG,统一为先绑定先执行的原则。
2. 支持自定义this指针.
3. 重复绑定的还没有完善,等完善后我会更新本代码。
4. 事件委托还没有放进来,和重复绑定一起解决完后放进来。
5. 代码中用到的navigator.isFirefox是自己补充的函数,因为里面处理的东西多,代码长,所以没有放上来,用的话,自己写一个简单的浏览器判断,很容易的....
1 var jm = {}; 2 jm.Contains = function(a, b){ 3 try{ 4 return a.contains ? a != b && a.contains(b) : !!(a.compareDocumentPosition(b) & 16); 5 }catch(e){} 6 }; 7 jm.eventTarget = function(e){ 8 return e.target || e.srcElement; 9 }; 10 //get event's relatedTarget 11 jm.relatedTarget = function(e){ 12 var element = null; 13 if(e.type === "mouseover"){ 14 element = e.relatedTarget || e.fromElement; 15 } else if(e.type === "mouseout"){ 16 element = e.relatedTarget || e.toElement; 17 } 18 return element; 19 }; 20 (function(){ 21 var cacheEvent = { 22 /* 23 elementId : { 24 "click": [{fun: function(){}, scope: null }], 25 "clickListener" : function(){}, 26 "mouseover" : [{fun: function(){}, scope: null }], 27 "mouseoverListener" : function(){} 28 }, 29 */ 30 uuid : 0 31 }; 32 var addEvent = function(oElm, eType, handler){ 33 if(document.addEventListener){ 34 oElm.addEventListener(eType, handler, false); 35 } else if(document.attachEvent){ 36 oElm.attachEvent("on" + eType,handler); 37 } 38 }; 39 var removeEvent = function(elm, eType, handler){ 40 if(document.removeEventListener){ 41 elm.removeEventListener(eType,handler, false); 42 } else if(document.detachEvent){ 43 elm.detachEvent("on" + eType, handler); 44 } 45 } 46 var addCache = function(oElm, eType, handler, scope){ 47 var cacheKey = oElm.eventId; 48 var scope = arguments.length > 3 ? scope : oElm; 49 var handleItem = {"fun": handler, "scope": scope}; 50 if(!cacheKey){ 51 oElm.eventId = "cache" + new Date().getTime() + "_" + (cacheEvent.uuid++); 52 cacheKey = oElm.eventId; 53 } 54 if(!cacheEvent[cacheKey]){ 55 cacheEvent[cacheKey] = {}; 56 } 57 var newEtype = eType; 58 switch(eType){ 59 case "mouseenter": 60 case "mouseleave": 61 newEtype = eType === "mouseenter" ? "mouseover" : "mouseout"; 62 var mouseEnterOrLeave = function(e){ 63 var related = jm.relatedTarget(e); 64 if (!((related !== oElm) && (!jm.Contains(oElm, related)))) { 65 return false; 66 } 67 return true; 68 }; 69 70 break; 71 case 'mousewheel': 72 newEtype = navigator.isFirefox ? 'DOMMouseScroll' : 'mousewheel'; 73 var mouseWheel = function(e){ 74 var wheel = 'wheelDelta' in e ? -e.wheelDelta : e.detail || 0; 75 if(!e.wheelUp){ 76 e.wheelUp = wheel < 0; 77 } 78 if(!e.wheelDown){ 79 e.wheelDown = wheel > 0; 80 } 81 }; 82 83 break; 84 } 85 86 if(!cacheEvent[cacheKey][eType]){ //寻找click,mouseover等事件对应的函数对列 87 cacheEvent[cacheKey][eType] = [handleItem]; 88 var funQuery = cacheEvent[cacheKey][eType]; 89 var listener = function(e){ 90 if(mouseEnterOrLeave){ 91 if(!mouseEnterOrLeave(e)){ 92 return; 93 } 94 } 95 if(mouseWheel){ 96 mouseEnterOrLeave(e); 97 } 98 99 var tempHandler; 100 for(var i = 0,l = funQuery.length; i < l; i ++){ 101 tempHandler = funQuery[i]; 102 tempHandler.fun.call(tempHandler.scope, e); 103 } 104 }; 105 cacheEvent[cacheKey][eType + "Listener"] = listener; 106 addEvent(oElm, newEtype, listener); 107 } else { 108 cacheEvent[cacheKey][eType].push(handleItem); 109 } 110 }; 111 var removeCache = function(oElm, eType, handler){ 112 var cacheKey = oElm.eventId; 113 114 if(!cacheKey || !cacheEvent[cacheKey]){ 115 return; 116 } 117 118 var newEvtType = eType; 119 switch(eType){ 120 case "mouseenter": 121 case "mouseleave": 122 newEvtType = eType === "mouseenter" ? "mouseover" : "mouseout"; 123 break; 124 case 'mousewheel': 125 newEvtType = navigator.isFirefox ? 'DOMMouseScroll' : 'mousewheel'; 126 break; 127 } 128 129 var funQuery = cacheEvent[cacheKey][eType]; 130 if(!funQuery){ //寻找click,mouseover等事件对应的函数对列 131 return; 132 } 133 if(arguments.length < 3 || !handler){ 134 removeEvent(oElm, newEvtType, cacheEvent[cacheKey][eType + "Listener"]); 135 delete cacheEvent[cacheKey][eType]; 136 delete cacheEvent[cacheKey][eType + "Listener"]; 137 return; 138 } 139 var i = 0; 140 while(funQuery[i]){ 141 if(funQuery[i].fun === handler){ 142 funQuery.splice(i, 1); 143 break; 144 } 145 i ++; 146 } 147 }; 148 jm.bind = addCache; 149 jm.unbind = removeCache; 150 })(); 151 152 //实例调用 153 var btn = document.getElementById("btn"); 154 var a = { 155 a: function(){ console.log(this.b); }, 156 b: "this is a下面的b" 157 }; 158 var clickHandler = function(){ 159 alert("this is click event"); 160 }; 161 jm.bind(btn, "click", a.a, a); 162 163 jm.bind(btn, "click", clickHandler); 164 jm.bind(btn, "mouseenter", function(){console.log("enter");}); 165 jm.bind(btn, "mouseleave", function(){console.log("leave");}); 166 jm.bind(btn, "mousewheel", function(){console.log("mousewheel");}); 167 var unbindBtn = document.getElementById("unbindBtn"); 168 jm.bind(unbindBtn, "click", function(){ 169 jm.unbind(btn, "click", clickHandler); 170 jm.unbind(btn, "mouseenter"); 171 jm.unbind(btn, "mouseleave"); 172 });