La gestion des événements

Introduction

Un événement est une action ou une situation détectée par le navigateur. Lorsqu'il se produit, il peut déclencher une fonction JavaScript, c'est-à-dire un ensemble d'instructions organisées pour accomplir une tâche précise.

Voici quelques exemples d'événements courants :

Les directives d'événements

En JavaScript vanilla (sans framework), la bonne pratique pour réagir à un événement est d'utiliser la méthode addEventListener(). Cette approche permet d'attacher un gestionnaire d'événement (event handler) à un élément HTML de manière propre, sans mélanger structure HTML et logique JavaScript.

Exemple : clic sur le bouton "Suivant" d'un carrousel

En JavaScript vanilla (Par exemple, dans le fichier index.html) :


                <button id="btnSuivant" type="button">Image suivante</button>

                <script>
                // 1. Définir le gestionnaire (fonction appelée lors du clic).
                const passerImageSuivante = () =>
                {
                    // Logique : passer à l'image suivante...
                    console.log('Simulation du passage à l\'image suivante');
                };

                // 2. Cibler le bouton (sélecteur CSS).
                const boutonSuivant = document.querySelector('#btnSuivant');

                // 3. Attacher l'écouteur sur l'événement "click".
                boutonSuivant.addEventListener('click', passerImageSuivante);
                </script>
            

Avec Vue.js (Par exemple, dans le fichier App.vue) :



                <script setup>
                // 1. Définir le gestionnaire (fonction appelée lors du clic).
                const passerImageSuivante = () => 
                {
                    // Logique : passer à l'image suivante...
                    console.log('Simulation du passage à l\'image suivante');
                };
                </script>

                <template>
                    <!-- 2. Attacher l'écouteur sur l'événement "click". -->
                    <button type="button" v-on:click="passerImageSuivante">Image suivante</button>
                </template>
            

On utilise ici une directive d'événement v-on, qui permet de réagir à un événement déclenché par l'utilisateur (comme un clic de souris, une touche pressée au clavier, etc.).

Lors de la compilation du composant, le compilateur de templates de Vue analyse cette directive et la transforme en code JavaScript natif qui utilise addEventListener() pour attacher le gestionnaire d'événement à l'élément concerné. Ainsi, le navigateur ne reçoit jamais la directive v-on:@click telle quelle, mais uniquement le code JavaScript nécessaire à son exécution.

Notez qu'il existe un alias permettant d'écrire la directive de manière encore plus concise. Il s'agit du symbole @ suivi directement du nom de l'événement. Par exemple, @click="maFonction" est strictement équivalent à v-on:click="maFonction".


                <template>
                    <!-- @click est l'abréviation de v-on:click -->
                    <button type="button" @click="gererCarrouselBtnSuivant">Image suivante</button>
                </template>
            

Vue permet d'écouter les événements DOM natifs en utilisant exactement les mêmes noms que ceux employés en JavaScript classique (par exemple @click, @input, @scroll, @keydown, etc.). Cela signifie que vous pouvez réutiliser la totalité des événements existants du DOM, tels qu'ils sont définis dans la documentation JavaScript standard. Pour consulter la liste complète, vous pouvez vous référer à la page « Liste des événements » de MDN.

Passer des arguments aux fonctions dans les directives d'événements

Dans certains cas, il est utile de fournir une valeur précise à la fonction au moment où l'événement se déclenche (par exemple l'identifiant d'un produit, le nombre d'articles à ajouter, etc.). Vue permet, de passer directement ces valeurs en argument dans les directives.


                <script setup>
                const ajouterAuPanier = (idProduit) => 
                {
                    // Logique : vérifier la validité de l'ID produit (idProduit), mettre à jour le panier local, ...
                };
                </script>

                <form>
                    <input type="text" name="nom" placeholder="Ex : Casque audio">
                    <input type="number" name="quantite">
                    <button type="button" @click="ajouterAuPanier(42)">Ajouter au panier</button>
                </form>
            

Dans cet exemple, le nombre 42 est directement passé en argument à la fonction ajouterAuPanier lors du clic.

L'objet événement

