oujood.com

Les événements de la souris en JavaScript

Dans cet article, nous allons étudier plus en détail les événements de la souris et leurs propriétés.
Veuillez noter que ces événements peuvent provenir non seulement des "périphériques souris", mais aussi d'autres périphériques, comme les téléphones et les tablettes, où ils sont émulés pour des raisons de compatibilité.

chercher |

Types d'événements liés à la souris

Nous avons déjà vu certains de ces événements :
mousedown/mouseup
Le bouton de la souris est cliqué/relâché sur un élément.
mouseover/mouseout
Le pointeur de la souris passe au-dessus ou en dehors d'un élément.
mousemove
Chaque déplacement de la souris sur un élément déclenche cet événement.
clic
Déclenche l'événement après le déplacement de la souris sur le même élément, si le bouton gauche de la souris a été utilisé.
dblclick
Se déclenche après deux clics sur le même élément dans un court laps de temps. Rarement utilisé de nos jours.
contextmenu
Se déclenche lorsque le bouton droit de la souris est enfoncé. Il y a d'autres façons d'ouvrir un menu contextuel, par exemple en utilisant une touche spéciale du clavier, il se déclenche dans ce cas également, ce n'est donc pas réellement l'événement souris.

...Il existe également plusieurs autres événements, que nous aborderons plus tard.

Bouton de la souris

Les événements liés au clic ont toujours la propriété button, qui permet d'obtenir le bouton exact de la souris.
En général, nous ne l'utilisons pas pour les événements liés au clic et au menu contextuel, car le premier ne se produit que lors d'un clic gauche, et le second - uniquement lors d'un clic droit.
Mais, les gestionnaires de mousedown et de mouseup peuvent avoir besoin de event.button, car ces événements se déclenchent sur n'importe quel bouton, et le bouton permet de distinguer le "mousedown droit" du "mousedown gauche".
Les valeurs possibles de event.button sont :

État du bouton event.button
Bouton de gauche (principal) 0
Bouton du milieu (auxiliaire) 1
Bouton droit (secondaire) 2

La plupart des souris ne possèdent que les boutons gauche et droit, les valeurs possibles sont donc 0 ou 2. Les périphériques tactiles génèrent également des événements similaires lorsque l'on tape dessus.

L'ordre des événements

Comme vous pouvez le constater dans la liste ci-dessus, une action utilisateur peut déclencher plusieurs événements.
Par exemple, un clic sur le bouton gauche déclenche d'abord le mousedown, lorsque le bouton est enfoncé, puis le mouseup et le click lorsqu'il est relâché.
Dans le cas où une action unique déclenche plusieurs événements, leur ordre est fixe. C'est-à-dire que les gestionnaires sont toujours appelés dans l'ordre mousedown → mouseup → click.
Voici un exemple qui va vous montrer tout ce qu’on vient de dire

Code

  Copier le code

<!DOCTYPE html>
<html lang="fr"><head>
<meta charset="utf-8">
<title>Exemple  événements de la souris en JavaScript</title>
<script>
{  var timer = 0;
  function voirMessage(txt, form) {
     if (timer == 0) {
       timer = new Date();
     }
     let tm = new Date();
     if (tm - timer > 300) {
       txt = '------------------------------\n' + txt;
     }
     let str = document.forms[form + 'form'].getElementsByTagName('textarea')[0];
     str.value += txt + '\n';
     str.scrollTop = str.scrollHeight;
     timer = tm;}
  function evsouris(e) {
     let evt = e.type;
     while (evt.length < 11){ evt += ' ';
     voirMessage(evt + " button=" + e.button, 'test')}
     return false;
  }
  function logClear(form) {
  	timer = 0;
  	document.forms[form+'form'].getElementsByTagName('textarea')[0].value ='';
  	lines = 0;
  }
}
</script>
</head>
<body>
<div>
<form id="testform" name="testform">
<p><input onmousedown="return evsouris(event)" onmouseup="return evsouris(event)" onclick="return evsouris(event)" oncontextmenu="return evsouris(event)" ondblclick="return evsouris(event)" value="Cliquer ici  droit | gauche de la souris" type="button"> 
</p>  
< textarea style="font-size:12px;height:250px;width:200px;"></textarea>
<p><input onclick="logClear('test')" value=" Effacer " type="button"></p>
</form>
</div>
</body>
</html>

