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
How to distinguish mouse "click" and "drag"
提问by Leem
I use jQuery.click
to handle the mouse click event on Raphael graph, meanwhile, I need to handle mouse drag
event, mouse drag consists of mousedown
, mouseup
and mousemove
in Raphael.
我jQuery.click
用来处理 Raphael 图上的鼠标点击事件,同时,我需要处理鼠标drag
事件,鼠标拖动由mousedown
,mouseup
和mousemove
Raphael 组成。
It is difficult to distinguish click
and drag
because click
also contain mousedown
& mouseup
, How can I distinguish mouse "click" & mouse "drag" then in Javascript?
很难区分click
,drag
因为click
也包含mousedown
& mouseup
,如何在Javascript中区分鼠标“单击”和鼠标“拖动”?
回答by wong2
I think the difference is that there is a mousemove
between mousedown
and mouseup
in a drag, but not in a click.
我认为不同之处在于拖动中有mousemove
之间mousedown
和mouseup
中,而不是点击中。
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 isDragging
flag is only reset if the new mouse position differs from that on mousedown
event. Unlike the accepted answer, that works on recent versions of Chrome, where mousemove
is 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 mousemove
if 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 sample
operator will take the latest value from the source (the merge
of mousedown
and mousemove
) and emit it when the inner observable (mouseup
) emits.
也很有趣的使用sample
。所述sample
操作者将采取的最新值从源(merge
的mousedown
和mousemove
),并发射它的内观察到的(当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.equals
function 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);