在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);});
來看看單擊之後的結果
IE |
FF |
originalEvent : [object]undefined : undefinedwhich : undefinedwheelDelta : 0view : undefinedtype : clicktoElement : nulltimeStamp : 1229092321548target : [object]srcElement : [object]shiftKey : falsescreenY : 157screenX : 140relatedTarget : undefinedrelatedNode : undefinedprevValue : undefinedpageY : 35pageX : 138originalTarget : undefinednewValue : undefinedmetaKey : undefinedkeyCode : 0handler : function(e){}fromElement : nulleventPhase : undefineddetail : undefineddata : undefinedcurrentTarget : undefinedctrlKey : falseclientY : 37clientX : 140charCode : undefinedcancelable : undefinedbutton : 0bubbles : undefinedattrName : undefinedattrChange : undefinedjQuery1229092320454 : truepreventDefault : function(){if(d.preventDefault)d.preventDefault();d.returnValue=false}stopPropagation : function(){if(d.stopPropagation)d.stopPropagation();d.cancelBubble=true} |
originalEvent : [object MouseEvent]undefined : undefinedwhich : 1wheelDelta : undefinedview : [object Window]type : clicktoElement : undefinedtimeStamp : 11258562target : [object HTMLDivElement]srcElement : undefinedshiftKey : falsescreenY : 154screenX : 124relatedTarget : nullrelatedNode : undefinedprevValue : undefinedpageY : 46pageX : 124originalTarget : [object HTMLDivElement]newValue : undefinedmetaKey : falsekeyCode : undefinedhandler : function (e) {}fromElement : undefinedeventPhase : 2detail : 1data : undefinedcurrentTarget : [object HTMLDivElement]ctrlKey : falseclientY : 46clientX : 124charCode : undefinedcancelable : truebutton : 0bubbles : trueattrName : undefinedattrChange : undefinedjQuery1229092311220 : truepreventDefault : function () {if (d.preventDefault) {d.preventDefault();}d.returnValue = false;}stopPropagation : function () {if (d.stopPropagation) {d.stopPropagation();}d.cancelBubble = true;} |
將測試代碼事件改為dblclick之後可以很簡單的得到雙擊的結果
IE |
FF |
originalEvent : [object]undefined : undefinedwhich : undefinedwheelDelta : 0view : undefinedtype : dblclicktoElement : nulltimeStamp : 1229094138735target : [object]srcElement : [object]shiftKey : falsescreenY : 173screenX : 126relatedTarget : undefinedrelatedNode : undefinedprevValue : undefinedpageY : 51pageX : 124originalTarget : undefinednewValue : undefinedmetaKey : undefinedkeyCode : 0handler : function(e){}fromElement : nulleventPhase : undefineddetail : undefineddata : undefinedcurrentTarget : undefinedctrlKey : falseclientY : 53clientX : 126charCode : undefinedcancelable : undefinedbutton : 0bubbles : undefinedattrName : undefinedattrChange : undefinedjQuery1229094137079 : truepreventDefault : function(){if(d.preventDefault)d.preventDefault();d.returnValue=false}stopPropagation : function(){if(d.stopPropagation)d.stopPropagation();d.cancelBubble=true} |
originalEvent : [object MouseEvent]undefined : undefinedwhich : 1wheelDelta : undefinedview : [object Window]type : dblclicktoElement : undefinedtimeStamp : 1229094216813target : [object HTMLDivElement]srcElement : undefinedshiftKey : falsescreenY : 141screenX : 137relatedTarget : nullrelatedNode : undefinedprevValue : undefinedpageY : 33pageX : 137originalTarget : [object HTMLDivElement]newValue : undefinedmetaKey : falsekeyCode : undefinedhandler : function (e) {}fromElement : undefinedeventPhase : 2detail : 2data : undefinedcurrentTarget : [object HTMLDivElement]ctrlKey : falseclientY : 33clientX : 137charCode : undefinedcancelable : truebutton : 0bubbles : trueattrName : undefinedattrChange : undefinedjQuery1229094214813 : truepreventDefault: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,除了單擊時有延時之外,基本實現了事件的獨立。