Exécuter ce code dans votre navigateur.
Cliquez sur le bouton et maintenez le bouton enfoncé pour un court instant puis relâchez, vous verrez les événements qui se sont créés et leur ordre. Essayez aussi le double-clique. Faites aussi un clique droit ou un clique avec le bouton central de la souri.
Sur le banc d'essai dans le code ci dessus, tous les événements de souris sont enregistrés, et s'il y a plus d'une seconde de délai entre eux, ils sont séparés par une ligne horizontale.
On peut également voir la propriété button qui nous permet de détecter le bouton de la souris.

Modificateurs : shift, alt, ctrl et meta

Tous les événements de souris incluent les informations sur les touches de modification pressées.
Propriétés de l'événement :
shiftKey : Shift
altKey : Alt (ou Opt pour Mac)
ctrlKey : Ctrl
metaKey : Cmd pour Mac
Ils sont vrais si la touche correspondante a été pressée pendant l'événement.
Par exemple, le bouton ci-dessous ne fonctionne que si vous appuyez sur Alt+Shift+clic :

Code

  Copier le code

<button id="button">Alt+Shift+Click!</button>
<script>
  button.onclick = function(event) {
    if (event.altKey && event.shiftKey) {
      alert('Hooray!');
    }
  };
</script>

Attention : sur Mac, c'est généralement Cmd au lieu de Ctrl.

Même si nous voulons forcer les utilisateurs de Mac à utiliser Ctrl+clic, c'est assez difficile.
Le problème est le suivant : un clic gauche avec Ctrl est interprété comme un clic droit sur MacOS, et cela génère l'événement contextuel, et non un clic comme sur Windows/Linux.
Donc, si nous voulons que les utilisateurs de tous les systèmes d'exploitation se sentent à l'aise, nous devrions vérifier metaKey en même temps que ctrlKey.
Pour le code JS, cela signifie que nous devrions vérifier si (event.ctrlKey || event.metaKey).
Il existe aussi des appareils mobiles
Les combinaisons de claviers sont un bon complément au flux de travail. Ainsi, si le visiteur utilise un clavier, elles fonctionnent.
Mais si leur appareil n'en est pas équipé, il doit y avoir un moyen pour fonctionner sans les touches de modification.

Empêcher la sélection lors du mousedown

Le double-clic de la souris a un effet secondaire qui peut être gênant dans certaines interfaces : il sélectionne le texte.
Par exemple, un double-clic sur le texte ci-dessous le sélectionne en plus de notre gestionnaire :
<span ondblclick="alert(' Le dblclick provoque une sélection ')">Double-click ici</span> Si l'on appuie sur le bouton gauche de la souris et que, sans le relâcher, on déplace la souris, cela fait également une sélection, souvent non désirée.

Il existe plusieurs façons d'empêcher la sélection.
Dans notre cas, le moyen le plus raisonnable est d'empêcher l'action du navigateur lors du déplacement de la souris. Cela empêche ces deux sélections :
<span ondblclick="alert(' Le dblClick! ne provoque plus la sélection ')" onmousedown="return false"> Double-click ici </span>
Désormais, le texte n'est pas sélectionné en cas de double-clic, et le fait d'appuyer sur le bouton gauche ne permet pas de lancer la sélection.

Remarque : le texte qu'il contient peut toujours être sélectionné. Cependant, la sélection ne doit pas commencer sur le texte lui-même, mais avant ou après. En général, cela convient aux utilisateurs.

Evénement généré par le déplacement de la souris : mouseover/ mouseout, mouseenter/mouseleave

Entrons dans le détail des événements qui se produisent lorsque la souris se déplace entre les éléments.

Événements mouseover/mouseout

