如何区分单击事件和双击事件?


116

我在id中有一个按钮 "my_id"。我在这个元素上附加了两个jQuery事件

1。

$("#my_id").click(function() { 
    alert('single click');
});

2。

$("#my_id").dblclick(function() {
    alert('double click');
});

但是每次它给我 single click


单击总是会触发,除非它确实在指定的双击时间内发生,否则无法知道是否会发生双击。
Pieter Germishuys 2011年

7
这是可能的,请检查我的答案。第一次单击后必须等待几毫秒,然后检查是否有新的单击,直到指定的时间为止。这样,您就可以知道这是简单的还是双击的。
艾德里安·舒勒

Answers:


65

您需要使用超时来检查第一次点击后是否还有另一次点击。

这是窍门

// Author:  Jacek Becela
// Source:  http://gist.github.com/399624
// License: MIT

jQuery.fn.single_double_click = function(single_click_callback, double_click_callback, timeout) {
  return this.each(function(){
    var clicks = 0, self = this;
    jQuery(this).click(function(event){
      clicks++;
      if (clicks == 1) {
        setTimeout(function(){
          if(clicks == 1) {
            single_click_callback.call(self, event);
          } else {
            double_click_callback.call(self, event);
          }
          clicks = 0;
        }, timeout || 300);
      }
    });
  });
}

用法:

$("button").single_double_click(function () {
  alert("Try double-clicking me!")
}, function () {
  alert("Double click detected, I'm hiding")
  $(this).hide()
})
<button>Click Me!</button>

编辑:

如下所述,最好使用本机dblclick事件:http : //www.quirksmode.org/dom/events/click.html

或jQuery提供的一个:http : //api.jquery.com/dblclick/


14
一般而言,这似乎工作得很好,但是两次单击之间允许的延迟时间(两次点击被解释为两次单击)是否因系统配置而有所不同?这也可能是更安全的依靠dblclick事件
乔恩·Z ^

1
是的,我认为您是对的,dblclick绝对是今天的发展之路。jQuery还处理以下事件:api.jquery.com/dblclick
Adrien Schuler

14
@AdrienSchuler-从文档中链接:建议不要将处理程序绑定到同一元素的click和dblclick事件。问题是两者兼而有之
阿尔瓦罗·冈萨雷斯

如果event.detail可用,这是从单击处理程序中检测双击的最佳方法。看到这个答案
卡尔·G

好的解决方案Adrien,在需要对一个对象进行一次单击和双击事件并且只应触发一个事件的情况下,我需要它。因此,您的解决方案对我来说是完美的。我只是对其进行了一些改进,以控制“ this”:playcode.io/492022
LOstBrOkenKeY

79

dblclick事件的行为在Quirksmode中进行了解释

a的事件顺序dblclick为:

  1. 按下鼠标
  2. 鼠标向上
  3. 点击
  4. 按下鼠标
  5. 鼠标向上
  6. 点击
  7. dblclick

此规则的一个例外是(当然)Internet Explorer,其自定义顺序为:

  1. 按下鼠标
  2. 鼠标向上
  3. 点击
  4. 鼠标向上
  5. dblclick

如您所见,在同一个元素上一起听这两个事件将导致对click处理程序的额外调用。


不确定dblclick是否可靠...如果单击一次,请等待一两秒钟,然后再次单击,dblclick第二次单击时会收到事件!
迈克尔(Michael)

如此长的单击对于例如重命名文件很有用。如果有“ longClick”之类的参数来区分它,那就太好了。
PeterM '18 -10-25

1
如果event.detail可用,这是从单击处理程序中检测双击的最佳方法。看到这个答案
卡尔·G

38

原来没有利用更多的即席状态和setTimeout,而是有一个本机属性detail,您可以从该event对象访问它!

element.onclick = event => {
   if (event.detail === 1) {
     // it was a single click
   } else if (event.detail === 2) {
     // it was a double click
   }
};

现代浏览器甚至IE-9都支持它:)

来源:https : //developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail


最佳答案:)
sk8terboi87 1919年

3
在双击的情况下,event.detail === 1仍然会触发一次单击(其中)。请参阅我的小提琴对此主题的评论
法比恩·斯诺瓦特

好点@FabienSnauwaert。我想我们不能在特定元素上同时绑定单击事件处理程序和双击事件处理程序。上面的方法可用于确定双击而不用借助计时器之类的东西。
kyw

您仍然需要在第一次点击时启用计时器,以免触发。检查我的回答如下stackoverflow.com/questions/5497073/...

只是一个可访问性注意事项:如果键盘触发了click事件(例如,当用户使用Tab键聚焦按钮并按Enter时),则会生成该事件,并将detail属性设置为0,因此可以进行一些if(evt.detail !== 1) return;意外的重复操作单击将阻止没有鼠标的用户对该按钮的访问。
格里斯托