Tout comme avec addEventListener() en JavaScript vanilla, Vue transmet automatiquement l'objet événement déclenché à la fonction associée si aucun autre argument n'est passé explicitement dans la directive. Cela permet, par exemple, d'identifier l'élément qui a provoqué l'action.

Exemple :


                <script setup>
                const afficherElementClique = (event) => 
                {
                    console.log("Élément cliqué :", event.currentTarget);
                };
                </script>

                <template>
                    <button type="button" @click="afficherElementClique">Bouton A</button>
                    <button type="button" @click="afficherElementClique">Bouton B</button>
                </template>
            

Dans cet exemple, chaque clic appelle la fonction afficherElementClique. Vue transmet automatiquement, en premier argument, un objet décrivant l'événement. Celui-ci permet notamment d'accéder à l'élément déclencheur grâce à event.currentTarget.

Dès qu'un argument personnalisé est fourni dans la directive, l'évènement n'est plus transmis automatiquement. Pour y accéder, il faut ajouter explicitement la variable spéciale $event dans l'appel de la fonction.

Dans l'exemple suivant, on souhaite transmettre un argument personnalisé correspondant au mot-clé à rechercher, ainsi que l'objet représentant l'évènement afin d'appeler preventDefault(). Cette méthode est souvent employée pour empêcher le comportement par défaut d'un élément, comme l'envoi classique d'un formulaire qui rechargerait la page, et ainsi pouvoir gérer l'action selon une logique personnalisée.


                <script setup>
                const modifierComportementLien = (idLien, event) =>
                {
                    // Empêche le comportement par défaut du lien (navigation vers l'URL du href).
                    event.preventDefault();

                    // Le nouveau comportement du lien cliqué...
                    console.log(`Comportement du lien avec l'id ${idLien} modifié !`);
                };
                </script>

                <template>
                    <!-- 
                        Ici, on appelle une fonction en lui passant un argument personnalisé (123).
                        Dès qu'on ajoute un argument, Vue ne transmet plus automatiquement l'objet event.
                        Il faut donc le passer manuellement en utilisant la constante spéciale $event.
                    -->
                    <p><a href="https://cvmdev.be" @click="modifierComportementLien(1, $event)">Plus beau site web du monde !</a></p>
                    <p><a href="https://brunomartin.be/" @click="modifierComportementLien(2, $event)">Plus moche site web du monde !</a></p>
                </template>
            

Les modificateurs d'événements

Les directives d'événements peuvent être enrichies grâce à des modificateurs. Un modificateur est un mot-clé ajouté au nom de l'événement, séparé par un point (ex. : @click.prevent). Il permet de modifier le comportement de l'événement ou de le filtrer avant d'exécuter la fonction.

On distingue deux grandes catégories :

Modificateurs de comportement global

Certains modificateurs s'appliquent à tout type d'événement et en modifient le fonctionnement global. Reprenons l'exemple de la section précédente. Lors de la soumission d'un formulaire, on appelait manuellement event.preventDefault() pour empêcher le rechargement de la page et garder la main sur la logique personnalisée. Avec Vue, il suffit d'ajouter le modificateur .prevent dans la directive, par exemple @click.prevent, ce qui évite d'écrire ce code manuellement.


                <script setup>
                const modifierComportementLien = (idLien) =>
                {
                    console.log(`Comportement du lien avec l'id ${idLien} modifié !`);
                };
                </script>

                <template>
                    <!-- 
                        Utilisation du modificateur .prevent pour simplifier le code
                        et éviter d'écrire event.preventDefault() dans la fonction.
                    -->
                    <p><a href="https://cvmdev.be" @click.prevent="modifierComportementLien(1)">Plus beau site web du monde !</a></p>
                    <p><a href="https://brunomartin.be/" @click.prevent="modifierComportementLien(2)">Plus moche site web du monde !</a></p>
                </template>
            

Il existe d'autres modificateurs globaux très utiles comme :

Pour la liste complète et détaillée des modificateurs globaux, vous pouvez consulter la documentation officielle de Vue.js .

Modificateurs liés au clavier

