175 votes

JavaScript : Vérifier si le bouton de la souris est enfoncé ?

Existe-t-il un moyen de détecter si un bouton de la souris est actuellement enfoncé en JavaScript ?

Je connais l'événement "mousedown", mais ce n'est pas ce dont j'ai besoin. Quelque temps après que le bouton de la souris ait été enfoncé, je veux pouvoir détecter s'il l'est toujours.

Est-ce possible ?

28 votes

Pourquoi vous acceptez une réponse qui ne répond pas à votre question. Enregistrer mousedown et mouseup est une erreur (car vous pouvez mouseup en dehors du navigateur et lui faire croire que vous êtes toujours en train de glisser). Venir après votre problème et atteindre cette page est complètement inutile.

3 votes

Jack, cela répond à ma question. Veuillez lire ma question et ensuite la réponse. Apparemment, plus de 100 autres personnes sont d'accord pour dire que c'était une bonne réponse.

6 votes

Oui mais moi, alfred, et d'autres 8 vous disent que le suivi de mouseup et mousedown n'est pas la bonne façon. La bonne réponse devrait impliquer l'analyse de l'objet événement dans le gestionnaire de votre choix, ou l'analyse de tous les événements liés à la souris (comme entrée/sortie) si vous avez besoin d'une vérification dans le temps au lieu d'une vérification par événement.

165voto

Eugene Lazutkin Points 22414

En ce qui concerne la solution de Pax : elle ne fonctionne pas si l'utilisateur clique sur plus d'un bouton, intentionnellement ou accidentellement. Ne me demandez pas comment je le sais :-(.

Le code correct devrait être comme ça :

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

Avec le test comme ça :

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

Si vous voulez savoir quel bouton est pressé, soyez prêt à faire de mouseDown un tableau de compteurs et à les compter séparément pour les différents boutons :

// 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;
}

Vous pouvez maintenant vérifier quels boutons ont été pressés exactement :

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!
    }
  }
}

Sachez que le code ci-dessus ne fonctionne que pour les navigateurs conformes aux normes qui vous transmettent un numéro de bouton à partir de 0. IE utilise un masque binaire des boutons actuellement pressés :

  • 0 pour " rien n'est appuyé "
  • 1 pour la gauche
  • 2 pour la droite
  • 4 pour le milieu
  • et toute combinaison des éléments ci-dessus, par exemple 5 pour gauche + milieu

Ajustez donc votre code en conséquence ! Je le laisse comme un exercice.

Et rappelez-vous : IE utilise un objet événement global appelé "événement".

Par ailleurs, IE possède une fonctionnalité utile dans votre cas : alors que les autres navigateurs envoient "button" uniquement pour les événements liés aux boutons de la souris (onclick, onmousedown et onmouseup), IE l'envoie également avec onmousemove. Vous pouvez donc commencer à écouter onmousemove lorsque vous avez besoin de connaître l'état du bouton, et vérifier evt.button dès que vous l'avez obtenu - vous savez maintenant quels boutons de la souris ont été pressés :

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

Bien sûr, vous n'obtenez rien si elle fait le mort et ne bouge pas.

Liens pertinents :

Mise à jour n° 1 : Je ne sais pas pourquoi j'ai reporté le code document.body-style. Il serait préférable d'attacher les gestionnaires d'événements directement au document.

0 votes

Superbe article, merci ! La dernière partie concernant la capture du bouton onmousemove est parfaite, car je n'ai besoin de cette information que pour résoudre un problème qui ne se produit que dans IE (certains rappels scriptaculous se déclenchent pendant le déplacement, alors qu'ils ne devraient se déclencher que lorsque le déplacement s'arrête, et j'avais besoin d'un moyen de les arrêter).

1 votes

Après test, il apparaît que evt.button n'existe en fait pas onmousemove avec IE7...

0 votes

Il est toujours utile de qualifier sa question aussi précisément que possible. J'ai juste ajouté la dernière partie comme un fait amusant. Maintenant, je suis content de l'avoir fait parce que cela s'est avéré utile pour vous.

72voto

Jono Job Points 804

C'est une vieille question, et les réponses semblent surtout préconiser l'utilisation de mousedown et mouseup pour savoir si un bouton est enfoncé. Mais comme d'autres l'ont souligné, mouseup ne se déclenchera que lorsqu'elle sera exécutée dans le navigateur, ce qui peut entraîner une perte de l'état du bouton.