L'événement mouseover se produit lorsque le pointeur de la souris arrive sur un élément, et mouseout - lorsqu'il le quitte.

Ces événements sont spéciaux, car ils ont la propriété relatedTarget. Cette propriété complète la cible. Lorsque la souris quitte un élément pour un autre, l'un d'eux devient target, et l'autre - relatedTarget.
Pour le mouseover :
event.target - est l'élément sur lequel la souris est passée.
event.relatedTarget - est l'élément d'où la souris est venue (relatedTarget → target).
Pour le mouseout, c'est l'inverse :
event.target - est l'élément que la souris a quitté.
event.target - est l'élément que la souris a quitté.
event.relatedTarget - est le nouvel élément sous le pointeur, pour lequel la souris est partie (target → relatedTarget).
Chaque évènement possède les informations concernant à la fois target et relatedTarget .
Voici un exemple qui mis en évidence touts les événements relatives au mouvement de la sourie :

Code

  Copier le code

<!DOCTYPE html>
<html lang="fr"><head>
<meta charset="utf-8">
<title>Evénement généré par le déplacement de la souris </title>
<link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="conteneur" id="container">
    <div class="Le-Vert">
      <div class="œil-gauche"></div>
      <div class="œil-droit"></div>
      <div class="smile"></div>
    </div>
    <div class="Le-Jaune">
      <div class="œil-gauche"></div>
      <div class="œil-droit"></div>
      <div class="smile"></div>
    </div>
    <div class="Le-Rouge">
      <div class="œil-gauche"></div>
      <div class="œil-droit"></div>
      <div class="smile"></div>
    </div>
  </div>
<form id="testform" name="testform">
  <textarea name="textarea" id="log">Les événements vont apparaître ici !</textarea>
<p><input onclick="document.forms['testform'].getElementsByTagName('textarea')[0].value ='Les événements vont apparaître ici !';" value=" Effacer " type="button"></p>
</form>
  <script>
  container.onmouseover = container.onmouseout = handler;
function handler(event) {
  function str(el) {
    if (!el) return "null"
    return el.className || el.tagName;
  }
  log.value += event.type + ':  ' +
    'target=' + str(event.target) +
    ',  relatedTarget=' + str(event.relatedTarget) + "\n";
  log.scrollTop = log.scrollHeight;
}
  </script>
</body>
</html>

Et voici le code fichier style.css qui va avec :

Code

  Copier le code

