link W3C close

Les événements en JavaScript

#1 Qu'est-ce qu'un événement ? open

Un événement, c'est une sorte de signal qui est envoyé au JavaScript par l'interface DOM. Ce signal est envoyé, lorsqu'il se passe quelque chose, sur un document qui est visualisé dans un navigateur. Par exemple, un clic de souris, le curseur de la souris qui survole une zone, la fin du chargement de la page.

Les éléments qui constituent un document étant en général nombreux, les signaux envoyés par l'interface sont nombreux et constituent ce que l'on appelle un flux d'événements. Ce flux est envoyé par défaut, sans que le programmeur JavaScript ait besoin de le demander.

Par contre, le programmeur a la possibilité d'écouter un événement faisant partie de ce flux, et de programmer un code qui s'exécutera à chaque fois qu'il "entendra" cet événement passer dans le flux. Il le fera en mettant en place un gestionnaire d'événement.

Etapes de la gestion d'un événement

Etape de la gestion d'un événement

On se rend bien compte ici, que l'interface DOM est une interface bidirectionnelle placée entre le JavaScript et le document visualisé. D'une part, le JavaScript peut descendre sur le document pour le modifier. D'autre part, l'interface informe le JavaScript de ce qui se passe au niveau du document sur le navigateur.

Notons tout de suite que les événements ne sont pas "envoyés" seulement au JavaScript. Le CSS reçoit aussi un certain nombre d'événements. Il conviendra de traiter ce qui relève du CSS dans le CSS et ce qui relève du JavaScript dans le JavaScript. Je vous donne un exemple. Lorsque vous changez la taille de la fenêtre de visualisation, c'est le CSS qui traitera l'événement et qui reconfigurera la présentation du document. On y reviendra.

#2 La liste des principaux événements open

Le nom de l'événement est le nom JavaScript de l'événement. C'est celui que vous devez utiliser dans les gestionnaires d'événements. Ne confondez pas avec les noms des attributs HTML. Des noms comme onload, onclick qui sont des noms d'attribut HTML et qui ont leur "équivalent" en termes de nom de propriété JavaScript.

Nom de l'événement Description
load fin de chargement de la page web
click clic sur un élément
dblclick double clic sur un élément
keydown une touche est appuyée
keypress une touche est maintenue enfoncée
keyup une touche est relâchée
mouseenter le curseur entre au dessus d'un élément
mouseleave le curseur quitte l'élément
select sélection d'une option dans un select
change changement de valeur sur un select, un checkbox..
submit soumission d'un formulaire
focus l'élément reçoit le focus
blur l'élément perd le focus

La liste des événements est très longue. Je vous mets un lien, vers une liste complète, visible sur une page de la documentation ici

#3 Gérer les événements avec la méthode JavaScript element.addEventListener() open

La méthode addEventListener() appelée par un élément écoute un événement sur cet élément. Lorsque cet événement est détecté, la méthode appelle une fonction callback, que vous devez lui passer en argument. C'est dans cette fonction que vous placez votre code.

Syntaxe

void addEventListener(evt, callback [,capture]);

Paramètres

evt est une chaîne de caractères représentant le nom de l'événement.

callback est une fonction. Le plus souvent, on utilise une fonction anonyme. On la déclare à cet endroit, mais vous pouvez très bien mettre le nom d'une fonction (attention sans les parenthèses, sinon vous invoquez la fonction c'est-à-dire que vous l'appelez).

capture est un booléen optionnel. S'il est true, c'est dans la phase de capture que sera traité l'événement. S'il est false, ce sera dans la phase de bouillonnement (voir ci-dessous). Si vous ne le mettez pas, il est considéré comme false.

Exemple

Tester le code

A signaler qu'il existe aussi la méthode removeEventListener() pour enlever un gestionnaire d'événement.

#4 Comment se propagent les événements dans l'arbre du document ? open

Dans l'exemple précédent, nous avons cliqué sur le paragraphe, on pourrait penser que seul le paragraphe a reçu l'événement et l'a traité. Il n'en est rien, car certains événements se propagent. Pas tous mais la plupart, et c'est le cas du click.

Phases de capture et de bouillonnement

En fait, notre clic s'est propagé à travers toute la hiérarchie des ancêtres qui se trouvent entre la racine du document et le paragraphe.