Les modificateurs de touche permettent de filtrer les événements clavier (@keydown, @keyup) afin de déclencher une fonction uniquement quand une touche précise est pressée. Cela évite de devoir vérifier manuellement quelle touche a été utilisée dans le code.

Les noms de touches utilisés dans les modificateurs proviennent directement de la propriété KeyboardEvent.key. Vue applique toutefois une version normalisée en minuscules. Par exemple, si la touche "A" est pressée, il suffit d'utiliser le modificateur en minuscule : @keydown.a.

Pour les touches dont le nom est composé, comme CapsLock ou encore PageDown, il faut convertir leur valeur en kebab-case (tout en minuscules et les mots séparés par des tirets). Ainsi, pour configurer la touche CapsLock, on écrit @keydown.caps-lock.


                <script setup>
                const ajouterElement = () =>
                {
                    console.log('Élement ajouté !');
                };

                const alerterToucheVerrouillageMajuscules = () =>
                {
                    console.log('Vous venez d\'appuyer sur la touche CapsLock !');
                };
                </script>

                <template>
                    <!-- Déclenche si l'utilisateur tape sur "A" pour ajouter un élément -->
                    <input type="text" @keyup.a="ajouterElement">

                    <!-- Déclenche si l'utilisateur appuie sur "CapsLock" pour afficher un avertissement -->
                    <input type="text" @keyup.caps-lock="alerterToucheVerrouillageMajuscules">
                </template>
            

Pour les touches les plus couramment utilisées, Vue fournit des alias simplifiés. Ces alias rendent les modificateurs plus lisibles et cohérents, tout en utilisant une version normalisée en minuscules :

Modificateurs liés aux touches système

Ces modificateurs détectent si une touche spéciale est maintenue enfoncée (Ctrl, Shift, Alt, Meta). Contrairement aux modificateurs de touches classiques (comme .enter ou .esc) qui ne fonctionnent qu'avec les événements clavier (@keydown, @keyup), ces touches système peuvent également être utilisées avec d'autres événements, comme @click.


                <!-- 
                    Appel la fonction "ouvrirDansNouvelOnglet()" si l'utilisateur 
                    clique sur le bouton tout en maintenant la touche "Ctrl" enfoncée.
                -->
                <button @click.ctrl="ouvrirDansNouvelOnglet">Ouvrir</button>
            

Modificateurs liés à la souris

Les événements de clic peuvent être filtrés selon le bouton de la souris. Cela évite d'écrire des conditions dans la fonction.


                <script setup>
                const actionGauche = () =>
                {
                    console.log('Clique gauche détecté !');
                };

                const actionDroite = () =>
                {
                    console.log('Clique droit détecté !');
                };

                const actionMolette = () =>
                {
                    console.log('Clique molette détecté !');
                };
                </script>

                <template>
                    <!-- Clic gauche -->
                    <button @click.left="actionGauche">Bouton gauche</button>

                    <!-- Clic droit -->
                    <button @click.right="actionDroite">Bouton droit</button>

                    <!-- Clic molette -->
                    <button @click.middle="actionMolette">Bouton molette</button>
                </template>
            

Combiner plusieurs modificateurs

Il est possible d'utiliser plusieurs modificateurs en même temps sur une même directive d'événement :


                <!-- 
                    1. self : L'événement ne se déclenche que si l'utilisateur clique directement sur la balise 'button' elle-même (et non sur un élément enfant).
                    2. prevent : Empêche le comportement par défaut.
                -->
                <button @click.self.prevent="gererClick">Bouton B</button>

                <!-- 
                    1. ctrl.s : Déclenche uniquement si Ctrl+S est pressé.
                    2. prevent : Empêche l'action par défaut (sauvegarde du navigateur).
                -->
                <input type="text" @keydown.ctrl.s.prevent="sauvegarder">
            

L'ordre des modificateurs peut modifier le comportement obtenu.


                <script setup>
                const minimiserConteneur = () =>
                {
                    console.log('Conteneur minimisé avec succès !');
                };
                </script>

                <!-- Appelle toujours 'event.preventDefault()', même si le clic provient d'un élément enfant. -->
                <template>
                    <div @click.prevent.self="minimiserConteneur">
                        <p>
                            <a href="https://fr.vuejs.org/" target="_blank" rel="noopener noreferrer">Lien impossible à cliquer</a>
                            à cause de l'ordre des modificateurs ".prevent.self" sur la balise parent !
                        </p>
                    </div>
                </template>
            

