JavaScript: controlla se il pulsante del mouse è abbassato?


136

C'è un modo per rilevare se un pulsante del mouse è attualmente inattivo in JavaScript?

Conosco l'evento "mousedown", ma non è quello di cui ho bisogno. Qualche volta dopo aver premuto il pulsante del mouse, voglio essere in grado di rilevare se è ancora premuto.

È possibile?


14
Perché accetti una risposta che non risponde alla tua domanda. La registrazione del mouse e del mouse è errata (poiché puoi passare il mouse all'esterno del browser e farti credere che stai ancora trascinando). Venire dopo il tuo problema e raggiungere questa pagina è completamente inutile
Jack

@ Jack risponde alla mia domanda. Per favore leggi la mia domanda e poi leggi la risposta. Apparentemente oltre 100 altre persone concordano sul fatto che sia stata una buona risposta.
TM.

4
sì .. ma io, Alfredo e altri 8 ti stiamo dicendo che il monitoraggio del mouseup e del mouse non è il modo giusto. La risposta corretta dovrebbe comprendere l'analisi dell'oggetto evento nel gestore di tua scelta o l'analisi di tutti gli eventi relativi al mouse (come enter / exit) se hai bisogno di un controllo temporizzato anziché di un controllo guidato da eventi.
Jack

Questa domanda è stata posta e ha risposto 7+ anni fa. Non ricevo una notifica quando ci sono nuove risposte (ma lo faccio per i commenti). Scrivi una risposta migliore e la community la voterà in alto :) Molte informazioni diventano stantie e le cose cambiano.
TM.

2
@TM. Mi dispiace per necro, ma ... No, queste informazioni non raggiungeranno mai la cima. Una non risposta autonoma, una volta accettata, resta per sempre in cima. Inoltre, "oh così tante persone hanno votato per questo" non significa che la risposta sia buona; significa solo che molte persone l'hanno visto, hanno pensato che andasse bene e hanno colpito il voto perché sembrava funzionare per loro.
Finanzia la causa di Monica il

Risposte:


147

Per quanto riguarda la soluzione di Pax: non funziona se l'utente fa clic intenzionalmente o accidentalmente su più di un pulsante. Non chiedermi come lo so :-(.

Il codice corretto dovrebbe essere così:

var mouseDown = 0;
document.body.onmousedown = function() { 
  ++mouseDown;
}
document.body.onmouseup = function() {
  --mouseDown;
}

Con il test in questo modo:

if(mouseDown){
  // crikey! isn't she a beauty?
}

Se vuoi sapere quale pulsante viene premuto, preparati a rendere mouseDown un array di contatori e contali separatamente per pulsanti separati:

// let's pretend that a mouse doesn't have more than 9 buttons
var mouseDown = [0, 0, 0, 0, 0, 0, 0, 0, 0],
    mouseDownCount = 0;
document.body.onmousedown = function(evt) { 
  ++mouseDown[evt.button];
  ++mouseDownCount;
}
document.body.onmouseup = function(evt) {
  --mouseDown[evt.button];
  --mouseDownCount;
}

Ora puoi controllare quali pulsanti sono stati premuti esattamente:

if(mouseDownCount){
  // alright, let's lift the little bugger up!
  for(var i = 0; i < mouseDown.length; ++i){
    if(mouseDown[i]){
      // we found it right there!
    }
  }
}

Ora tieni presente che il codice sopra funzionerebbe solo per i browser conformi allo standard che ti passano un numero di pulsante a partire da 0 in su. IE utilizza una maschera di bit dei pulsanti attualmente premuti:

  • 0 per "non viene premuto nulla"
  • 1 a sinistra
  • 2 a destra
  • 4 per metà
  • e qualsiasi combinazione di cui sopra, ad es. 5 per left + middle

Quindi regola il tuo codice di conseguenza! Lo lascio come un esercizio.

E ricorda: IE utilizza un oggetto evento globale chiamato ... "evento".

Per inciso IE ha una funzione utile nel tuo caso: quando altri browser inviano "button" solo per eventi di pulsanti del mouse (onclick, onmousedown e onmouseup), IE lo invia anche con onmousemove. Quindi puoi iniziare ad ascoltare onmousemove quando devi conoscere lo stato del pulsante e controllare il pulsante evt. non appena l'hai ricevuto - ora sai quali pulsanti del mouse sono stati premuti:

