ou devrais-je dire, des choses que vous devriez savoir sur les événements DOM.

Si vous avez eu la chance de faire du Javascript côté client, vous avez certainement eu à gérer les événements JS. Bien que des bibliothèques comme Jquery l’aient rendu très facile et simple à faire, il y a encore quelques parties ombragées qui, je pense, méritent d’être examinées.

L’objet event

Commençons par capturer un objet event factice et jetons un coup d’oeil dessus, c’est aussi simple que de faire ceci :

document.body.addEventListener("click", function(event) {
  console.log(event);
});

Si vous regardez l’objet, vous devriez vous retrouver avec quelque chose comme ça :

événements JS

Vous pouvez voir beaucoup de propriétés liées à la position réelle de l’événement JS. La propriété isTrusted indique que l’événement a été généré par un utilisateur réel et non par un script. Aujourd’hui, nous n’allons pas les couvrir tous, mais seulement les quatre à l’intérieur des rectangles rouges.

useCapture, ou le paramètre inconnu des événements JS

C’est ainsi que j’ai ajouté l’écouteur de l’événement à mon body :

document.body.addEventListener("click", function(event) {
  console.log(event);
});

Voici à quoi ressemblait mon DOM lors de la capture de cet événement :

<body>
    <div id="div1">
        Cliquez moi!
    </div>
</body>

Donc en cliquant sur une balise div, un gestionnaire attaché au corps a été exécuté, comment est-ce possible ? Je veux dire, j’ai cliqué sur un tag div, pas sur le corps. Eh bien, la première réponse qui vous vient à l’esprit pourrait être :

“Les événements javascript traversent dom, fin de l’histoire, rien qui vaille la peine d’écrire un article”

Et vous avez raison, les événements JS traversent le dom, mais dans quel ordre ? Je veux dire, pensez-y. Deux ordres sont possibles, et les deux ont le même sens.

L’ordre du dom

Donc le DOM est un arbre, et pour traverser un arbre vous allez de la racine aux feuilles n’est ce pas ? Donc dans mon cas, la balise body serait la racine, et la balise div serait la feuille, est-ce que cela semble acceptable ?

“Hum pourquoi pas ?, qu’en est-il de l’autre approche”’ ?

L’ordre UI

Vous pourriez également soutenir que parce que vous, en tant qu’utilisateur, voyez la div au-dessus du corps, et donc cliquez sur la div et non sur le corps, l’événement pourrait passer de la div au corps. Des feuilles à la racine. Et ça aussi, c’est logique.

“Oui, c’est plus logique, et c’est ce que j’ai observé, où est la vérité?”’.

La vérité est au W3C, passons-la en revue ensemble et jetons un coup d’oeil à la méthode addEventListener.

element.addEventListener(event, function, useCapture)

http://www.w3schools.com/jsref/met_element_addeventlistener.asp

Vous voyez ce troisième paramètre booléen, c’est là que toute la magie opère. Par défaut, ce paramètre est faux, ce qui signifie, en suivant la sémantique, que par défaut nous n’utilisons pas la capture. Notez que ce troisième argument est la raison pour laquelle je n’ai pas pu écrire ce post avec Jquery. La méthode click() (ou toute autre méthode liée à un événement), ne prend pas un troisième paramètre.

“Mais qu’est-ce que la capture ?”

La capture est un mode et serait ce que nous appelions auparavant l’ordre DOM. L’autre mode, le mode par défaut, est le bubbling mode, l’ordre de l’interface utilisateur si vous préférez. Ces deux modes décideront si le gestionnaire sera exécuté pendant la phase de capture ou la phase de bubbling.

La phase de bubbling et de capture dans les events JS

Lorsque vous cliquez sur un document, l’événement vient d’abord de la racine de votre DOM, le noeud window, vers les feuilles, c’est la phase de capture. Une fois que l’événement a atteint la feuille, comme une bulle d’eau qui tente de remonter à la surface, l’événement retourne à la racine du DOM, c’est la phase de bubbling.

Ordre de propagation des events js

En réglant ce troisième paramètre, vous dites simplement à votre élément DOM d’exécuter le gestionnaire pendant la phase de bubbling ou pendant la phase de capture. Parce que le paramètre a une valeur par défaut qui couvre la plupart des cas d’utilisation, il a été oublié. En l’utilisant correctement, nous pouvons avoir beaucoup plus de contrôle sur notre événement, comme je vais vous le montrer.

Que se passerait-il si nous ajoutions un écouteur d’événement, pour chaque phase, dans quel ordre serait-il déclenché ? Changeons un peu le code.

//Capturing phase
document.body.addEventListener("click", function(event) {
  console.log(" body capturing");
}, true);

document.getElementById("div1").addEventListener("click", function(event) {
  console.log(" div1 capturing");
}, true);

//Bubbling phase
document.getElementById("div1").addEventListener("click", function(event) {
  console.log(" div1 bubbling");
}, false);

document.body.addEventListener("click", function(event) {
  console.log(" body bubbling");
}, false);

Et comme prévu, la console nous montre le parcours si on clique sur la div :

body capturing
div1 capturing
div1 bubbling 
body bubbling 

Vous pouvez y aller et vérifier par vous-même

See the Pen Events JS : Bubbling and capturing by Siddhy (@Siddhyn) on CodePen.

Comme vous pouvez le voir c’est très simple, ce troisième paramètre vous permet de savoir si les divs externes doivent exécuter le gestionnaire avant ou après les divs internes. Notez qu’à tout moment vous pouvez dire à l’événement de cesser de se propager dans l’un ou l’autre mode en utilisant :

event.stopPropagation()

CurrentTarget et target

Maintenant que vous comprenez que les événements traversent les DOM dans les deux sens, il y a une question à laquelle il est encore difficile de répondre.

Comment dans mon gestionnaire puis-je savoir d’où vient l’événement ?

Par exemple, dans notre gestionnaire attaché au corps, si je veux exécuter le gestionnaire lorsqu’on clique sur le corps, et seulement sur le corps, pas dans div ci-dessus. C’est exactement un cas où vous pourriez utiliser currentTarget et target.

currentTarget est génial, currentTarget aura toujours la valeur de l’élément DOM auquel est attaché l’écouteur d’événement. Cela signifie que dans notre cas, currentTarget aura toujours l’élément body comme valeur.

target aura pour valeur l’élément DOM qui reçoit l’événement en premier lieu (l’élément sous votre souris). Donc si vous voulez que le gestionnaire ne soit exécuté que lorsque le corps est “vraiment” cliqué, vous pouvez faire quelque chose comme ça :

document.body.addEventListener("click", function(event) {
  // Target and currentTarget are the same
  // You clicked on the body
  if(event.target === event.currentTarget) {
    // the behavior you want
  } else {
    // default behavior
  }
}, false);

Conclusion

Les événements JS peuvent être difficile à comprendre dans un premier lieu car ils ont différentes manières de se propager. Par contre grâce à cela tout est faisable et vous avez la main pour faire – presque – tout ce que vous voulez.

Si vous avez des questions supplémentaires sur les events JS je vous invite à me les laisser dans les commentaires et j’essaierai d’y répondre du mieux possible 😉

Catégories : javascript

siddhy

Développeur web full stack depuis une 15aine d'année dans une agence web du sud de la France et Geek depuis toujours, l'apprentissage et le partage font parti intégrante de ma philosophie au même titre que l'évolution personnelle et la sagesse bouddhiste.

0 commentaire

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *