47

我正在处理 DOM 元素上的 click 和 dblclick 事件。每个执行不同的命令,但我发现双击元素时,除了触发双击事件外,还触发了两次单击事件。防止这种行为的最佳方法是什么?

4

13 回答 13

37

万一其他人偶然发现这个(就像我一样)寻找答案,我能想出的绝对最佳解决方案如下:

    $node.on('click',function(e){
      if(e.originalEvent.detail > 1){
         return;
        /* if you are returning a value from this
         function then return false or cancel 
         the event some other way */
      }
    });

完毕。如果背靠背点击不止一次,第二次,第三次等。不会开火。我绝对更喜欢使用任何类型的计时器。

通过阅读这篇文章,我让自己指向了这个方向。


顺便说一句:我第一次研究这个问题是因为我不小心双击了一个分页链接,事件触发并在回调发生之前完成了两次。

在想出上面的代码之前,我有

 if e.originalEvent.detail === 2 //return

但是,我能够点击链接 3 次(三次点击),虽然第二次点击没有触发,但第三次点击了

于 2015-05-01T18:49:29.203 回答
18

你在评论中说,

我将点击处理程序延迟了 300 毫秒(一个明显且令人讨厌的延迟),甚至......

因此,听起来您想要的是,当您单击时,DOM 应该立即生成一个单击事件,除非单击是双击的第一次单击。

要实现此功能,当您单击时,DOM 需要能够预测这是最终单击还是第一次双击(但我认为 DOM 通常无法预测用户是否要再次点击)。


您尝试在单击和双击时采取的两种不同的操作是什么?IMO,在一个正常的应用程序中,您可能需要这两个事件:例如单击以关注一个元素,然后双击以激活它。

当您必须分离事件时,某些应用程序会使用双击以外的方式:例如,它们使用右键单击或控制单击。

于 2009-05-19T03:08:56.230 回答
11

UIEvent.detail如果您想检测元素被点击的次数并基于此触发事件,您可以使用。

一个简单的例子:

element.addEventListener("click", function (e) {
  if (e.detail === 1) {
    // do something if the element was clicked once.
  } else if (e.detail === 2) {
    // do something else if the element was clicked twice
  }
});
于 2018-03-24T14:22:49.383 回答
6

在这种情况下,最好稍微延迟单击事件的执行。让您的双击处理程序设置一个单击事件将检查的变量。如果该变量具有特定值,可能是boolDoubleClick == true,则不要fire/handle单击。

于 2009-05-19T01:40:59.713 回答
4

感谢这里的所有其他答案,因为当交互需要两者但相互排斥时,它们的组合似乎为我提供了一个合理的解决方案:

var pendingClick = 0;

function xorClick(e) {
    // kill any pending single clicks
    if (pendingClick) {
        clearTimeout(pendingClick);
        pendingClick = 0;
    }

    switch (e.detail) {
        case 1:
            pendingClick = setTimeout(function() {
                console.log('single click action here');
            }, 500);// should match OS multi-click speed
            break;
        case 2:
            console.log('double click action here');
            break;
        default:
            console.log('higher multi-click actions can be added as needed');
            break;
    }
}

myElem.addEventListener('click', xorClick, false);

更新:我在这个 Github 存储库中添加了这种方法的通用版本以及用于触摸设备的 click polyfill,并附有示例:

https://github.com/mckamey/doubleTap.js

于 2012-06-15T20:04:04.433 回答
3

AFAIK DOM Level 2 Events 没有指定双击。它在 IE7 上对我不起作用(令人震惊),但 FF 和 Opera 管理规范没有问题,我可以将所有操作附加到点击事件,但双击只需等到“详细信息”属性事件对象的值为 2。来自文档:“如果在同一屏幕位置发生多次点击,则序列重复,详细属性随着每次重复而递增。”

于 2009-06-29T10:56:50.750 回答
3