Il y a eu une première phase que l'on appelle la phase de capture dans laquelle l'événement est parti de la racine du document pour descendre jusqu'au paragraphe.

Ensuite, il y a eu une deuxième phase que l'on appelle phase de bouillonnement dans laquelle l'événement est remonté du paragraphe vers la racine du document en traversant une nouvelle fois la liste de ses ancêtres.

La conséquence, c'est qu'un ancêtre a la possibilité lui aussi d'écouter un événement qui peut se produire sur l'un de ses enfants et de le traiter lorsqu'il le détecte dans le flux. Attention toutefois, le fait de détecter et de traiter un événement ne stoppe pas sa propagation.

Dans l'exemple ci-dessous, cliquez sur le paragraphe. Constatez la propagation de l'événement en phase de bouillonnement vers les éléments parents. D'abord la section puis le body.

Tester le code

Regardez bien le code et comprenez bien que ce n'est pas un code séquentiel traditionnel qui s'exécute. C'est d'abord le gestionnaire du paragraphe qui traite l'événement, puis celui de la section, puis celui du body. Vous voyez bien qu'on remonte "dans le code". Seule la mise en place des gestionnaires est séquentielle.

Un même événement peut être écouté et traité, soit pendant la phase de capture, soit pendant la phase de bouillonnement. Par défaut, il sera traité pendant la phase de bouillonnement. C'est ce que l'on vient de mettre en évidence dans l'exemple. Un troisième argument peut être ajouté à la méthode addEventLitener pour choisir la phase de capture.

Une petite astuce mnémotechnique. Bouillonnement ça vient de "bubbling" qui vient de "bubble" qui veut dire bulle. Ce qu'il faut retenir, c'est que le bouillonnement est à l'image d'une bulle d'eau qui remonte à la surface.

Ajoutons un booléen true en troisième argument de addEventListener sur la section.

Cliquez sur le paragraphe, et vous allez constater que c'est le gestionnaire posé sur la section qui traite l'événement en premier pendant la phase de capture. Les autres suivent en phase de bouillonnement.

Tester le code

#5 L'objet JavaScript Event open

Il est possible de récupérer des informations sur l'événement dans la fonction qui traite l'événement. Pour cela, il faut placer un paramètre de déclaration dans la fonction qui traite l'événement. Ici, il faut comprendre ce que vous faites. Vous déclarez une fonction qui sera appelée par quelqu'un d'autre, en l'occurrence le gestionnaire d'événement. Il se trouve que par construction ce gestionnaire passe à la fonction qui lui est fournie un objet de constructeur Event au moment de l'appel de la fonction. Vous, de votre côté, vous vous contentez de prévoir ce paramètre dans votre déclaration et vous lui donnez le nom que vous voulez.

Tester le code

Comme vous pouvez le voir, il y a énormément d'informations contenues dans cet objet :

  • Position de la souris.
  • Touche du clavier qui a été enfoncée.
  • Le bouton de la souris qui a été cliqué.
  • Lorsqu'un événement se propage, vous pouvez savoir quel élément est à l'origine du clic.
  • Vous pouvez stopper la propagation d'un événement.
  • Et s'il y a un comportement par défaut, par exemple un clic sur un lien, qui va vous envoyer vers une page, eh bien, vous pouvez annuler ce comportement par défaut.

#6 Comment utiliser this open

Dans votre gestionnaire d'événement, vous pouvez accéder à l'élément sur lequel vous avez mis en place ce gestionnaire. Pour cela, vous devez utiliser le mot réservé this.

Dans l'exemple ci-dessous, this accède au paragraphe et change la couleur de son texte.

Tester le code

#7 Bloquer la propagation des événements avec la méthode event.stopPropagation() open

L'utilité ici est assez évidente, à savoir, stopper la propagation d'un événement. Dans l'exemple ci-dessous, on stoppe la propagation au niveau du paragraphe.

Tester le code

#8 Bloquer l'éventuel comportement par défaut avec la méthode event.preventDefault() open

Que signifie le nom de la méthode ? prevent est utilisé ici dans le sens d'empêcher, donc empêcher quoi ? Eh bien, le Default donc le comportement par défaut. Ca suppose, déjà qu'il y ait un comportement par défaut.