Dans ce cas, event.preventDefault() est exécuté avant la vérification de .self. Le clic sur l'élément enfant est donc bloqué, ce qui empêche le lien d'être suivi normalement.

Pour éviter ce problème, il suffit d'inverser l'ordre des modificateurs et d'écrire .self.prevent. Dans ce cas, la condition .self est vérifiée en premier, et event.preventDefault() n'est exécuté que si le clic provient directement de l'élément sur lequel est appliqué le déclancheur de l'événement @click.

Exercices

Créer un nouveau projet Vue nommé vuejs02-gestion-evenements en suivant la procédure décrite dans le chapitre dédié. Tous les exercices de cette page peuvent être réalisés dans ce projet, directement les uns à la suite des autres dans le fichier App.vue.

Dans la partie template, créer une balise <h1> avec le texte suivante : "Vue.js 02 : La gestion des événements".

Exercice 01 : Premier clic

Objectif : Découvrir l'utilisation de la directive d'événement @click.

Instructions :

  1. Dans la partie <script>, déclarer une fonction direBonjour() qui affiche dans la console "Bonjour Vue.js !".
  2. Dans la partie <template>, ajouter un sous-titre <h2> avec le texte "Exo 01".
  3. Ajouter un bouton qui appelle direBonjour() lors du clic.
  4. Tester dans le navigateur et observer la console.

Exercice 02 : Un même gestionnaire pour plusieurs éléments

Objectif : Réutiliser une même fonction pour plusieurs boutons et identifier lequel a été cliqué grâce à $event.

Instructions :

  1. Dans la partie <script>, déclarer une fonction afficherSource(event) qui affiche dans la console le texte du bouton cliqué à l'aide de event.currentTarget.textContent.
  2. Dans la partie <template>, ajouter un sous-titre <h2> avec le texte "Exo 02".
  3. Ajouter trois boutons "Accueil", "Produits", "Contact" qui appellent tous afficherSource().
  4. Cliquer chaque bouton et vérifier le message en console.

Exercice 03 : Passer un argument simple

Objectif : Transmettre une valeur à la fonction appelée par l'événement.

Instructions :

  1. Dans la partie <script>, déclarer une fonction afficherMessage(message) qui affiche le paramètre message dans la console.
  2. Dans la partie <template>, ajouter un sous-titre <h2> avec le texte "Exo 03".
  3. Ajouter deux boutons qui appellent respectivement afficherMessage('Bonjour') et afficherMessage('Au revoir').
  4. Tester et observer la console.

Exercice 04 : Passer un argument ainsi que l'objet event

Objectif : Transmettre un argument personnalisé et l'objet événement à la fonction appelée par l'événement.

Instructions :

  1. Dans la partie <script>, déclarer une fonction selectionner(id, event) qui affiche dans la console "Sélection de [id]" et le type d'élément cliqué via event.currentTarget.tagName.
  2. Dans la partie <template>, ajouter un sous-titre <h2> avec le texte "Exo 04".
  3. Ajouter deux boutons qui appellent chacun la fonction selectionner() en lui passant un identifiant ('produit-01' pour le premier bouton et 'produit-02' pour le second).
  4. Tester et observer la console.

Exercice 05 : Empêcher le comportement par défaut

Objectif : Empêcher l'envoi classique d'un formulaire avec le modificateur .prevent.

Instructions :

  1. Dans la partie <script>, déclarer une fonction rechercher() qui affiche dans la console "Recherche effectuée".
  2. Dans la partie <template>, ajouter un sous-titre <h2> avec le texte "Exo 05".
  3. Créer un formulaire minimal avec un champ texte et un bouton de type "submit".
  4. Associer l'événement @submit au formulaire qui appelle la fonction rechercher(), sans oublier d'appliquer le modificateur .prevent afin d'empêcher l'action par défaut du formulaire, c'est-à-dire le rechargement de la page lors de sa soumission.
  5. Vérifier que la page ne se recharge pas suite à la soumission du formulaire et que la fonction est bien appelée.

