javascript - Hvordan skille mellom mus "klikk" og "dra"
Jeg bruker jQuery.click for å håndtere musklikkhendelsen på Raphael-grafen, samtidig trenger jeg å håndtere mus drag-hendelsen, musdrag består av mousedown, mouseup og mousemove i Raphael.
Det er vanskelig å skille click og drag fordi click også inneholder mousedown og mouseup. Hvordan kan jeg da skille mus "click" og mus "drag" i Javascript?
Svar #1
Jeg tror forskjellen er at det er en mousemove mellom mousedown og mouseup i en draing, men ikke i et klikk.
Du kan gjøre noe sånt som dette:
const element = document.createElement('div')
element.textContent = 'test'
document.body.appendChild(element)
let moved = false
const downListener = () => {
moved = false
}
const moveListener = () => {
moved = true
}
const upListener = () => {
if (moved) {
console.log('moved')
} else {
console.log('not moved')
}
}
// Attach listeners
element.addEventListener('mousedown', downListener)
element.addEventListener('mousemove', moveListener)
element.addEventListener('mouseup', upListener)
// Release memory
element.removeEventListener('mousedown', downListener)
element.removeEventListener('mousemove', moveListener)
element.removeEventListener('mouseup', upListener)Svar #2
Alle disse løsningene bryter enten ved små musebevegelser, eller er overkompliserte.
Her er en enkel tilpassbar løsning som bruker to hendelseslyttere. Delta er avstanden i piksler som du må bevege deg horisontalt eller vertikalt mellom opp- og nedhendelsene for at koden skal klassifisere det som en draing i stedet for et klikk. Dette er fordi du noen ganger vil bevege musen eller fingeren noen få piksler før du løfter den.
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!
}
});
Svar #3
Renere ES2015
let drag = false;
document.addEventListener('mousedown', () => drag = false);
document.addEventListener('mousemove', () => drag = true);
document.addEventListener('mouseup', () => console.log(drag ? 'drag' : 'click'));Opplevde ingen feil, som andre kommenterer.
Svar #4
I tilfelle du allerede bruker 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);
});
});
Svar #5
Dette bør fungere bra. Ligner på det aksepterte svaret (selv om det bruker jQuery), men isDragging-flagget tilbakestilles bare hvis den nye museposisjonen er annerledes enn på mousedown-hendelsen. I motsetning til det aksepterte svaret, fungerer dette på nyere versjoner av Chrome, hvor mousemove utløses uavhengig av om musen ble flyttet eller ikke.
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 = [];
});
Du kan også justere koordinatsjekken i mousemove hvis du vil legge til litt toleranse (dvs. behandle små bevegelser som klikk, ikke dra).
Svar #6
Hvis du har lyst til å bruke 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 /dist/global/Rx.js"></script>Dette er en direkte klone av det @wong2 gjorde i sitt svar, men konvertert til RxJs.
Også interessant bruk av sample. sample-operatoren vil ta den nyeste verdien fra kilden (samlingen av mousedown og mousemove) og sende den ut når den indre observable (mouseup) sender ut.
Svar #7
Som mrjrdnthms påpeker i sin kommentar til det aksepterte svaret, fungerer ikke dette lenger på Chrome (det utløser alltid mousemove), jeg har tilpasset Gustavos svar (siden jeg bruker jQuery) for å ta hensyn til Chrome-oppførselen.
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);
});
});
Funksjonen Array.prototype.equals kommer fra dette svaret
