Javascript 如何区分鼠标“点击”和“拖动”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6042202/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 19:59:52  来源:igfitidea点击:

How to distinguish mouse "click" and "drag"

javascriptdom-events

提问by Leem

I use jQuery.clickto handle the mouse click event on Raphael graph, meanwhile, I need to handle mouse dragevent, mouse drag consists of mousedown, mouseupand mousemovein Raphael.

jQuery.click用来处理 Raphael 图上的鼠标点击事件,同时,我需要处理鼠标drag事件,鼠标拖动由mousedown,mouseupmousemoveRaphael 组成。

It is difficult to distinguish clickand dragbecause clickalso contain mousedown& mouseup, How can I distinguish mouse "click" & mouse "drag" then in Javascript?

很难区分clickdrag因为click也包含mousedown& mouseup,如何在Javascript中区分鼠标“单击”和鼠标“拖动”?

回答by wong2

I think the difference is that there is a mousemovebetween mousedownand mouseupin a drag, but not in a click.

我认为不同之处在于拖动中有mousemove之间mousedownmouseup中,而不是点击中。

You can do something like this:

你可以这样做:

const element = document.createElement('div')
element.innerHTML = 'test'
document.body.appendChild(element)
let moved
let downListener = () => {
    moved = false
}
element.addEventListener('mousedown', downListener)
let moveListener = () => {
    moved = true
}
element.addEventListener('mousemove', moveListener)
let upListener = () => {
    if (moved) {
        console.log('moved')
    } else {
        console.log('not moved')
    }
}
element.addEventListener('mouseup', upListener)

// release memory
element.removeEventListener('mousedown', downListener)
element.removeEventListener('mousemove', moveListener)
element.removeEventListener('mouseup', upListener)

回答by Gustavo Rodrigues

In case you are already using jQuery:

如果您已经在使用 jQuery:

var $body = $('body');
$body.on('mousedown', function (evt) {
  $body.on('mouseup mousemove', function handler(evt) {
    if (evt.type === 'mouseup') {
      // click
    } else {
      // drag
    }
    $body.off('mouseup mousemove', handler);
  });
});

回答by Przemek

Cleaner ES2015

清洁工 ES2015

let drag = false;

document.addEventListener('mousedown', () => drag = false);
document.addEventListener('mousemove', () => drag = true);
document.addEventListener('mouseup', () => console.log(drag ? 'drag' : 'click'));

Didn't experience any bugs, as others comment.

没有遇到任何错误,正如其他人评论的那样。

回答by nirvana-msu

This should work well. Similar to the accepted answer (though using jQuery), but the isDraggingflag is only reset if the new mouse position differs from that on mousedownevent. Unlike the accepted answer, that works on recent versions of Chrome, where mousemoveis fired regardless of whether mouse was moved or not.

这应该运作良好。类似于已接受的答案(尽管使用 jQuery),但isDragging仅当新鼠标位置与mousedown事件时的位置不同时才会重置该标志。与接受的答案不同,它适用于最新版本的 Chrome,mousemove无论鼠标是否移动,都会触发。

var isDragging = false;
var startingPos = [];
$(".selector")
    .mousedown(function (evt) {
        isDragging = false;
        startingPos = [evt.pageX, evt.pageY];
    })
    .mousemove(function (evt) {
        if (!(evt.pageX === startingPos[0] && evt.pageY === startingPos[1])) {
            isDragging = true;
        }
    })
    .mouseup(function () {
        if (isDragging) {
            console.log("Drag");
        } else {
            console.log("Click");
        }
        isDragging = false;
        startingPos = [];
    });

You may also adjust the coordinate check in mousemoveif you want to add a little bit of tolerance (i.e. treat tiny movements as clicks, not drags).

mousemove如果您想增加一点容差(即将微小的移动视为点击,而不是拖动),您也可以调整坐标检入。

回答by Dorus

If you feel like using Rxjs:

如果你喜欢使用Rxjs

var element = document;

