Gestion des évènements en Javascript

Jean-Marc Lecarpentier
Université de Caen

Les 3 couches du Web

  • Structure de la page : HTML
  • Mise en forme de la page : CSS
  • Interactions et comportement : Javascript
  • Objectif : séparation de ces 3 couches
Les 3 couches du web

Interactions ⇒ capter des évènements

  • Évènements se produisent sur la page : clic, survol de la souris, etc
  • Dire aux éléments « d'écouter » si un évènement se produit : event listener
  • Lorsque l'évènement est capté, il faut savoir quoi faire
  • Notion de programmation évènementielle

Capter un évènement : étapes

  1. Dire à un nœud élément d'écouter un évènement :
    elt.addEventListener(...)
  2. Dire quel type d'évènement attendre :
    elt.addEventListener('click', ...)
    L'élément déclenchera une action quand on clique dessus
  3. Dire quoi exécuter quand l'évènement est capté :
    elt.addEventListener('click', aFaire)
    aFaire est le nom de la fonction qui sera exécutée

addEventListener et fonction callback

  • DOM fournit une fonction : addEventListener
  • elt.addEventListener('click', maFonction) (avec elt qui est un objet de type Élément)
  • Deux arguments :
    1. le type d'évènement à capter : clic, etc (voir plus loin)
    2. le nom de la fonction à exécuter
  • On appelle cette fonction une fonction callback : c'est une fonction qui est passée en argument à une autre fonction
  • Concept de callback en programmation (article Wikipedia)

Fonction callback et évènement en Javascript

  • Ce qui se passe par exemple pour un clic sur un élément :
    1. L'utilisateur clique sur l'élément
    2. Le clic génère un objet de type Event
    3. Si l'élément possède un listener de clic alors celui-ci se charge d'appeler la fonction callback dont le nom a été donné au listener
    4. La fonction callback reçoit en argument l'objet Event créé
    5. La fonction callback est enfin exécutée

Fonction callback

  • Une fonction en Javascript est aussi un objet, on peut donc « mentionner » son nom comme une variable
  • elt.addEventListener('click', maFonction) : on donne en argument le nom de la fonction qui devra être exécutée. Ceci fait référence à l'objet fonction correspondant.
    Attention la fonction n'est pas exécutée à ce moment, donc pas de parenthèses !
  • La fonction callback sera exécutée lors du captage d'un événement. Lors de cette exécution, elle reçoit en argument uniquement l'objet évènement qui a été capté.

    let maDiv = document.getElementById('div1');
    maDiv.addEventListener('click', clicSurElement);

    function clicSurElement(event) {
        console.log("Un clic est capté");
        console.log(event);
    }
        
Démo

Types d'évènements

  • Évènements souris : mouseenter, mouseleave, click, mousedown, etc...
  • Évènements clavier : keyup, keydown, keypress (obsolète)
  • Évènements globaux : load, unload, resize, scroll, etc...
  • Évènements liés aux formulaires : focus, change, blur, submit
  • Plus évènements touchdown pour les appareils tactiles, les évènements fenêtre, les évènements liés aux différentes APIs, etc
Liste complète

Objet évènement

  • Objet Event dans le DOM
  • Un objet event est toujours passé en argument à la fonction callback déclenché par la capture d'un évènement.
    Aucun autre argument ne lui sera passé
  • Cet objet event fournit des informations sur le contexte d'exécution
  • Quelques propriétés de base :
    • type : le type de l'évènement
    • timeStamp : la date de création (en ms) de l'évènement
    • currentTarget : le nœud du DOM qui a déclenché le callback
    • target : le nœud du DOM qui a reçu l'évènement en premier
    • bubbles : booléen vrai si l'évènement est en phase de bubbling
    • Liste complète
  • Plus autres propriétés qui dépendent du type d'évènement, par exemple :
    • Évènement souris : screenX, screenY, clientX, clientY, etc liste complète
    • Évènement clavier : key, code, ctrlKey, altKey, etc liste complète
      Attention pas mal d'incompatibilités selon les navigateurs
Démo

Phases d'un évènement

  1. Capture : l'évènement descend dans l'arbre DOM jusqu'à sa cible
    peu utilisé et désactivé par défaut
  2. Target : l'évènement atteint sa cible, le callback est déclenché
  3. Bubble : l'évènement remonte
Capture et bubble

target et currentTarget

  • target : le nœud du DOM qui a reçu l'évènement en premier
  • currentTarget : le nœud du DOM qui a déclenché le callback
Couches HTMl et évènements

Application

  • Dans la fonction callback, c'est seul moyen d'avoir :
    • l'élément qui a déclenché le callback : event.currentTarget
    • l'élément qui a reçu l'évènement en premier : event.target
    
    function clicSurElement(event) {
        // event est la seule variable disponible
        // event.currentTarget donne l'élément qui a déclenché la fonction callback
        console.log(event.currentTarget);
        // event.target donne l'élément qui a reçu l'évènement
        // mais pas nécessairement déclenché la fonction callback
        console.log(event.target);
            
Démo

Intervenir sur l'évènement

  • event.preventDefault() : empêcher l'action par défaut de se produire (par ex. activation d'un lien)
  • event.stopPropagation() : arrêter la propagation de l'évènement dans l'arbre (arrêter le bubbling)
  • elt.removeEventListener('click', clicSurElement) pour supprimer un capteur d'évènement sur un élément. Les paramètres doivent être les mêmes que ceux qui ont servi à créer le capteur.
Démo

Séparation structure-forme-interactions

  • Séparer la structure du document et les interactions sur la page
    interdiction d'utiliser des attributs HTML onclick="..." et consorts
  • Un script initialise les évènements à capter sur la page
  • Attention : placer le script en fin de body pour que l'arbre DOM soit bien construit
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <title>Capteur d'évènement</title>
    <!-- inclure le script qui contient les fonctions Javascript -->
    <script src="mesFonctions.js"></script>
</head>
<body>
    <h1>Capteurs d'évènement</h1>
    
    <p id="p1">Attention : mettre le JS à la fin du HTML 
    afin que l'arbre DOM soit bien créé !</p>
    
    <script>
        "use strict";
        // lister les évènements à capter 
        document.getElementById('p1').addEventListener('click', clicSurElement);
    </script>
</body>
</html>        

Structure d'application

  1. Inclure les appels aux scripts externes dans l'en-tête
    Exemple :
        <head>
            <meta charset="UTF-8">
            <title>Capteur d'évènement</title>
            <script src="lib/adress-book.js"></script>
            <script src="lib/person.js"></script>
            <script src="app/init.js"></script>
        </head>        
  2. Créer une fonction qui initialise les interactions de la page
            "use strict";
            
            function initApp() {
                // mettre toutes les interactions à initialiser
                // par ex
                let toto = document.getElementById("toto"); 
                toto.addEventListener("click", displayAddressBook);
                ...
            }    
  3. Appeler la fonction d'initialisation en fin de body
        <body>
            ...
            <script>
            "use strict";
            // appel de la fonction d'initialisation
            initApp();
            </script>
        </body>        

On commence à créer des applications web

  • Javascript pilote les interactions
  • Initialiser les évènements sur la page après son chargement
  • Gestion des évènements : ajout, suppression, propagation
  • Actions gérées par des fonctions callback
  • Possibilités quasi infinies