25

一个简单的功能。不需要jquery或其他框架。将函数作为参数传递

<div onclick="doubleclick(this, function(){alert('single')}, function(){alert('double')})">click me</div>
    <script>
        function doubleclick(el, onsingle, ondouble) {
            if (el.getAttribute("data-dblclick") == null) {
                el.setAttribute("data-dblclick", 1);
                setTimeout(function () {
                    if (el.getAttribute("data-dblclick") == 1) {
                        onsingle();
                    }
                    el.removeAttribute("data-dblclick");
                }, 300);
            } else {
                el.removeAttribute("data-dblclick");
                ondouble();
            }
        }
    </script>

2
我认为这应该是最好的答案。但是,我必须将超时时间减少到200,才能在Windows IE8上运行,但是此值可能取决于操作系统和用户。并且还保存了计时​​器参考,以便在注册双击时能够取消单击的执行。
xpereta

感谢您提供的这段代码,它在chrome和firefox上非常有效(尽管chrome不需要此hack即可与dbl和single一起使用)。
胜利者2014年

使用el.dataset.dblclick将是一种更好的方法。
WORMSS,2016年

如果event.detail可用,这是从单击处理程序中检测双击的最佳方法。看到这个答案
卡尔·G

12

恐怕该行为取决于浏览器:

将处理程序绑定到同一元素的click和dblclick事件都是不可取的。触发事件的顺序因浏览器而异,其中一些事件在dblclick之前收到两个click事件,其他事件仅收到一个。双击灵敏度(检测为两次单击之间的最长间隔时间)可能因操作系统和浏览器而异,并且通常可由用户配置。

http://api.jquery.com/dblclick/

在Firefox中运行代码,click()处理程序中的alert()阻止您再次单击。如果删除此类警报,则会同时发生这两个事件。


如果event.detail可用,这是从单击处理程序中检测双击的最佳方法。看到这个答案
卡尔·G

11

为了双击(单击两次),您必须先单击一次。该click()处理程序会在您的第一次点击时触发,并且由于警报弹出,因此您没有机会进行第二次点击来触发dblclick()处理程序。

更改您的处理程序以执行除an之外的其他操作alert(),您将看到该行为。(可能会更改元素的背景颜色):

$("#my_id").click(function() { 
    $(this).css('backgroundColor', 'red')
});

$("#my_id").dblclick(function() {
    $(this).css('backgroundColor', 'green')
});

7

随着时间的流逝,此答案已过时,请检查@kyw的解决方案。

我创建了一个由@AdrienSchuler发布的要旨启发的解决方案。仅当您希望将单击绑定和双击绑定到元素时,才使用此解决方案。否则,我建议使用本机clickdblclick侦听器。

这些是差异:

  • Vanillajs,无依赖项
  • 不要等待 setTimeout来处理click或doubleclick处理程序
  • 双击时,它会先触发点击处理程序,然后触发双击处理程序

Javascript:

function makeDoubleClick(doubleClickCallback, singleClickCallback) {
    var clicks = 0, timeout;
    return function() {
        clicks++;
        if (clicks == 1) {
            singleClickCallback && singleClickCallback.apply(this, arguments);
            timeout = setTimeout(function() { clicks = 0; }, 400);
        } else {
            timeout && clearTimeout(timeout);
            doubleClickCallback && doubleClickCallback.apply(this, arguments);
            clicks = 0;
        }
    };
}

用法:

var singleClick = function(){ console.log('single click') };
var doubleClick = function(){ console.log('double click') };
element.addEventListener('click', makeDoubleClick(doubleClick, singleClick));

以下是jsfiddle中的用法,jQuery按钮是已接受答案的行为。

jsfiddle


2
上面的代码和小提琴的“香草”版本不起作用...这是固定的香草版本:jsfiddle.net/jeum/cpbwx5vr/19
jeum 2016年

@jeum在每个浏览器中,它仍然为我提供了窍门。什么是“无效”,您期望什么?看来您的版本没有按照我的意图执行。
A1rPun

拳头我已经修改了我的版本(删除了双闭包),请尝试新的版本:jsfiddle.net/jeum/cpbwx5vr/20您的小提琴(香草版本)存在的问题是双击触发了单个处理程序:它只检索单个+为我加倍。
jeum

@jeum一个错误。是的,我的答案与此处接受的答案和其他答案不同,我在这一行中也指定了以下区别:
触发

1
是,再次发生错误,因此该版本响应了主要问题:jsfiddle.net/jeum/cpbwx5vr/21。现在,关于您的版本(确实我不了解),您是否注意到jQuery无法满足您的要求?
jeum

5

另一种基于A1rPun答案的简单Vanilla解决方案(有关jQuery解决方案,请参见他的小提琴,二者均在示例中)。