Par exemple, si vous cliquez sur un lien, vous êtes dirigé vers une nouvelle page. Si vous cliquez sur un bouton de soumission de formulaire, le formulaire est envoyé. Ca ce sont des comportements par défaut. Si vous cliquez sur un paragraphe, par défaut il ne se passe rien.

Dans l'exemple ci-dessous, on va utiliser le lien. On va renseigner href, et en plus, nous allons placer sur le lien un gestionnaire d'événement qui écoutera le click.

Si on ne fait rien de plus, au moment du clic, il va se passer dans l'ordre deux choses :

  1. Le traitement du click par le gestionnaire.
  2. Suivi du traitement par défaut, c'est-à-dire aller sur la page de wikipédia.

Pour bloquer le traitement par défaut, il nous faut utiliser la méthode preventDefault() dans la fonction de traitement appelée avant par le gestionnaire.

Tester le code

#9 La propriété target open

La propriété target vous indique quel est l'élément qui est à l'origine de l'événement. Dans le cas où, l'événement est détecté par un gestionnaire placé sur un parent, target vous indique quel est l'enfant sur lequel a été déclenché l'événement.

Il y a aussi la propriété currenTarget qui désigne l'élément sur lequel est placé le gestionnaire. Ne les confondez pas.

Dans l'exemple ci-dessous, la liste ul est encadrée par une bordure rouge et les li par une bordure noire.

Cliquez dans un élément de la liste et vous voyez que vous pouvez accéder à son id par l'intermédiaire de la propriété target.

Tester le code

#10 Déclencher un événement sur un élément cible open

Dans le programme ci-dessous, nous avons deux paragraphes qui sont frères. Si on clique sur un paragraphe l'événement n'est évidemment pas propagé au frère. Justement on va imaginer que c'est notre besoin et on va voir comment le programmer.

Il nous faut un gestionnaire d'événement sur le paragraphe p1 pour intercepter le premier clic. Dans ce gestionnaire on instancie l'objet Event avec la chaîne de caractères 'click'. Puis on "expédie" cet événement vers le deuxième paragraphe p2 avec la méthode dispatchEvent();. Bien sûr on a aussi besoin d'un gestionnaire sur p2 pour intercepter le clic expédié.

Notez bien que c'est sur p2 que se fait l'appel à dispachEvent() alors que c'est lui qui reçoit l'événement. Il faut donc voir ça comme une demande de "dispatch".

Tester le code

#11 D'autres manières "historiques" de gérer les événements open

Il est encore possible de traiter les événements au niveau du HTML en utilisant des attributs fait pour cela. C'est une technique obsolète qui n'est plus à utiliser, car on mélange le JavaScript au HTML. Toutefois, on trouve encore des codes dans lesquels cette méthode est utilisée. Je vous montre juste un exemple. Ce morceau de code passe à la validation !!

Le nom des attributs HTML se retrouve en ajoutant le préfixe on, devant le nom JavaScript de l'événement. Par exemple, pour l'événement JavaScript click l'attribut HTML s'appelle onclick. Le return false remplace ici le preventDefault.

Tester le code

Par contre, il est possible d'accéder à l'attribut HTML depuis le JavaScript en passant par une propriété JavaScript qui porte ici le même nom que l'attribut HTML et ça, c'est propre. Un exemple ci-dessous, pour attendre le chargement d'une page web, on passe par la propriété JavaScript onload de l'objet window.

Regardez cependant le problème que vous aurez si vous décidez d'écrire un deuxième script et d'attendre le chargement de la page avec la même méthode. Le problème viendra du fait que la propriété onload sera affectée une deuxième fois et par conséquent seul le deuxième code sera exécuté. Je vous laisse vérifier cela sur cet exemple ici. Par contre, vous n'avez par ce problème si vous utilisez addEventListener pour mettre en place vos deux gestionnaires. Vérifier ici.

#12 Gérer les événements en JavaScript ou en CSS ? open

Il ne faut pas oublier que le CSS3 est capable lui aussi d'intercepter des événements. Prenons le cas d'un élément qui est survolé par le curseur. On imagine que cet élément doit changer de couleur lorsqu'il est survolé.

Techniquement nous avons deux solutions pour faire cela :

  1. utiliser la pseudo-classe :hover de la feuille de style CSS.
  2. utiliser des gestionnaires d'événements JavaScript sur les événements mouseover et mouseout.

Dans ce cas, qui relève de la présentation du document, on laissera faire le CSS.