在Javascript中,如果对一个元素同时绑定Click和Double Click事件,在进行Double Click动作时,程序在响应一个双击事件的同时,还会响应两个单击事件。从原理上来说这应该是正确的,但在开发中往往需要对双击和单击做不同的处理(比如常见的单击选中,双击执行),单双击事件的混杂响应就带来了一定的困扰。本次的目的就是让单击和双击事件各自独立不互相干扰。

首先我们需要弄清楚,浏览器在进行单击和双击时,究竟向DOM元素传递了什么,也就是说Javascript究竟靠什么来区别单击和双击。明白了原理,才好对症下药。

为了简单说明,以JQuery为例,编写测试代码如下:

$("#test").click(function(e){
	var res = '';
	for(var i in e) {
		res += i + ' : ' + e[i] + "\n";
	}
	alert(res);
});

来看看单击之后的结果

IEFF
originalEvent : [object]
undefined : undefined
which : undefined
wheelDelta : 0
view : undefined
type : click
toElement : null
timeStamp : 1229092321548
target : [object]
srcElement : [object]
shiftKey : false
screenY : 157
screenX : 140
relatedTarget : undefined
relatedNode : undefined
prevValue : undefined
pageY : 35
pageX : 138
originalTarget : undefined
newValue : undefined
metaKey : undefined
keyCode : 0
handler : function(e){}
fromElement : null
eventPhase : undefined
detail : undefined
data : undefined
currentTarget : undefined
ctrlKey : false
clientY : 37
clientX : 140
charCode : undefined
cancelable : undefined
button : 0
bubbles : undefined
attrName : undefined
attrChange : undefined
jQuery1229092320454 : true
preventDefault : function(){if(d.preventDefault)d.preventDefault();d.returnValue=false}
stopPropagation : function(){if(d.stopPropagation)d.stopPropagation();d.cancelBubble=true}
originalEvent : [object MouseEvent]
undefined : undefined
which : 1
wheelDelta : undefined
view : [object Window]
type : click
toElement : undefined
timeStamp : 11258562
target : [object HTMLDivElement]
srcElement : undefined
shiftKey : false
screenY : 154
screenX : 124
relatedTarget : null
relatedNode : undefined
prevValue : undefined
pageY : 46
pageX : 124
originalTarget : [object HTMLDivElement]
newValue : undefined
metaKey : false
keyCode : undefined
handler : function (e) {}
fromElement : undefined
eventPhase : 2
detail : 1
data : undefined
currentTarget : [object HTMLDivElement]
ctrlKey : false
clientY : 46
clientX : 124
charCode : undefined
cancelable : true
button : 0
bubbles : true
attrName : undefined
attrChange : undefined
jQuery1229092311220 : true
preventDefault : function () {if (d.preventDefault) {d.preventDefault();}d.returnValue = false;}
stopPropagation : function () {if (d.stopPropagation) {d.stopPropagation();}d.cancelBubble = true;}

将测试代码事件改为dblclick之后可以很简单的得到双击的结果

IEFF
originalEvent : [object]
undefined : undefined
which : undefined
wheelDelta : 0
view : undefined
type : dblclick
toElement : null
timeStamp : 1229094138735
target : [object]
srcElement : [object]
shiftKey : false
screenY : 173
screenX : 126
relatedTarget : undefined
relatedNode : undefined
prevValue : undefined
pageY : 51
pageX : 124
originalTarget : undefined
newValue : undefined
metaKey : undefined
keyCode : 0
handler : function(e){}
fromElement : null
eventPhase : undefined
detail : undefined
data : undefined
currentTarget : undefined
ctrlKey : false
clientY : 53
clientX : 126
charCode : undefined
cancelable : undefined
button : 0
bubbles : undefined
attrName : undefined
attrChange : undefined
jQuery1229094137079 : true
preventDefault : function(){if(d.preventDefault)d.preventDefault();d.returnValue=false}
stopPropagation : function(){if(d.stopPropagation)d.stopPropagation();d.cancelBubble=true}
originalEvent : [object MouseEvent]
undefined : undefined
which : 1
wheelDelta : undefined
view : [object Window]
type : dblclick
toElement : undefined
timeStamp : 1229094216813
target : [object HTMLDivElement]
srcElement : undefined
shiftKey : false
screenY : 141
screenX : 137
relatedTarget : null
relatedNode : undefined
prevValue : undefined
pageY : 33
pageX : 137
originalTarget : [object HTMLDivElement]
newValue : undefined
metaKey : false
keyCode : undefined
handler : function (e) {}
fromElement : undefined
eventPhase : 2
detail : 2
data : undefined
currentTarget : [object HTMLDivElement]
ctrlKey : false
clientY : 33
clientX : 137
charCode : undefined
cancelable : true
button : 0
bubbles : true
attrName : undefined
attrChange : undefined
jQuery1229094214813 : true
preventDefault:function(){if(d.preventDefault){d.preventDefault();}d.returnValue=false;}
stopPropagation:function(){if(d.stopPropagation){d.stopPropagation();}d.cancelBubble=true;}

需要注意的是type和detail这两项,type标记了事件的类型,detail则是Firefox独有的属性,对单击进行了计数,双击时第一次为1,第二次为2。

即是说在FF中,还是有办法区别两次单击动作的,但无论单击双击,detail都先从1开始计数,所以想从事件自带的属性并不能达到独立事件的目的。

这里有一篇关于单双击问题的解决,提供了一种思路,简单说是将第一次单击延时执行,如果在延时期间出现第二次单击,则取消第一次单击的执行。

按照上述办法我们可以模拟出近似效果,可以参看DEMO,除了单击时有延时之外,基本实现了事件的独立。

为了方便,做成JQuery插件,有兴趣的同学可以自取所需。


 Tags : YD的程序员葛阁 jQuery javascript 事件 event dblclick click

Donate:Buy me a coffee  | 文章有帮助,可以请我喝杯咖啡

Hpyer

那帖子是我发的,不过你比我考虑周全,还写成插件了,呵呵~~

Hpyer

AlloVince

多亏Hpyer想到的方法才少走了不少弯路,不过300ms的延时对于用户体验来说还是有一定影响的。还是尽可能的不要再一个动作上同时绑定两个事件比较好。

话说原帖貌似挂了- -

AlloVince