답변:
차이점은 mousemove
사이 mousedown
에mouseup
드래그 드래그 에 있지만 클릭에는 없다는 것입니다.
다음과 같이 할 수 있습니다 :
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)
mousedown
하고 mouseup
대신에 듣는 mousemove
플래그를 설정하는 이벤트입니다. 또한 @mrjrdnthms
이미 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);
});
});
drag
됩니다. 다른 의견과 마찬가지로 추가 범위가 필요할 수 있습니다.
evt
두 번째의 위치와 비교 evt
예를 들어, 그래서, : if (evt.type === 'mouseup' || Math.abs(evt1.pageX - evt2.pageX) < 5 || Math.abs(evt1.pageY - evt2.pageY) < 5) { ...
.
.on('mouseup mousemove touchend touchmove')
위치 변수를 설정하지 않습니다. 훌륭한 솔루션!
let drag = false;
document.addEventListener('mousedown', () => drag = false);
document.addEventListener('mousemove', () => drag = true);
document.addEventListener('mouseup', () => console.log(drag ? 'drag' : 'click'));
다른 사람들이 언급했듯이 버그가 발생하지 않았습니다.
이것은 잘 작동합니다. 허용 된 답변과 유사하지만 (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 = [];
});
mousemove
약간의 공차를 추가 하려면 좌표 체크인을 조정할 수도 있습니다 (예 : 작은 움직임은 드래그가 아닌 클릭으로 처리).
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/rxjs@5.4.1/dist/global/Rx.js"></script>
이것은 @ wong2가 그의 대답에서 한 일을 직접 복제했지만 RxJ로 변환되었습니다.
의 흥미로운 사용 sample
. sample
오퍼레이터는 소스로부터의 최신의 값을 (뜻 merge
의 mousedown
및 mousemove
) 때 내부 관찰 (그것을 방출 mouseup
) 방출한다.
mrjrdnthms가 허용 된 답변에 대한 그의 의견에서 지적한 것처럼, 이것은 더 이상 Chrome에서 작동하지 않으며 (항상 마우스 이동을 발생시킵니다) Chrome 동작을 해결하기 위해 Gustavo의 답변을 조정했습니다 (jQuery를 사용하기 때문에).
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);
});
});
Array.prototype.equals
기능이에서 오는 대답
[evt.pageX, evt.pageY].equals()
명령 에서 오류가 발생했습니다 . 나는 그것을로 바꾸었고 (evt.pageX === currentPos[0] && evt.pageY===currentPos[1])
모든 것이 좋았습니다. :)
equals
코드의 요구가 내 게시물의 하단에있는 링크에서 추가 할
currentPos
에 mousemove
? 이것이 드래그를 클릭으로 취급한다는 의미는 아닙니까?
"mouseup"
마우스를 움직이고있는 동안에는 작동하지 않습니다 .
이러한 모든 솔루션은 작은 마우스 움직임으로 인해 깨지거나 지나치게 복잡합니다.
다음은 두 개의 이벤트 리스너를 사용하는 간단한 적응 형 솔루션입니다. 델타는 코드가 클릭이 아닌 드래그로 코드를 분류하기 위해 위쪽 및 아래쪽 이벤트 사이에서 가로 또는 세로로 이동해야하는 거리 (픽셀 단위)입니다. 마우스 나 손가락을 들어 올리기 전에 몇 픽셀 움직일 때가 있기 때문입니다.
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!
}
});
delta
이것에 무엇이 사용 되는지 알 수 있습니까? 휴대 기기의 탭과 관련이 있습니까?
delta
이 "한 번의 마우스 이동으로 인해 클릭하여 드래그 조작을 시도하는 것이 좌절 될 것"이라고 생각합니다.
드래그를 감지하기 위해 5 픽셀 x / y theshold와 함께 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");
});
드래그 케이스를 필터링하려면 다음과 같이하십시오.
var moved = false;
$(selector)
.mousedown(function() {moved = false;})
.mousemove(function() {moved = true;})
.mouseup(function(event) {
if (!moved) {
// clicked without moving mouse
}
});
이 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);
OSM 맵 (클릭시 마커 위치)에 대한 공개 조치의 경우 1) 마우스 다운 지속 시간을 결정하는 방법-> (각 클릭마다 새로운 마커를 만드는 것을 상상할 수 없음) 2) 아래-> 위로 마우스를 움직입니다 (예 : 사용자가지도를 끌고 있음).
const map = document.getElementById('map');
map.addEventListener("mousedown", position);
map.addEventListener("mouseup", calculate);
let posX, posY, endX, endY, t1, t2, action;
function position(e) {
posX = e.clientX;
posY = e.clientY;
t1 = Date.now();
}
function calculate(e) {
endX = e.clientX;
endY = e.clientY;
t2 = (Date.now()-t1)/1000;
action = 'inactive';
if( t2 > 0.5 && t2 < 1.5) { // Fixing duration of mouse down->up
if( Math.abs( posX-endX ) < 5 && Math.abs( posY-endY ) < 5 ) { // 5px error on mouse pos while clicking
action = 'active';
// --------> Do something
}
}
console.log('Down = '+posX + ', ' + posY+'\nUp = '+endX + ', ' + endY+ '\nAction = '+ action);
}
거리 임계 값을 사용하는 클래스 기반 바닐라 JS를 사용하는 또 다른 솔루션
private initDetectDrag(element) {
let clickOrigin = { x: 0, y: 0 };
const dragDistanceThreshhold = 20;
element.addEventListener('mousedown', (event) => {
this.isDragged = false
clickOrigin = { x: event.clientX, y: event.clientY };
});
element.addEventListener('mousemove', (event) => {
if (Math.sqrt(Math.pow(clickOrigin.y - event.clientY, 2) + Math.pow(clickOrigin.x - event.clientX, 2)) > dragDistanceThreshhold) {
this.isDragged = true
}
});
}
그리고 클래스에 추가하십시오 (SOMESLIDER_ELEMENT는 전 세계적 으로 문서화 될 수 있습니다).
private isDragged: boolean;
constructor() {
this.initDetectDrag(SOMESLIDER_ELEMENT);
this.doSomeSlideStuff(SOMESLIDER_ELEMENT);
element.addEventListener('click', (event) => {
if (!this.sliderIsDragged) {
console.log('was clicked');
} else {
console.log('was dragged, ignore click or handle this');
}
}, false);
}
특정 요소의 클릭 또는 드래그 동작을 확인하려면 본문을 듣지 않아도됩니다.
$(document).ready(function(){
let click;
$('.owl-carousel').owlCarousel({
items: 1
});
// prevent clicks when sliding
$('.btn')
.on('mousemove', function(){
click = false;
})
.on('mousedown', function(){
click = true;
});
// change mouseup listener to '.content' to listen to a wider area. (mouse drag release could happen out of the '.btn' which we have not listent to). Note that the click will trigger if '.btn' mousedown event is triggered above
$('.btn').on('mouseup', function(){
if(click){
$('.result').text('clicked');
} else {
$('.result').text('dragged');
}
});
});
.content{
position: relative;
width: 500px;
height: 400px;
background: #f2f2f2;
}
.slider, .result{
position: relative;
width: 400px;
}
.slider{
height: 200px;
margin: 0 auto;
top: 30px;
}
.btn{
display: flex;
align-items: center;
justify-content: center;
text-align: center;
height: 100px;
background: #c66;
}
.result{
height: 30px;
top: 10px;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/owl.carousel.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.carousel.min.css" />
<div class="content">
<div class="slider">
<div class="owl-carousel owl-theme">
<div class="item">
<a href="#" class="btn" draggable="true">click me without moving the mouse</a>
</div>
<div class="item">
<a href="#" class="btn" draggable="true">click me without moving the mouse</a>
</div>
</div>
<div class="result"></div>
</div>
</div>
@Przemek의 답변에서
function listenClickOnly(element, callback, threshold=10) {
let drag = 0;
element.addEventListener('mousedown', () => drag = 0);
element.addEventListener('mousemove', () => drag++);
element.addEventListener('mouseup', e => {
if (drag<threshold) callback(e);
});
}
listenClickOnly(
document,
() => console.log('click'),
10
);