似乎在用户双击时不触发单击处理程序,单击处理程序一定是在延迟后触发的...

var single = function(e){console.log('single')},
    double = function(e){console.log('double')};

var makeDoubleClick = function(e) {

  var clicks = 0,
      timeout;

  return function (e) {

    clicks++;

    if (clicks == 1) {
      timeout = setTimeout(function () {
        single(e);
        clicks = 0;
      }, 250);
    } else {
      clearTimeout(timeout);
      double(e);
      clicks = 0;
    }
  };
}
document.getElementById('btnVanilla').addEventListener('click', makeDoubleClick(), false);

3
如果您不希望单击一下,这确实是最好的选择:)
A1rPun

如果event.detail可用,这是从单击处理程序中检测双击的最佳方法。看到这个答案
卡尔·G

5

这是针对任意事件的jeum代码的替代方法:

 var multiClickHandler = function (handlers, delay) {
    var clicks = 0, timeout, delay = delay || 250;
    return function (e) {
      clicks++;
      clearTimeout(timeout);
      timeout = setTimeout(function () {
        if(handlers[clicks]) handlers[clicks](e);
        clicks = 0;
      }, delay);
    };
  }

  cy.on('click', 'node', multiClickHandler({
    1: function(e){console.log('single clicked ', e.cyTarget.id())},
    2: function(e){console.log('double clicked ', e.cyTarget.id())},
    3: function(e){console.log('triple clicked ', e.cyTarget.id())},
    4: function(e){console.log('quadro clicked ', e.cyTarget.id())},
    // ...
  }, 300));

cytoscape.js应用需要此文件


真好!我们还可以在返回的函数中声明一个新变量,并将其分配给this被单击的元素,并将其传递给处理程序(沿着e或替代)。
HeyJude

5

如何区分一个元素和同一元素的单击和双击?

如果您不需要混合它们,则可以依靠clickdblclick每个将做的工作就好了。

尝试将它们混合时会出现问题:一个dblclick事件实际上也会触发一个click事件,所以你需要确定一个单一的点击是否是一个“独立的”一次点击,或者双击的一部分。

另外:您不应该在同一元素上同时使用clickdblclick

将处理程序绑定到同一元素的click和dblclick事件都是不可取的。触发事件的顺序因浏览器而异,其中一些事件在dblclick之前收到两个click事件,其他事件仅收到一个。双击敏感度(检测为两次单击之间的最长间隔时间)可能因操作系统和浏览器而异,并且通常可由用户配置。
来源:https//api.jquery.com/dblclick/

现在来个好消息:

您可以使用活动的 detail属性来检测与事件相关的点击次数。这使得双击click很容易被检测到。

问题仍然是检测单击,以及它们是否属于双击。为此,我们回到使用计时器并setTimeout

使用data属性(以避免全局变量)将它们包装在一起,而无需自己计算点击次数,我们得到:

HTML:

<div class="clickit" style="font-size: 200%; margin: 2em; padding: 0.25em; background: orange;">Double click me</div>

<div id="log" style="background: #efefef;"></div>

JavaScript:

<script>
var clickTimeoutID;
$( document ).ready(function() {

    $( '.clickit' ).click( function( event ) {

        if ( event.originalEvent.detail === 1 ) {
            $( '#log' ).append( '(Event:) Single click event received.<br>' );

            /** Is this a true single click or it it a single click that's part of a double click?
             * The only way to find out is to wait it for either a specific amount of time or the `dblclick` event.
             **/
            clickTimeoutID = window.setTimeout(
                    function() {
                        $( '#log' ).append( 'USER BEHAVIOR: Single click detected.<br><br>' );
                    },
                    500 // how much time users have to perform the second click in a double click -- see accessibility note below.
                );

        } else if ( event.originalEvent.detail === 2 ) {
            $( '#log' ).append( '(Event:) Double click event received.<br>' );
            $( '#log' ).append( 'USER BEHAVIOR: Double click detected.<br>' );
            window.clearTimeout( clickTimeoutID ); // it's a dblclick, so cancel the single click behavior.
        } // triple, quadruple, etc. clicks are ignored.

    });

});
</script>

演示:

JS小提琴


