Javascript 绑定事件
绑定事件:
看到这个词,你肯定非常的熟悉吧。立即想到 标准浏览器的addEventListener 以及iE的attachEvent 然后 做个判断之类的等等 就给自己需要的元素加上了事件上
但是只是这样是不够的,因为在实际工作中,我们的需求,远不是只是绑定事件就了事了,我们可能会给一个元素绑定多个事件,而且还希望他能按照顺序执行,再面对浏览的
兼容性方法,我们自然不再想处理,希望有一个统一的替代方案 !还有一个,我想你也能够想到的 就是this ~
好吧 针对以上需要求 我们列出了 一个 addEvent 方法应当达到的要求:
1. 支持同一元素的同一事件句柄可以绑定多个监听函数;
2. 绑定监听的函数的执行顺序应当是按照绑定的顺序执行;
3. 如果在同一元素的同一事件句柄上多次注册同一函数,那么第一次注册后的所有注册都被忽略 (相同的事件,只绑一次就好)
4. 在函数体内不用使用 event = event || window.event; 来标准化Event对象;
5. 函数体内的this指向的应当是正在处理事件的节点(如当前正在运行事件句柄的节点);
先来看一下 大牛的实现方式
John Resig 所写的 addEvent() 函数:http://ejohn.org/projects/flexible-javascript-events/
1 function addEvent( obj, type, fn ) { 2 if ( obj.attachEvent ) { 3 obj['e'+type+fn] = fn; 4 obj[type+fn] = function(){obj['e'+type+fn]( window.event );} 5 obj.attachEvent( 'on'+type, obj[type+fn] ); 6 } else 7 obj.addEventListener( type, fn, false ); 8 } 9 function removeEvent( obj, type, fn ) { 10 if ( obj.detachEvent ) { 11 obj.detachEvent( 'on'+type, obj[type+fn] ); 12 obj[type+fn] = null; 13 } else 14 obj.removeEventListener( type, fn, false ); 15 }
这个函数如此简单易懂,的确非常令人惊讶。我们看看上面的五点要求是可以:
对于第1点满足了;
对于第4点和第5点,肯定也满足了;
第2点,也没有满足,因为Dom标准没有确定调用一个对象的时间处理函数的顺序,所以不应该想当然的认为它们以注册的顺序调用。
但是这个函数仍然是一个非常优秀的函数。
第3点,并没有满足,因为addEventListener()会忽略重复注册,而attachEvent()则不会忽略;
Dean Edward 所写的 addEvent() 函数 :http://dean.edwards.name/weblog/2005/10/add-event2/
function addEvent(element, type, handler) { if (!handler.$$guid) handler.$$guid = addEvent.guid++; if (!element.events) element.events = {}; var handlers = element.events[type]; if (!handlers) { handlers = element.events[type] = {}; if (element["on" + type]) { handlers[0] = element["on" + type]; } } handlers[handler.$$guid] = handler; element["on" + type] = handleEvent; } addEvent.guid = 1; function removeEvent(element, type, handler) { if (element.events && element.events[type]) { delete element.events[type][handler.$$guid]; } } function handleEvent(event) { var returnValue = true; event = event || fixEvent(window.event); var handlers = this.events[event.type]; for (var i in handlers) { this.$$handleEvent = handlers[i]; if (this.$$handleEvent(event) === false) { returnValue = false; } } return returnValue; }; function fixEvent(event) { event.preventDefault = fixEvent.preventDefault; event.stopPropagation = fixEvent.stopPropagation; return event; }; fixEvent.preventDefault = function() { this.returnValue = false; }; fixEvent.stopPropagation = function() { this.cancelBubble = true; };
该函数使用了传统的绑定方法,所以它可以在所有的浏览器中工作,也不会造成内存泄露。
但是对于最初提出的5点,该函数只是满足了 1 3 4 5 。只有最后2没有满足,因为在JavaScript中对for/in语句的执行顺序没有规定是按照赋值的顺序执行,尽管大部分时刻是按照预期的顺序执行,因此在不同的JavaScript版本或实现中这一语句的顺序有可能不同。
三、Dean Edward 的 addEvent() 函数的改进
Array.prototype.indexOf = function( obj ){ var result = -1 , length = this.length , i=length - 1; for ( ; i>=0 ; i-- ) { if ( this[i] == obj ) { result = i; break; } } return result; } Array.prototype.contains = function( obj ) { return ( this.indexOf( obj ) >=0 ) } Array.prototype.append = function( obj , nodup ) { if ( !(nodup && this.contains( obj )) ) { this[this.length] = obj; } } Array.prototype.remove = function( obj ) { var index = this.indexOf( obj ); if ( !index ) return ; return this.splice( index , 1); }; function addEvent(element , type , fun){ if (!element.events) element.events = {}; var handlers = element.events[type]; if (!handlers) { handlers = element.events[type] = []; if(element['on' + type]) { handlers[0] = element['on' + type]; } } handlers.append( fun , true) element['on' + type] = handleEvent; } function removeEvent(element , type , fun) { if (element.events && element.events[type]) { element.events[type].remove(fun); } } function handleEvent(event) { var returnValue = true , i=0; event = event || fixEvent(window.event); var handlers = this.events[event.type] , length = handlers.length; for ( ; i < length ; i++) { if ( handlers[i].call( this , event) === false ){ returnValue = false; } } return returnValue; } function fixEvent(event) { event.preventDefault = fixEvent.preventDefault; event.stopPropagation = fixEvent.stopPropagation; return event; } fixEvent.preventDefault = function() { this.returnValue = false; }; fixEvent.stopPropagation = function() { this.cancelBubble = true; };
该函数是对Dean Edward 的 addEvent() 函数的改进,完全满足了最初提出的5点要求。有时间,再查看一下,各大类库的实现形式,供大家参考学习 如果大家有更好的方法,期待分享!
有时间再分享一下关于自定义事件机制。

浙公网安备 33010602011771号