// for IE only!
document.body.onmousemove = function(){
  if(event.button){
    // aha! we caught a feisty little sheila!
  }
};

Ovviamente non otterrai nulla se lei gioca morta e non si muove.

Link rilevanti:

Aggiornamento n. 1 : non so perché ho riportato il documento in stile document.body. Sarà meglio collegare i gestori di eventi direttamente al documento.


1
Dopo il test, sembra che evt.button in realtà non esista onmousemove con IE7 ...
TM.

5
Penso che questo non funzionerà in Chrome, perché Chrome non genera eventi di mouseup se il mouse originale è avvenuto su una barra di scorrimento. Un esempio , da questo problema di Chrome / Chromium . Quindi il pulsante sinistro del mouse rimarrà per sempre, se c'è una barra di scorrimento che qualcuno usa! (In Chrome)
KajMagnus,

1
Adoro la tua soluzione, ma cosa succede se il mouse proviene da un'altra applicazione dire ms word e trascinare del testo. Come rileverai che il mouse è abbassato?
Shadrack B. Orina,

6
Non capisco perché stai aumentando gli array di mousedown nel secondo esempio. Perché un contatore per ciascun pulsante anziché un valore booleano per ciascun pulsante?
amwinter

2
Questa è una domanda (e una risposta) molto popolare. Sono sorpreso che questo non sia ancora emerso, ma non è necessario archiviare i dati del mouse. Puoi semplicemente collegarti event.buttonsa qualsiasi trigger di evento che stai utilizzando, senza variabili salvate esterne. Ho fatto una domanda nuova di zecca (perché il mio evento con il mouse non si attiva sempre, quindi questa soluzione non funziona per me) e ho ottenuto la risposta in 5 minuti.
RoboticRenaissance

32

Questa è una vecchia domanda, e le risposte qui sembrano sostenere principalmente l'utilizzo mousedowne mouseuptenere traccia del fatto che un pulsante sia premuto. Ma come altri hanno sottolineato,mouseup attiverà solo se eseguito all'interno del browser, il che può portare a perdere traccia dello stato del pulsante.

Tuttavia, MouseEvent (ora) indica quali pulsanti sono attualmente premuti:

  • Per tutti i browser moderni (tranne Safari) utilizzare MouseEvent.buttons
  • Per Safari, utilizzare MouseEvent.which( buttonsnon sarà definito per Safari) Nota: whichutilizza numeri diversi da quelli buttonsper i clic destro e centrale.

Quando registrato il document,mousemove attiverà immediatamente non appena il cursore rientrerà nel browser, quindi se l'utente rilascia all'esterno, lo stato verrà aggiornato non appena il mouse tornerà all'interno.

Una semplice implementazione potrebbe apparire come:

var leftMouseButtonOnlyDown = false;

function setLeftButtonState(e) {
  leftMouseButtonOnlyDown = e.buttons === undefined 
    ? e.which === 1 
    : e.buttons === 1;
}

document.body.onmousedown = setLeftButtonState;
document.body.onmousemove = setLeftButtonState;
document.body.onmouseup = setLeftButtonState;

Se sono necessari scenari più complicati (pulsanti diversi / pulsanti multipli / tasti di controllo), consulta i documenti MouseEvent. Quando / se Safari alza il suo gioco, questo dovrebbe essere più facile.


6
Questo codice controlla se viene premuto SOLO il pulsante principale e richiede che tutti gli altri pulsanti non siano premuti. (es. se vengono premuti sia primario che secondario, e.buttonssarà 1+2=3, quindi e.buttons === 1sarà falso). Se vuoi verificare se il pulsante principale è inattivo, ma non preoccuparti di altri stati del pulsante, procedi come segue:(e.buttons & 1) === 1
AJ Richardson

Ho una situazione in cui mi aspetto che durante un mousemove dovrei ottenere il codice pulsanti '1' ma produce '7', - tutto il lavoro è su Chrome. Qualcuno ha qualche idea?
Vasily Hall,