Cependant, MouseEvent (maintenant) indique les boutons qui sont actuellement enfoncés :

  • Pour tous les navigateurs modernes (sauf Safari), utilisez MouseEvent.buttons
  • Pour Safari, utilisez MouseEvent.which ( buttons sera indéfini pour Safari) Note : which utilise des numéros différents de buttons pour les clics droit et moyen.

Lorsqu'il est enregistré sur document , mousemove se déclenchera immédiatement dès que le curseur reviendra dans le navigateur. Ainsi, si l'utilisateur relâche la souris à l'extérieur, l'état sera mis à jour dès qu'il reviendra dans le navigateur.

Une mise en œuvre simple pourrait ressembler à ceci :

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;

Si des scénarios plus complexes sont nécessaires (différents boutons/multiples boutons/clés de commande), consultez la documentation MouseEvent. Si Safari améliore son jeu, cela devrait devenir plus facile.

13 votes

Ce code vérifie si SEUL le bouton principal est enfoncé et exige que tous les autres boutons soient relâchés. (par exemple, si les boutons primaire et secondaire sont tous deux enfoncés, e.buttons sera 1+2=3 donc e.buttons === 1 sera fausse). Si vous voulez vérifier si le bouton principal est abaissé, mais que vous ne vous souciez pas de l'état des autres boutons, faites ceci : (e.buttons & 1) === 1

0 votes

J'ai une situation où je m'attends à ce que le code des boutons soit '1' lors d'un déplacement de la souris, mais il produit '7', - tout le travail se fait sur Chrome. Quelqu'un a-t-il une idée ?

0 votes

@VasilyHall En regardant les documents MDN pour MouseEvent.buttons il semblerait que 7 signifie qu'il pense que les boutons primaire, secondaire et auxiliaire sont tous pressés ensemble. Je ne sais pas pourquoi ce serait le cas - utilisez-vous une souris avancée ? Si oui, cela vaut peut-être la peine d'essayer avec une souris de base. Si vous avez juste besoin de la faire fonctionner, vous pouvez utiliser une souris de type vérification par bit pour s'assurer que le bouton gauche est enfoncé et ignorer tous les autres. ex. MouseEvent.buttons & 1 === 1 .

21voto

paxdiablo Points 341644

Je pense que la meilleure approche consiste à conserver votre propre enregistrement de l'état du bouton de la souris, comme suit :

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

et ensuite, plus tard dans votre code :

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

0 votes

+1, et merci. J'ai pensé que je devrais avoir recours à cela, mais j'espérais qu'il y avait une fonction qui vous permettait simplement de vérifier l'état directement.

22 votes

Y a-t-il une raison pour ne pas utiliser un booléen ?

2 votes

@moala Je pense que Int semble être moins de frappe, et finalement une performance légèrement meilleure : jsperf.com/bool-vs-int

13voto

alfred Points 459

La solution n'est pas bonne. On pourrait faire un "mousedown" sur le document, puis un "mouseup" en dehors du navigateur, et dans ce cas le navigateur penserait toujours que la souris est en bas.

la seule bonne solution est d'utiliser l'objet IE.event.

18 votes

Je vois où vous voulez en venir, mais avoir une solution qui ne fonctionne que pour IE n'est pas non plus une bonne solution.

0 votes

@alfred Dans certains cas, il pourrait être utile de savoir si le déplacement de la souris est hors de la fenêtre. Si(event.target.nodeName.toLowerCase==='html')down=0 ;

7voto

Martin Points 51

Je sais que c'est un vieux post, mais je trouvais que le suivi du bouton de la souris en utilisant le haut/bas de la souris était un peu maladroit, alors j'ai trouvé une alternative qui pourrait plaire à certains.

<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>

Le sélecteur :active gère le clic de la souris bien mieux que les mouvements de souris vers le haut ou vers le bas, il faut simplement trouver un moyen de lire cet état dans l'événement onmousemove. Pour cela, j'ai dû tricher et m'appuyer sur le fait que le curseur par défaut est "auto" et que je le change simplement en "default", ce qui est ce que l'auto sélectionne par défaut.

Vous pouvez utiliser n'importe quel élément de l'objet renvoyé par getComputedStyle que vous pouvez utiliser comme indicateur sans bouleverser l'aspect de votre page, par exemple border-color.

J'aurais aimé définir mon propre style défini par l'utilisateur dans la section :active, mais je n'ai pas réussi à le faire fonctionner. Ce serait mieux si c'était possible.

0 votes

Merci de partager cela. J'ai utilisé cette idée pour une logique de style par glisser-déposer, mais j'ai rencontré un problème avec IE et j'ai dû faire appel à un autre logiciel. inclure une logique supplémentaire

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X