有关辅助功能和双击速度的说明:

  • 正如Wikipedia所说:“连续两次单击被解释为双击所需要的最大延迟时间尚未标准化。”
  • 无法在浏览器中检测系统的双击速度。
  • 似乎默认值是500毫秒,Windows上的范围是100-900毫米(来源
  • 想想残疾人士,他们在其操作系统设置中将双击速度设置为最低。
    • 如果系统双击速度慢于我们上面默认的500毫秒,则将触发单击和双击行为。
    • 要么不使用依赖结合在一个和同一项目上的单击和双击。
    • 或者:在选项中添加设置以具有增加值的能力。

找到了令人满意的解决方案花了一段时间,希望对您有所帮助!




3

现代的正确答案是接受的答案和@kyw解决方案之间的混合。您需要超时以防止第一次单击,并需要进行event.detail检查以防止第二次单击。

const button = document.getElementById('button')
let timer
button.addEventListener('click', event => {
  if (event.detail === 1) {
    timer = setTimeout(() => {
      console.log('click')
    }, 200)
  }
})
button.addEventListener('dblclick', event => {
  clearTimeout(timer)
  console.log('dblclick')
})
<button id="button">Click me</button>


1

我喜欢避免使用jquery(以及其他90-140k库),并且如前所述,浏览器会先处理onclick,因此这是我在创建的网站上所做的事情(此示例还介绍了如何获取本地xy的点击位置)

clicksNow-0; //global js, owell

function notify2(e, right) {  // called from onclick= and oncontextmenu= (rc)
var x,y,xx,yy;
var ele = document.getElementById('wrap');  
    // offset fixed parent for local win x y
var xxx= ele.offsetLeft;
var yyy= ele.offsetTop;

//NScape
if (document.layers || document.getElementById&&!document.all) {
    xx= e.pageX;
    yy= e.pageY;
} else {
    xx= e.clientX;
    yy= e.clientY;
}
x=xx-xxx;
y=yy-yyy;

clicksNow++;
    // 200 (2/10ths a sec) is about a low as i seem to be able to go
setTimeout( "processClick( " + right + " , " + x + " , " + y + ")", 200);
}

function processClick(right, x, y) {
if (clicksNow==0) return; // already processed as dblclick
if (clicksNow==2) alert('dbl');
clicksNow=0;
    ... handle, etc ...
}

希望能有所帮助


2
完全不需要了解游戏答案的URL。我将其删除,因此该帖子不会被视为垃圾邮件的尝试。
安德鲁·巴伯

1
唯一的负号200是魔法常数,可以与OS中用户的鼠标设置大不相同
Danubian Sailor

1

基于Adrien Schuler(非常感谢您!)答案,用于Datatables.net和许多用途,这里有一个修改:

功能

/**
 * For handle click and single click in child's objects
 * @param {any} selector Parents selector, like 'tr'
 * @param {any} single_click_callback Callback for single click
 * @param {any} double_click_callback Callback for dblclick
 * @param {any} timeout Timeout, optional, 300 by default
 */
jQuery.fn.single_double_click = function (selector, single_click_callback, double_click_callback, timeout) {
    return this.each(function () {
        let clicks = 0;
        jQuery(this).on('click', selector, function (event) {
            let self = this;
            clicks++;
            if (clicks == 1) {
                setTimeout(function () {
                    if (clicks == 1) {
                        single_click_callback.call(self, event);
                    } else {
                        double_click_callback.call(self, event);
                    }
                    clicks = 0;
                }, timeout || 300);
            }
        });
    });
}

$("#MyTableId").single_double_click('tr',
            function () {   //  Click
                let row = MyTable.row(this);
                let id = row.id();
                let data = row.data();
                console.log("Click in "+id+" "+data);
            },
            function () {   //  DBLClick
                let row = MyTable.row(this);
                let id = row.id();
                let data = row.data();
                console.log("DBLClick in "+id+" "+data);
            }
        );

0

这对我有用–

var clicked=0;
function chkBtnClcked(evnt) {
    clicked++;
    // wait to see if dblclick
    if (clicked===1) {
        setTimeout(function() {
            clicked=0;
            .
            .
        }, 300); // test for another click within 300ms
    }
    if (clicked===2) {
        stopTimer=setInterval(function() {
            clicked=0;
            .
            .
        }, 30*1000); // refresh every 30 seconds
    }
}

用法-

<div id="cloneimages" style="position: fixed;" onclick="chkBtnClcked(evnt)"  title="Click for next pic; double-click for slide show"></div>

0

只是发布本机HTML答案,以防万一需要HTML。

<p ondblclick="myFunction()" id = 'id'>Double-click me</p>

当然,这具有本地Jquery选项。即... $('#id').attr('ondblclick',function(){...})或如前所述,$('#id').dblclick(function(){...});


0

我知道这很老,但是下面是一个基本的循环计数器的JS实例,它带有一个计时器来确定单击与双击。希望这对某人有帮助。

var count = 0;
var ele = document.getElementById("my_id");
ele.addEventListener('click', handleSingleDoubleClick, false); 

function handleSingleDoubleClick()
{
  if(!count) setTimeout(TimerFcn, 400); // 400 ms click delay
  count += 1;
}
function TimerFcn() 
{
  if(count > 1) console.log('you double clicked!')
  else console.log('you single clicked')
  count = 0;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.