@VasilyHall Guardando i documenti MDN per MouseEvent.buttons, sembrerebbe che ciò 7significhi che i pulsanti Primario, Secondario e Ausiliario vengono premuti tutti insieme. Non sono sicuro del perché questo sarebbe il caso - stai usando un mouse avanzato? Se è così, forse vale la pena provare con uno di base. Se hai solo bisogno di farlo funzionare, potresti usare un controllo bit a bit per assicurarti che il pulsante sinistro sia premuto e ignorare tutti gli altri. per esempio. MouseEvent.buttons & 1 === 1.
Jono Job

Grazie, stavo usando il mio JavaScript all'interno di un browser speciale: il Chrome incorporato (ium?) All'interno dell'applicazione Adobe Illustrator- Scommetto che la combinazione di tutte le varie cose porta in qualche modo a un 7, anche se viene premuto solo un pulsante . Visto che ciò è coerente con la mia applicazione, sto semplicemente facendo un controllo per 1 o 7 per facilitare la mia interattività. Aggiungerò, anche se utilizzo il mouse trackball Logitech M570 (o qualsiasi altra cosa), registra correttamente 1 nel browser normale ma 7 all'interno di Illustrator.
Vasily Hall,

16

Penso che l'approccio migliore a questo sia quello di mantenere la propria registrazione dello stato del pulsante del mouse, come segue:

var mouseDown = 0;
document.body.onmousedown = function() { 
    mouseDown = 1;
}
document.body.onmouseup = function() {
    mouseDown = 0;
}

e poi, più avanti nel tuo codice:

if (mouseDown == 1) {
    // the mouse is down, do what you have to do.
}

+1 e grazie. Ho pensato che avrei dovuto ricorrere a questo, ma speravo ci fosse qualche caratteristica che ti permettesse semplicemente di controllare direttamente lo stato.
TM.

12
C'è un motivo per non usare un booleano?
Moala,

1
@moala Penso che Int sembra essere meno dattiloscritto e, in definitiva, prestazioni leggermente migliori: jsperf.com/bool-vs-int
Johnathan Elmore

12

la soluzione non è buona. si potrebbe "mousedown" sul documento, quindi "mouseup" al di fuori del browser, e in questo caso il browser continuerebbe a pensare che il mouse non sia attivo.

l'unica buona soluzione sta usando l'oggetto IE.event.


11
Vedo da dove vieni, ma avere una soluzione che funziona solo per IE non è una buona soluzione.
TM.

@alfred In alcuni casi potrebbe essere utile sapere se mousemove è fuori dalla finestra. Se (event.target.nodeName.toLowerCase === 'html') verso il basso = 0;
BF

6

So che questo è un vecchio post, ma ho pensato che il tracciamento del pulsante del mouse usando il mouse su / giù fosse un po 'goffo, quindi ho trovato un'alternativa che potrebbe piacere ad alcuni.

<style>
    div.myDiv:active {
        cursor: default;
    }
</style>

<script>
    function handleMove( div ) {
        var style = getComputedStyle( div );
        if (style.getPropertyValue('cursor') == 'default')
        {
            // You're down and moving here!
        }
    }
</script>

<div class='myDiv' onmousemove='handleMove(this);'>Click and drag me!</div>

Il selettore: active gestisce il clic del mouse molto meglio del mouse su / giù, hai solo bisogno di un modo per leggere quello stato nell'evento onmousemove. Per questo avevo bisogno di imbrogliare e basarmi sul fatto che il cursore predefinito è "auto" e lo cambio semplicemente in "default", che è ciò che auto seleziona automaticamente.

Puoi usare qualsiasi cosa nell'oggetto che viene restituito da getComputedStyle che puoi usare come flag senza stravolgere l'aspetto della tua pagina, ad es. Bordo-colore.

Mi sarebbe piaciuto impostare il mio stile definito dall'utente nella sezione: active, ma non riuscivo a farlo funzionare. Sarebbe meglio se fosse possibile.


Grazie per averlo condiviso. Stavo usando questa idea per una logica di stile drag-and-drop, ma ho affrontato un problema su IE e
ho

4

Il frammento seguente tenterà di eseguire la funzione "doStuff" 2 secondi dopo che si verifica l'evento mouseDown in document.body. Se l'utente solleva il pulsante, si verificherà l'evento mouseUp e annullerà l'esecuzione ritardata.

