|
Oct
29
|
|
|
Categories: JavaScript
| Tags: JavaScript, jQuery, 左右键同时点击
| Views: 4,153
|
之所以同时加上引号,是因为真正的同时,除了机器人,是不可能做到的。
这个是利用jQuery的事件管理机制来实现的,并把它写成了一个jQuery插件。
在Firefox中表现完美, 在IE中能够实现想要的功能,但是总是有些不尽如人意。
在IE中左键的button值是1,右键是0;而在Firefox中左键是0,右键是2.
问题倒不在这里,问题在于,如果你在IE中先点右键,再很短的时间内再点左键,你会发现得到的button值是3!并且如果是这么简单也就好了,直接检测button值,如果是3,就直接执行事件就行了。可是问题总不是想象中的那样简单,在button=3的事件执行完之后,IE还会激发一个button=1的事件(先点的右键,那点的左键)。这在处理起来就麻烦多了。
我的思路和网上想实现这类功能的人的思路大致相同,也是通过一个计时器来判断。
具体思路是这样的:
这个插件可以处理鼠标左右键的同时点击(click),鼠标按下(mousedown),鼠标弹起(mouseup)事件。在讲思路的时候就以点击为
例。
首先我们必须先找出所有绑定为点击的事件,unbind它们,因为要阻止它们在一点击鼠标的时候就执行。
在找这些事件的时候还是颇费了一番功夫的。因为jQuery的源码还没有真正的读通。所以机制也并没有弄很清楚明白。jQuery将事件存在了一个缓存里面(jQuery.cache),但是如果从这个缓存里把这些事件取出来?关键问题是找到元素对应的在缓存的位置,我找遍了jQuery(…)就是没有这样的公有方法。于是用了一个小trick,我们知道jQuery允许我们给一个元素绑定data,而这个data也是存在缓存里的。所以我就可以赋一个唯一的属性值给data(时间戳或者随机数),再后再通过这个唯一值找到这个元素并找到存储的事件。
这时候我们就可以处理左右键的事件了。因为无论左键还是右键先点,我们要达到的效果是一样的,所以这里只说一下其中一个键点击的事件。
当点击一个键的时候,我们先需要先判断另一个键是否已经点击,如果还没有点击,这时候判断一下时间差(这个是专为IE设计的。。。因为IE会引起一个button=1的事件,在button=3的事件执行之后,就把时间变量设置为当前时间),如果不在时间差内,就等待另一个按键的点击。如果另一个键已经点击了的话,那就直接判断时间差,在时间差内就执行给定的事件;如果不在,就执行原有的事件。
这样,在bindLR后,也不影响原来已经bind的事件的执行(会有设定时间的延时,为了等待另一个键的点击),在unbindLR之后,也能够恢复原来已经bind的事件,我没有采用循环绑定,所以在绑定了bindLR事件之后,无法再用unbind来原有事件的绑定,并且,unbindLR现在的功能有限,只能解除所有的bindLR事件,并不能解除指定事件的绑定。
jquery.LRmouse.js
/** * * jquery.LRmouse 1.0.0 * * Author: pwwang ( http://pwwang.com ) * 2009.10.26 * * Bind an event handle to a listener that * LButton and RButton of the mouse act * ( click, mousedown, mouseup ) "simultaneously" * * It works on both IE and Firefox, distinguishedly, * however, it performs perfectly in Firefox; not * exactly ideally in IE. * **/ (function($){ $.bindLR = function( elem, type, data, fn, intv ){ var L_BUTTON = $.browser.msie ? 1 : 0 ; var R_BUTTON = $.browser.msie ? 0 : 2 ; var LR_BUTTON = 3; // ie var orgType = type.substr(2); var L_flag = false; var R_flag = false; var getTime = function(){ return +new Date; }; var lrId = getTime(); // for finding the elem in $.cache // a trick, 'cz I don't know how to // find the function directly elem.data('lrId', lrId); var orgFns = []; for( var i in $.cache ){ // find original binded functions if( $.cache[i]['lrId'] == lrId ){ var fns = $.cache[i]['events'][orgType]; for( var j in fns ){ orgFns.push( fns[j] ); elem.unbind( orgType, fns[j] ); } //remove it elem.removeData('lrId'); break; } } elem.data('lrTempEvents',orgFns); var timer = getTime(); var timeOut; var reset = function(){ L_flag = false; R_flag = false; clearTimeout( timeOut ); }; var orgFnHandle = function(e, data){ reset(); for( var i=0; i<orgFns.length; i++ ){ orgFns[i].call(elem, e, data); } }; var L_event = function(e, data){ if( !R_flag ){ //waiting // if LR_BUTTON, do NOT wait // LR_BUTTON in ie will call L_BUTTON event if( getTime() - timer > intv ){ L_flag = true; timer = getTime(); timeOut = setTimeout( function(){orgFnHandle(e, data);}, intv+1 ); } } else { reset(); var deltT = getTime() - timer; if( deltT <= intv ){ fn.call(elem, e, data); } else { orgFnHandle(e, data); } } }; var R_event = function(e, data){ if( !L_flag ){ if( getTime() - timer > intv ){ R_flag = true; timer = getTime(); timeOut = setTimeout( function(){orgFnHandle(e, data);}, intv+1 ); } } else{ reset(); var deltT = getTime()-timer; if( deltT <= intv ){ fn.call(elem, e, data) } else { orgFnHandle(e, data); } } } var eventHandle = function(e, data){ if( L_BUTTON === e.button ) L_event (e, data); else if( R_BUTTON === e.button ) R_event (e, data); else if( LR_BUTTON === e.button ) { //ie timer = getTime(); fn.call(elem, e, data); } }; //ban context menu; elem.bind('contextmenu', function(){ return false; }); //bind new elem.bind( orgType, data, eventHandle ); }; $.unbindLR = function(elem, type){ elem.unbind('contextmenu'); elem.unbind( type ); var orgType = type.substr(2); elem.unbind( orgType ); var lrId = Math.random(); elem.data('lrId', lrId); for( var i in $.cache ){ if( $.cache[i]['lrId'] == lrId ){ var fns = $.cache[i]['lrTempEvents']; for( var j in fns ){ elem.bind( orgType, function(){ fns[j].apply(elem,arguments) }); } //remove it elem.removeData('lrId'); elem.removeData('lrTempEvents'); break; } } }; $.fn.bindLR = function(type, data, fn, intv){ if( $.isFunction( data ) ){ intv = fn || 500; fn = data; data = {}; } else { data = data || {}; fn = fn || {}; intv = intv || 500; } // lr bind for $(...).trigger() this.bind(type,data,fn); if( type.substr(0,2)=='lr' ){ $.bindLR( this, type, data, fn, intv ); } return this; }; $.fn.unbindLR = function(type){ $.unbindLR( this,type ); return this; } })(jQuery);
RELATED POSTS:


太高深,好好学习下!