body,
html {
  margin: 10px;
  padding: 0;
}
#container {
  border: 1px solid brown;
  padding: 10px;
  width: 330px;
  margin-bottom: 5px;
  box-sizing: border-box;
}
#log {
  height: 300px;
  width: 500px;
  display: block;
  box-sizing: border-box;
}
[class^="smiley-"] {
  display: inline-block;
  width: 70px;
  height: 70px;
  border-radius: 50%;
  margin-right: 20px;
}
.smiley-green {
  background: #a9db7a;
  border: 5px solid #92c563;
  position: relative;
}
.smiley-green .left-eye {
  width: 18%;
  height: 18%;
  background: #84b458;
  position: relative;
  top: 29%;
  left: 22%;
  border-radius: 50%;
  float: left;
}
.smiley-green .right-eye {
  width: 18%;
  height: 18%;
  border-radius: 50%;
  position: relative;
  background: #84b458;
  top: 29%;
  right: 22%;
  float: right;
}
.smiley-green .smile {
  position: absolute;
  top: 67%;
  left: 16.5%;
  width: 70%;
  height: 20%;
  overflow: hidden;
}
.smiley-green .smile:after,
.smiley-green .smile:before {
  content: "";
  position: absolute;
  top: -50%;
  left: 0%;
  border-radius: 50%;
  background: #84b458;
  height: 100%;
  width: 97%;
}
.smiley-green .smile:after {
  background: #84b458;
  height: 80%;
  top: -40%;
  left: 0%;
}
.smiley-yellow {
  background: #eed16a;
  border: 5px solid #dbae51;
  position: relative;
}
.smiley-yellow .left-eye {
  width: 18%;
  height: 18%;
  background: #dba652;
  position: relative;
  top: 29%;
  left: 22%;
  border-radius: 50%;
  float: left;
}
.smiley-yellow .right-eye {
  width: 18%;
  height: 18%;
  border-radius: 50%;
  position: relative;
  background: #dba652;
  top: 29%;
  right: 22%;
  float: right;
}
.smiley-yellow .smile {
  position: absolute;
  top: 67%;
  left: 19%;
  width: 65%;
  height: 14%;
  background: #dba652;
  overflow: hidden;
  border-radius: 8px;
}
.smiley-red {
  background: #ee9295;
  border: 5px solid #e27378;
  position: relative;
}
.smiley-red .left-eye {
  width: 18%;
  height: 18%;
  background: #d96065;
  position: relative;
  top: 29%;
  left: 22%;
  border-radius: 50%;
  float: left;
}
.smiley-red .right-eye {
  width: 18%;
  height: 18%;
  border-radius: 50%;
  position: relative;
  background: #d96065;
  top: 29%;
  right: 22%;
  float: right;
}
.smiley-red .smile {
  position: absolute;
  top: 57%;
  left: 16.5%;
  width: 70%;
  height: 20%;
  overflow: hidden;
}
.smiley-red .smile:after,
.smiley-red .smile:before {
  content: "";
  position: absolute;
  top: 50%;
  left: 0%;
  border-radius: 50%;
  background: #d96065;
  height: 100%;
  width: 97%;
}
.smiley-red .smile:after {
  background: #d96065;
  height: 80%;
  top: 60%;
  left: 0%;
} 

Saut d'éléments

L'événement mousemove se déclenche lorsque la souris se déplace. Mais cela ne signifie pas que chaque pixel mène à un événement.
Le navigateur vérifie la position de la souris de temps en temps. Et s'il remarque des changements, il déclenche les événements.
Cela signifie que si le visiteur déplace la souris très rapidement, certains éléments du DOM peuvent être ignorés .
C'est une bonne chose pour les performances, car il peut y avoir de nombreux éléments intermédiaires. Nous n'avons pas vraiment envie d'entrer et de sortir de chacun d'eux.
D'un autre côté, il ne faut pas oublier que le pointeur de la souris ne "visite" pas tous les éléments en cours de route. Il peut "sauter".

En particulier, il est possible que le pointeur saute en plein milieu de la page depuis l'extérieur de la fenêtre. Dans ce cas, relatedTarget est nul, car il ne vient de "nulle part".
Vous pouvez le vérifier "en direct" sur un banc d'essai dont le code ci-dessous.
Son HTML comporte deux éléments imbriqués : la <div id=" enfant "> est à l'intérieur de la <div id=" parent ">. Si vous déplacez rapidement la souris au-dessus d'eux, alors peut-être que seule la <div id=" enfant " déclenchera des événements, ou peut-être celle du parent, ou peut-être qu'il n'y aura pas d'événements du tout.

Placez également le pointeur dans la division enfant, puis déplacez-le rapidement vers le bas. Si le mouvement est suffisamment rapide, l'élément parent est ignoré. La souris traversera l'élément parent sans s'en apercevoir.

Code

  Copier le code

<!doctype html>
<html>
<head>
  <meta charset="UTF-8">
 <title>Evénement de mouvement de la souris : Saut d'éléments</title>
  <style>
  #parent {
  background: #99C0C3;
  width: 160px;
  height: 120px;
  position: relative;
}
#enfant {
  background: #FFDE99;
  width: 50%;
  height: 50%;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
textarea {
  height: 140px;
  width: 300px;
  display: block;
}
  </style>
</head>
<body>
  <div id="parent">Elément parent
    <div id="enfant">Elément enfant</div>
  </div>
  <textarea id="text"></textarea>
  <input onclick="clearText()" value="Effacer" type="button">
  <script>
    let parent = document.getElementById('parent');