Consiglio di utilizzare un metodo per l'allegato di eventi cross-browser: l'impostazione delle proprietà mousedown e mouseup è stata esplicitamente eseguita per semplificare l'esempio.

function doStuff() {
  // does something when mouse is down in body for longer than 2 seconds
}

var mousedownTimeout;

document.body.onmousedown = function() { 
  mousedownTimeout = window.setTimeout(doStuff, 2000);
}

document.body.onmouseup = function() {
  window.clearTimeout(mousedownTimeout);
}

Grazie, ma questo non è proprio il comportamento che stavo cercando (anche se posso vedere come la mia domanda indica che questo è quello che sto cercando di fare).
TM.

3

Breve e dolce

Non sono sicuro del motivo per cui nessuna delle risposte precedenti ha funzionato per me, ma ho trovato questa soluzione durante un momento di eureka. Non solo funziona, ma è anche molto elegante:

Aggiungi al tag body:

onmouseup="down=0;" onmousedown="down=1;"

Quindi prova ed esegui myfunction()se è downuguale a 1:

onmousemove="if (down==1) myfunction();"

4
sei nuovo, quindi ti aiuterò un po ', qui. Prima di tutto, tieni a mente la tua grammatica nei tuoi post - probabilmente ho trascorso più tempo a correggerlo di quello che hai inserito. In secondo luogo, la tua soluzione è solo un'altra versione delle altre sopra elencate: non è una novità. In terzo luogo, la tua soluzione utilizza una tecnica denominata "utilizzo di flag", suggerita da Thomas Hansen, sopra. Assicurati di controllare la grammatica e di non ripetere le soluzioni quando pubblichi post precedenti senza fornire alcune spiegazioni sul perché le altre soluzioni non abbiano funzionato per te.
Zachary Kniebel,

5
Ho votato, tuttavia, la tua soluzione, poiché è valida e sei nuovo di SO
Zachary Kniebel,

2

Puoi combinare @Pax e le mie risposte per ottenere anche la durata in cui il mouse è rimasto inattivo per:

var mousedownTimeout,
    mousedown = 0;

document.body.onmousedown = function() {
  mousedown = 0; 
  window.clearInterval(mousedownTimeout);
  mousedownTimeout = window.setInterval(function() { mousedown += 200 }, 200);
}

document.body.onmouseup = function() {
  mousedown = 0;
  window.clearInterval(mousedownTimeout);
}

Poi più tardi:

if (mousedown >= 2000) {
  // do something if the mousebutton has been down for at least 2 seconds
}

Non è una cattiva idea, Jake. Devi cancellareInterval () in onmouseup () prima di impostare mousedown su 0? Diffido della funzione timer che si attiva tra l'impostazione su 0 e l'arresto del timer, lasciando il timeout a 200? Allo stesso modo in onmousedown.
paxdiablo,

L'ordine di clearIntervals non farà alcuna differenza poiché l'attuale thread di esecuzione terminerà prima che vengano attivati ​​tutti gli eventi (inclusi i timer).
Nathaniel Reinhart,

2

