如何在Javascript/jQuery中检测双击拖动?

7

我想在网页中检测用户通过拖动选中文本的情况。然而,在Windows操作系统中,有一种我称之为“双击拖动”的场景(如果已有更好的名称,请见谅),我无法找出如何检测它。具体步骤如下:

  1. 按下鼠标按钮
  2. 快速释放鼠标按钮
  3. 再次快速按下鼠标按钮
  4. 按住鼠标按钮并拖动

这会导致拖动选择整个单词。从用户角度来看,这是非常有用的技巧。

我的目标是区分双击拖动和先单击再拖动两种情况。所以,当我到达第2步时,我会得到一个点击事件,但我不想立刻将其视为点击事件;我要观察他们是否将立即进入第3步。

据推测,Windows系统基于时间和鼠标在第2步和第3步之间移动的距离来检测此操作,但我不知道它使用的参数,因此无法复制Windows系统的逻辑。请注意,即使鼠标在第2步和第3步之间根本没有移动,我仍会收到mousemove事件。

我意识到我应该设计适合触摸的、设备中立的界面。我也有意支持其他设备,但这是一个面向Windows电脑用户的企业应用程序,因此如果可能的话,我希望优化此情况。


这可能会对您有所帮助http://stackoverflow.com/questions/9950042/javascript-click-doubleclick-and-drag-in-the-same-element。尽管您需要根据自己的需求进行修改。 - Zzyrk
我不确定我理解了这个问题,但是如果你在浏览器中双击一个单词,它不是默认被选中了吗?所以你真正需要做的就是将文本选择包装起来,并使其可拖动。 - adeneo
2个回答

4
我们做了类似的事情。我们的最终解决方案是创建一个点击处理程序,抑制默认响应,然后将全局变量设置为当前日期/时间。然后我们设置另一个函数在大约200毫秒左右触发“点击”事件的处理。这是我们的基本函数。
然后我们修改它以查看全局变量,以确定上次点击发生的时间。如果时间小于200毫秒(根据您的需求进行修改),我们设置一个标志,使点击处理程序失败,并调用双击处理程序。
您可以通过让单击和双击处理程序手动触发拖动功能来扩展该方法。
我现在无法访问上述代码,但是下面是一个使用该框架跟踪键盘点击以确定扫描仪或用户是否已完成字段输入的示例:
    var lastKeyPress    = loadTime.getTime();

    // This function fires on each keypress while the cursor is in the field.  It checks the field value for preceding and trailing asterisks, which
    // denote use of a scanner.  If these are found it cleans the input and clicks the add button.  This function also watches for rapid entry of keyup events, which 
    // also would denote a scanner, possibly one that does not use asterisks as control characters.
    function checkForScanKeypress() {
        var iVal = document.getElementById('field_id').value;

        var currentTime = new Date()
        var temp        = currentTime.getTime();
        if (temp - lastKeyPress < 80) {
            scanCountCheck = scanCountCheck + 1;
        } else {
            scanCountCheck = 0;
        }
        lastKeyPress    = currentTime.getTime();
    }


    // The script above tracks how many successive times two keyup events have occurred within 80 milliseconds of one another.  The count is reset
    // if any keypress occurs more than 80 milliseconds after the last (preventing false positives from manual entry).  The script below runs
    // every 200 milliseconds and looks to see if more than 3 keystrokes have occurred in such rapid succession.  If so, it is assumed that a scanner
    // was used for this entry.  It then waits until at least 200 milliseconds after the last event and then triggers the next function.
    // The 200ms buffer after the last keyup event insures the function is not called before the scanner completes part number entry.
    function checkForScan() {
        var currentTime = new Date();
        var temp        = currentTime.getTime();
        if (temp - lastKeyPress > 200 && scanCountCheck > 3) {
            FiredWhenUserStopsTyping();
            scanCountCheck = 0;
        }
        setTimeout(checkForScan, 200);
    }

以下是我根据上述想法刚刚写的一些代码。它未经测试,也不包含实际的拖动事件,但应该能为您提供一个很好的起点:

    var lastClick   = loadTime.getTime();

    function fireOnClickEvent(event) {
        event.preventDefault;

        var currentTime = new Date()
        var temp        = currentTime.getTime();
        if (temp - lastClick < 80) {
            clearTimeout(tf);
            doubleClickHandler();
        } else {
            tf          = setTimeout(singleClickHandler, 100);
        }
        lastClick       = currentTime.getTime();
    }

    function singleClickHandler() {
        // Begin normal drag function
    }

    function doubleClickHandler() {
        // Begin alternate drag function
    }

谢谢。我希望不必采用这种低级别的点击检测,因为这样会对用户的PC设置进行二次猜测,但从缺乏其他回复来看,我想没有简单的解决方案。 - Andy
很遗憾,我们没有找到任何解决方案。我想我们找到了一些库和其他更为结构化的方法,但是兼容性,特别是对于旧版浏览器而言,还不够完善。这是我们能想到的最好的解决问题的方式。抱歉。 - Nicholas

0
一个单击双击拖动操作包含以下事件序列:
mousedown -> mouseup -> click -> mousedown -> mousemove

考虑到这一点,我想出了这个简单的解决方案:

let maybeDoubleClickDragging = false;
    let maybeDoubleClickDraggingTimeout;
    const element = document.querySelector('#container');

    element.addEventListener("click", function (e) {
      maybeDoubleClickDragging = true;
      element.removeEventListener("mousemove", handleMousemove);

    });

    element.addEventListener("mousedown", (e) => {
      element.addEventListener("mousemove", handleMousemove);

      if (maybeDoubleClickDragging) {
        clearTimeout(maybeDoubleClickDraggingTimeout);
        return;
      }
    });

    element.addEventListener("mouseup", (event) => {
      maybeDoubleClickDraggingTimeout = setTimeout(() => {
        maybeDoubleClickDragging = false;
      }, 200);
    });

    function handleMousemove(e) {
       if(maybeDoubleClickDragging) {
       element.textContent = 'you are double-click-dragging'
       }
    
    }
#container {
 width: 300px;
 height: 300px;
 background: yellow;
 }
<div id="container"></div>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接