parent.onmouseover = parent.onmouseout = parent.onmousemove = handler;
function handler(event) {
  let type = event.type;
  while (type.length < 11) type += ' ';
  log(type + " target=" + event.target.id)
  return false;
}
function clearText() {
  text.value = "";
  lastMessage = "";
}
let lastMessageTime = 0;
let lastMessage = "";
let repeatCounter = 1;
function log(message) {
  if (lastMessageTime == 0) lastMessageTime = new Date();
  let time = new Date();
  if (time - lastMessageTime > 500) {
    message = '------------------------------\n' + message;
  }
  if (message === lastMessage) {
    repeatCounter++;
    if (repeatCounter == 2) {
      text.value = text.value.trim() + ' x 2\n';
    } else {
      text.value = text.value.slice(0, text.value.lastIndexOf('x') + 1) + repeatCounter + "\n";
    }
  } else {
    repeatCounter = 1;
    text.value += message + "\n";
  }
  text.scrollTop = text.scrollHeight;
  lastMessageTime = time;
  lastMessage = message;
}
  </script>
</body>
</html>

Mouseout lors du passage à un enfant

Une caractéristique importante du mouseout, il se déclenche, lorsque le pointeur se déplace d'un élément à son descendant, par exemple de #parent à #enfant.
Si nous sommes sur #parent et que nous déplaçons le pointeur plus profondément dans #enfant, nous obtenons le mouseout sur #parent !

Cela peut sembler étrange, mais s'explique facilement.
Selon la logique du navigateur, le curseur de la souris ne peut se trouver qu'au-dessus d'un seul élément à la fois - l'élément le plus imbriqué et le plus haut selon l'indice z.
Ainsi, s'il passe à un autre élément (même descendant), il quitte l'élément précédent.
Veuillez noter un autre détail important du traitement des événements.
L'événement de survol d'un élément descendant s'étend vers le haut. Donc, si #parent a un gestionnaire de mouseover, il se déclenche :

Vous pouvez très bien le voir dans l'exemple ci-dessous : <div id="enfant"> est à l'intérieur de la <div id="parent">. Il y a des gestionnaires de mouseover/out sur l'élément #parent qui sortent les détails de l'événement.
Si vous déplacez la souris de #parent à #enfant, vous voyez deux événements sur #parent :
mouseout [target : parent] (quitte le parent), puis
mouseover [target : enfant] (arrive à l'enfant,).

Code

  Copier le code

<!doctype html>
<html>
<head>
  <meta charset="UTF-8">
 <title>Evénement de mouvement de la souris : Saut d'éléments</title>
 <style>
  #parent {
  background: #99C0C3;
  width: 160px;
  height: 120px;
  position: relative;
}
#enfant {
  background: #FFDE99;
  width: 50%;
  height: 50%;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
textarea {
  height: 140px;
  width: 300px;
  display: block;
}
</style>
</head>
<body>
 <div id="parent" onmouseover="mouselog(event)" onmouseout="mouselog(event)">Elément parent
    <div id="enfant">Elément enfant</div>
  </div>
  <textarea id="text"></textarea>
  <input type="button" onclick="text.value=''" value="Effacer">
  <script>
    function mouselog(event) {
  let d = new Date();
  text.value += `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()} | ${event.type} [target: ${event.target.id}]\n`.replace(/(:|^)(\d\D)/, '$10$2');
  text.scrollTop = text.scrollHeight;
}
  </script>
</body>
</html>

Et voilà nous avons fait le tour dans la plus part des événement de la souris, il reste quelques uns que nous utilisons presque jamais


créer par carabde le 4 fevrier 2022




Voir aussi nos tutoriel :

Barres de navigation et menu entête en bootstrap

Comment créer les en-têtes de navigation fixes et réactive en utilisant le composant navbar de Bootstrap.

fonction strnatcasecmp, strnatcasecmp

Comparaison de chaînes avec l'algorithme d'"ordre naturel" (insensible la casse)

L'attribut tabindex

Spécifie l'ordre de tabulation d'un élément