这是我在模块中所做的区分

       node.on('click', function(e) {

            //Prepare for double click, continue to clickHandler doesn't come soon enough
            console.log("cleared timeout in click",_this.clickTimeout);
            clearTimeout(_this.clickTimeout);
            _this.clickTimeout = setTimeout(function(){
                console.log("handling click");
                _this.onClick(e);
            },200);
            console.log(_this.clickTimeout);
        });

        node.on('dblclick', function (e) {

            console.log("cleared timeout in dblclick",_this.clickTimeout);
            clearTimeout(_this.clickTimeout);
            // Rest of the handler function
于 2013-02-14T14:20:57.467 回答
2

如果我有 dblclick 事件应该做不同的事情,我会在我的项目中使用这个解决方案来防止点击事件动作。

注意:此解决方案仅适用于 click 和 dblclick,而不适用于 Tripleclick 等任何其他内容。

要查看单击和双击之间的适当时间,请参阅

对不起,我的英语不好。我希望它有帮助:)

var button, isDblclick, timeoutTiming;
var clickTimeout, dblclickTimeout;
//-----
button = $('#button');
isDblclick = false;
/*
the proper time between click and dblclick is not standardized,
and is cutsomizable by user apparently (but this is windows standard I guess!)
*/
timeoutTiming = 500;
//-----
button.on('dblclick', function () {

  isDblclick = true;
  clearTimeout(dblclickTimeout);
  dblclickTimeout = setTimeout(function () {
    isDblclick = false;
  }, timeoutTiming);
  //-----
  // here goes your dblclick codes
  console.log('double clicked! not click.');
  
}).on('click', function () {

  clearTimeout(clickTimeout);
  clickTimeout = setTimeout(function () {
    if(!isDblclick) {
      // here goes your click codes
      console.log('a simple click.');
    }
  }, timeoutTiming);
  
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" id="button">
click/dblclick on this to see the result
</button>

于 2020-05-17T23:03:20.213 回答
0

您可以使用 debounce 将单击处理程序从检测双击/多次单击中释放出来

测试:https ://jsfiddle.net/L3sajybp/

HTML

<div id='toDetect'>
Click or double-click me
</div>
<hr/>

<ol id='info'>
</ol>

JS

function debounce(func, wait, immediate) {
    let timeout;
    return function () {
        const context = this,
            args = arguments;
        const later = function () {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        const callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
}

function debounceSingleClickOnly(func, timeout = 500) {
   function eventHandler (event) {
        const { detail } = event;
      if (detail > 1) {
         console.log('no double click for you '+ func.name);
         console.log('');
         return;
      }
      
      func.apply(this, arguments);
   }
   
   return debounce(eventHandler, timeout); 
}

window.toDetect.addEventListener('click', debounceSingleClickOnly(handleSingleClick));

window.toDetect.addEventListener('dblclick', handleDoubleClick);

function handleS() {
    console.log('S func');
  console.log(this.id);
}

function handleSingleClick(event) { 
   console.log('single click');
   const divText = document.createElement('li');
   divText.appendChild(document.createTextNode('single click'));
   window.info.appendChild(divText)

   console.group();
   console.log('this element was single-clicked: ' + event.target.id);   
   console.log(this.id);  
     console.log('');   
   console.groupEnd();
}

function handleDoubleClick(event) {
   console.log('double click');
   const divText = document.createElement('li');
   divText.appendChild(document.createTextNode('double click'));
   window.info.appendChild(divText);


     console.group();  
   console.log('this element was double-clicked: ' + event.target.id);
   console.log(this.id);  
     console.log('');
   console.groupEnd();
 }

输出:在此处输入图像描述

于 2021-05-05T08:45:36.603 回答
0

我知道这已经很老了,但我想无论如何我都会发布,因为我遇到了同样的问题。这是我解决它的方法。

 $('#alerts-display, #object-display').on('click', ['.item-data-summary', '.item-marker'], function(e) {
    e.preventDefault();

    var id;

    id = setTimeout(() => {
       // code to run here
       return false;
    }, 150);

    timeoutIDForDoubleClick.push(id);
});


$('.panel-items-set-marker-view').on('dblclick', ['.summary', '.marker'], function(e) {
    for (let i = 0; i < timeoutIDForDoubleClick.length; i++) {
       clearTimeout(timeoutIDForDoubleClick[i]);
    }

    // code to run on double click

    e.preventDefault();
});
于 2017-11-21T19:02:29.843 回答
0

这是我防止第二次点击的简单解决方案。当然,我可以在检测到双击时重新启动超时,但实际上我从来不需要它。

clickTimeoutId = null;

onClick(e) {
    if (clickTimeoutId !== null) {
        // Double click, do nothing
        return;
    }

    // Single click
    // TODO smth

    clickTimeoutId = setTimeout(() => {
        clearTimeout(clickTimeoutId);
        clickTimeoutId = null;
    }, 300);
}
于 2020-06-11T10:04:14.890 回答
0

总而言之,要识别同一元素上的 simpleClick 和 doubleClick 事件,只需使用此方法处理 onClick 事件:

var EVENT_DOUBLE_CLICK_DELAY = 220; // Adjust max delay btw two clicks (ms)
var eventClickPending = 0;

function onClick(e){
    if ((e.detail == 2 ) && (eventClickPending!= 0)) {
//       console.log('double click action here ' + e.detail);
         clearTimeout(eventClickPending);
         eventClickPending = 0;
         // call your double click method
         fncEventDblclick(e);

    } else if ((e.detail === 1 ) && (eventClickPending== 0)){   
//      console.log('sigle click action here 1');
        eventClickPending= setTimeout(function() {
//          console.log('Executing sigle click');
            eventClickPending = 0
            // call your single click method
            fncEventClick(e);
        }, EVENT_DOUBLE_CLICK_DELAY);

//    } else { // do nothing
//      console.log('more than two clicks action here ' + e.detail);
            
    }
}
于 2020-11-15T13:06:42.423 回答
-1

  const toggle = () => {
      watchDouble += 1;
      setTimeout(()=>{
        if (watchDouble === 2) {
          console.log('double' + watchDouble)
        } else if (watchDouble === 1) {
          console.log("signle" + watchDouble)
        }
        watchDouble = 0
      },200);

  }
于 2019-05-28T17:27:23.717 回答