Categories: JavaScript | Tags: , , | Views: 3,806

 

之所以同时加上引号,是因为真正的同时,除了机器人,是不可能做到的。

这个是利用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:

  1. Js的检测函数集合
  2. 又见div提示框,jQuery版
  3. jQuery插件:音标辅助输入1.0
  4. jQuery插件:不超过50行的评分插件jquery.rate 1.0
  5. 简单写了个jquery的鼠标提示文字插件
  6. A more elegant way to write OO-JavaScript
  1. October 29th, 2009 at 21:17
    Reply | Quote | #1

    太高深,好好学习下!

;) :| :x :twisted: :roll: :oops: :o :mrgreen: :lol: :idea: :evil: :cry: :arrow: :P :D :?: :? :) :( :!: 8O 8)

你可以使用@somebody:开头, 来邮件通知somebody你回复了他的留言(用户名区分大小写).