È necessario gestire MouseDown e MouseUp e impostare un flag o qualcosa per rintracciarlo "più avanti lungo la strada" ... :(


2

Se lavori all'interno di una pagina complessa con gestori di eventi del mouse esistenti, ti consiglio di gestire l'evento al momento dell'acquisizione (anziché del fumetto). Per fare ciò, basta impostare il 3 ° parametro di addEventListenera true.

Inoltre, potresti voler controllare per event.whichassicurarti di gestire l'interazione dell'utente reale e non gli eventi del mouse, ad es elem.dispatchEvent(new Event('mousedown')).

var isMouseDown = false;

document.addEventListener('mousedown', function(event) { 
    if ( event.which ) isMouseDown = true;
}, true);

document.addEventListener('mouseup', function(event) { 
    if ( event.which ) isMouseDown = false;
}, true);

Aggiungi il gestore al documento (o alla finestra) invece di document.body è importante in b / c, assicura che gli eventi del mouse al di fuori della finestra siano ancora registrati.


1

Utilizzando l' API MouseEvent , per verificare l'eventuale pulsante premuto:

document.addEventListener('mousedown', (e) => console.log(e.buttons))

Ritorno :

Un numero che rappresenta uno o più pulsanti. Per più di un pulsante premuto contemporaneamente, i valori vengono combinati (ad es. 3 è primario + secondario).

0 : No button or un-initialized
1 : Primary button (usually the left button)
2 : Secondary button (usually the right button)
4 : Auxilary button (usually the mouse wheel button or middle button)
8 : 4th button (typically the "Browser Back" button)
16 : 5th button (typically the "Browser Forward" button)

0

Usando jQuery, la seguente soluzione gestisce anche il "trascinamento dalla pagina e quindi rilascio".

$(document).mousedown(function(e) {
    mouseDown = true;
}).mouseup(function(e) {
    mouseDown = false;
}).mouseleave(function(e) {
    mouseDown = false;
});

Non so come gestisce più pulsanti del mouse. Se ci fosse un modo per avviare il clic fuori dalla finestra, quindi portare il mouse nella finestra, probabilmente anche questo non funzionerebbe correttamente lì.


0

Sotto l'esempio di jQuery, quando il mouse è sopra $ ('.elemento'), il colore cambia a seconda del pulsante del mouse premuto.

var clicableArea = {
    init: function () {
        var self = this;
        ('.element').mouseover(function (e) {
            self.handlemouseClick(e, $(this));
        }).mousedown(function (e) {
            self.handlemouseClick(e, $(this));
        });
    },
    handlemouseClick: function (e, element) {
        if (e.buttons === 1) {//left button
            element.css('background', '#f00');
        }
        if (e.buttons === 2) { //right buttom
            element.css('background', 'none');
        }
    }
};
$(document).ready(function () {
    clicableArea.init();
});

0

Come detto @Jack, quando mouseupaccade al di fuori della finestra del browser, non ne siamo consapevoli ...

Questo codice (quasi) ha funzionato per me:

window.addEventListener('mouseup', mouseUpHandler, false);
window.addEventListener('mousedown', mouseDownHandler, false);

Sfortunatamente, non riceverò l' mouseupevento in uno di questi casi:

  • l'utente preme contemporaneamente un tasto della tastiera e un pulsante del mouse, rilascia il pulsante del mouse all'esterno della finestra del browser, quindi rilascia il tasto.
  • l'utente preme due pulsanti del mouse contemporaneamente, rilascia un pulsante del mouse e l'altro, entrambi al di fuori della finestra del browser.

-1

Bene, non puoi controllare se è inattivo dopo l'evento, ma puoi verificare se è attivo ... Se è attivo .. significa che non è più inattivo: P lol

Quindi l'utente preme il pulsante in basso (evento onMouseDown) ... e successivamente si verifica se è attivo (onMouseUp). Anche se non funziona, puoi fare quello che ti serve.


2
Anche onMouseUp non è un evento? Come controllerai la "proprietà" suMouseup? O di chi di proprietà, piuttosto?
Rohit,

@Rohit: non controlli la proprietà, gestisci un flag che indica che l'evento si è verificato ... Il pulsante del mouse è su o giù.
PhiLho,

-1
        var mousedown = 0;
        $(function(){
            document.onmousedown = function(e){
                mousedown = mousedown | getWindowStyleButton(e);
                e = e || window.event;
                console.log("Button: " + e.button + " Which: " + e.which + " MouseDown: " + mousedown);
            }

            document.onmouseup = function(e){
                mousedown = mousedown ^ getWindowStyleButton(e);
                e = e || window.event;
                console.log("Button: " + e.button + " Which: " + e.which + " MouseDown: " + mousedown);
            }

            document.oncontextmenu = function(e){
                // to suppress oncontextmenu because it blocks
                // a mouseup when two buttons are pressed and 
                // the right-mouse button is released before
                // the other button.
                return false;
            }
        });

        function getWindowStyleButton(e){
            var button = 0;
                if (e) {
                    if (e.button === 0) button = 1;
                    else if (e.button === 1) button = 4;
                    else if (e.button === 2) button = 2;  
                }else if (window.event){
                    button = window.event.button;
                }
            return button;
        }

questa versione cross-browser funziona bene per me.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.