Exercice 06 : Un seul déclenchement

Objectif : Utiliser le modificateur .once pour n'exécuter un gestionnaire qu'une seule fois.

Instructions :

  1. Dans la partie <script>, déclarer une fonction confirmerInscription() qui affiche "Inscription confirmée" dans la console.
  2. Dans la partie <template>, ajouter un sous-titre <h2> avec le texte "Exo 06".
  3. Créer un bouton et lui associer l'événement @click. L'événement appelle la fonction confirmerInscription(), sans oublier d'appliquer le modificateur .once afin que cette fonction ne soit exécutée qu'une seule fois, même si l'utilisateur clique plusieurs fois sur le bouton.
  4. Cliquer plusieurs fois et vérifier que la fonction ne s'exécute qu'au premier clic.

Exercice 07 : Différencier les clics de la souris

Objectif : Utiliser des modificateurs de bouton souris pour adapter l'action.

Instructions :

  1. Dans la partie <script>, déclarer trois fonctions clicGauche(), clicMilieu() et clicDroit() qui affichent des messages distincts dans la console.
  2. Dans la partie <template>, ajouter un sous-titre <h2> avec le texte "Exo 07".
  3. Créer trois boutons cliquables qui déclanchent respectivement les fonctions clicGauche(), clicMilieu() et clicDroit().
  4. Tester les différents clics et observer la console.

Exercice 08 : L'ordre des modificateurs compte

Objectif : Mettre en évidence que l'ordre des modificateurs peut changer le comportement final d'un événement.

Instructions :

  1. Dans la partie <script>, déclarer une fonction guiderUtilisateur() qui affiche dans la console le message : "Attention : vous devez cliquer sur la case à cocher !".
  2. Dans la partie <template>, ajouter un sous-titre <h2> avec le texte "Exo 08".
  3. Ajouter un paragraphe de consigne expliquant à l'utilisateur qu'il doit essayer de cocher les cases dans deux blocs différents et observer la différence de comportement.
  4. Créer deux blocs <fieldset> avec un titre <legend> ("Bloc A" et "Bloc B"). Chaque bloc contient un <label> et une case à cocher <input type="checkbox">.
    • Bloc A : appliquer @click.prevent.self="guiderUtilisateur" sur le <fieldset>.
    • Bloc B : appliquer @click.self.prevent="guiderUtilisateur" sur le <fieldset>.
  5. Cliquer sur le texte du <label> (et non directement sur la case). Vérifier :
    • Le message affiché en console.
    • Le comportement de la case à cocher (elle se coche/décoche ou reste bloquée).
  6. Expliquer en une phrase pourquoi les résultats diffèrent : Dans le Bloc A, .prevent agit avant .self et empêche la case de fonctionner, alors que dans le Bloc B, la vérification .self est faite avant, ce qui laisse la case utilisable.

Exercice 09 : Envoyer un message avec une combinaison de touches

Objectif : Simuler l'envoi d'un message en interceptant une combinaison de touches (Ctrl+Entrée).

Instructions :

  1. Dans la partie <script>, écrire une fonction envoyer(event) qui affiche en console le contenu de la zone de texte en utilisant event.currentTarget.value.
  2. Dans la partie <template>, ajouter un sous-titre <h2> avec le texte "Exo 09".
  3. Ajouter une zone de texte <textarea>. Associer-lui l'événement clavier adapté et combiner les modificateurs nécessaires pour que la fonction envoyer() soit appelée uniquement lorsque l'utilisateur appuie en même temps sur Ctrl et Entrée. Il faudra également empêcher l'ajout automatique d'une nouvelle ligne lors de cette combinaison de touches.
  4. Tester dans le navigateur :
    • Appuyer sur Entrée seule doit insérer une nouvelle ligne dans la zone de texte sans rien afficher dans la console.
    • Appuyer sur Ctrl+Entrée doit déclencher la fonction envoyer() et afficher le texte saisi dans la console.