Rx.Observable
  .merge(
    Rx.Observable.fromEvent(element, 'mousedown').mapTo(0),
    Rx.Observable.fromEvent(element, 'mousemove').mapTo(1)
  )
  .sample(Rx.Observable.fromEvent(element, 'mouseup'))
  .subscribe(flag => {
      console.clear();
      console.log(flag ? "drag" : "click");
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://unpkg.com/@reactivex/[email protected]/dist/global/Rx.js"></script>

This is a direct clone of what @wong2 did in his answer, but converted to RxJs.

这是@wong2 在他的回答中所做的直接克隆,但转换为 RxJs。

Also interesting use of sample. The sampleoperator will take the latest value from the source (the mergeof mousedownand mousemove) and emit it when the inner observable (mouseup) emits.

也很有趣的使用sample。所述sample操作者将采取的最新值从源(mergemousedownmousemove),并发射它的内观察到的(当mouseup)发射。

回答by Francisco Aquino

As mrjrdnthms points out in his comment on the accepted answer, this no longer works on Chrome (it always fires the mousemove), I've adapted Gustavo's answer (since I'm using jQuery) to address the Chrome behavior.

正如 mrjrdnthms 在他对已接受答案的评论中指出的那样,这不再适用于 Chrome(它总是触发 mousemove),我已经调整了 Gustavo 的答案(因为我使用的是 jQuery)来解决 Chrome 的行为。

var currentPos = [];

$(document).on('mousedown', function (evt) {

   currentPos = [evt.pageX, evt.pageY]

  $(document).on('mousemove', function handler(evt) {

    currentPos=[evt.pageX, evt.pageY];
    $(document).off('mousemove', handler);

  });

  $(document).on('mouseup', function handler(evt) {

    if([evt.pageX, evt.pageY].equals(currentPos))
      console.log("Click")
    else
      console.log("Drag")

    $(document).off('mouseup', handler);

  });

});

The Array.prototype.equalsfunction comes from this answer

Array.prototype.equals功能来自这个答案

回答by silverwind

Using jQuery with a 5 pixel x/y theshold to detect the drag:

使用带有 5 像素 x/y 阈值的 jQuery 来检测拖动:

var dragging = false;
$("body").on("mousedown", function(e) {
  var x = e.screenX;
  var y = e.screenY;
  dragging = false;
  $("body").on("mousemove", function(e) {
    if (Math.abs(x - e.screenX) > 5 || Math.abs(y - e.screenY) > 5) {
      dragging = true;
    }
  });
});
$("body").on("mouseup", function(e) {
  $("body").off("mousemove");
  console.log(dragging ? "drag" : "click");
});

回答by andreyrd

All these solutions either break on tiny mouse movements, or are overcomplicated.

所有这些解决方案要么因微小的鼠标移动而中断,要么过于复杂。

Here is a simple adaptable solution using two event listeners. Delta is the distance in pixels that you must move horizontally or vertically between the up and down events for the code to classify it as a drag rather than a click. This is because sometimes you will move the mouse or your finger a few pixels before lifting it.

这是一个使用两个事件侦听器的简单适应性解决方案。Delta 是以像素为单位的距离,您必须在向上和向下事件之间水平或垂直移动代码才能将其归类为拖动而不是点击。这是因为有时您会在抬起鼠标或手指之前将其移动几个像素。

const delta = 6;
let startX;
let startY;

element.addEventListener('mousedown', function (event) {
  startX = event.pageX;
  startY = event.pageY;
});

element.addEventListener('mouseup', function (event) {
  const diffX = Math.abs(event.pageX - startX);
  const diffY = Math.abs(event.pageY - startY);

  if (diffX < delta && diffY < delta) {
    // Click!
  }
});

回答by jqgsninimo

If just to filter out the drag case, do it like this:

如果只是为了过滤掉拖动案例,请这样做:

var moved = false;
$(selector)
  .mousedown(function() {moved = false;})
  .mousemove(function() {moved = true;})
  .mouseup(function(event) {
    if (!moved) {
        // clicked without moving mouse
    }
  });

回答by Waqas Bukhary

Pure JS with DeltaX and DeltaY

带有 DeltaX 和 DeltaY 的纯 JS

This DeltaX and DeltaY as suggested by a commentin the accepted answer to avoid the frustrating experience when trying to click and get a drag operation instead due to a one tick mousemove.

这个 DeltaX 和 DeltaY 按照已接受的答案中的评论所建议的,以避免在尝试单击并获得拖动操作时的令人沮丧的体验,而不是由于一个勾号鼠标移动。

    deltaX = deltaY = 2;//px
    var element = document.getElementById('divID');
    element.addEventListener("mousedown", function(e){
        if (typeof InitPageX == 'undefined' && typeof InitPageY == 'undefined') {
            InitPageX = e.pageX;
            InitPageY = e.pageY;
        }

    }, false);
    element.addEventListener("mousemove", function(e){
        if (typeof InitPageX !== 'undefined' && typeof InitPageY !== 'undefined') {
            diffX = e.pageX - InitPageX;
            diffY = e.pageY - InitPageY;
            if (    (diffX > deltaX) || (diffX < -deltaX)
                    || 
                    (diffY > deltaY) || (diffY < -deltaY)   
                    ) {
                console.log("dragging");//dragging event or function goes here.
            }
            else {
                console.log("click");//click event or moving back in delta goes here.
            }
        }
    }, false);
    element.addEventListener("mouseup", function(){
        delete InitPageX;
        delete InitPageY;
    }, false);

   element.addEventListener("click", function(){
        console.log("click");
    }, false);