Topic outline

  • Pré-requis et introduction

    Bienvenue dans le cours concernant la programmation événementielle en JavaScript.

    Mais que se passe-t-il ? Il doit y avoir un événement ce soir !



    Avant de débuter, vous devez déjà maitriser quelques notions :

    • les bases de JS, et surtout les fonctions
    • manipuler un minimum le DOM et le BOM


    Voici quelques liens utiles présentant la programmation événementielle :


    C'est parti !

    • Présentation

      En JavaScript, la programmation événementielle est un concept très important. En effet, c'est la principale interface entre les actions effectuées par l'utilisateur humain et votre application. Les événements sont un peu les "sens" de votre programme. Par exemple, un humain peut voir, sentir, gouter, entendre et toucher. Pour un programme, les "capteurs" sont principalement la souris et le clavier. Cela va permettre à votre programme de détecter un changement de son environnement, et de réagir d'une manière que vous aurez anticipée.


      Interactions avec "le monde extérieur"
      Version humain Version logiciel


      Nous verrons qu'il y a différents types d'événements. Certains sont déclenchés par une action utilisateur, et d'autres sont déclenchés par l'environnement d'exécution de JavaScript.

      Exemples :
      • le navigateur peut émettre l'événement "chargement de la page web terminé"
      • le clavier peut émettre l'événement "touche Echap pressée"

      Dans cette image, l'émetteur est l'environnement d'exécution de JS (navigateur, moteur JS, etc...), et le récepteur, c'est votre application.





      La boucle des événements

      Afin d'écouter les différents événements déclenchés, il existe une boucle infinie qui tourne dans le moteur de JavaScript, et qui "attrape" tout événement déclenché (fired ou trigged en anglais) afin de les envoyer à votre application. Ce n'est pas à vous de coder cette boucle bien sur, mais il est bon de savoir comment cela fonctionne, au moins en théorie.

      Note : cette notion sera vraiment centrale pour ceux qui approfondiront NodeJS. En effet NodeJS est basé sur ce mode de fonctionnement, mais pour tous les aspects de votre programme. Les requêtes HTTP sont gérées comme des événements afin de créer un serveur web qui fonctionne de manière asynchrone, et non-bloquante. Mais vous verrez ça plus tard.


      • Événements et attributs de balises HTML

        Cette méthode permet d'écouter un type d'événement sur une balise HTML en utilisant un attribut dédié. On écrira alors le code JS directement dans la valeur de l'attribut. 

        Pour l'exemple, voici un simple événement clic sur un bouton, tout ce qu'il y a de plus classique :

        <button onclick="alert('Vous venez de me cliquer');">Cliquez-moi !</button>

        Cette technique, bien que dépréciée, permet de découvrir le fonctionnement basique de la gestion des événements. On peut déterminer plusieurs informations de cette simple ligne de code :

        1. l'événement est "branché" sur une balise HTML. En d'autres termes : un élément du DOM.
        2. l'écoute de l'événement se fait via deux mot-clé hyper important : on et click. Le "on" spécifie le déclenchement d'un événement, tandis que le click spécifie la nature de l'événement. 
        3. l'apparition de l'événement déclenche l'exécution d'une instruction. Ici l'apparition de la boite de dialogue.


        On pourrai donc traduire ce code par : quand l'événement clic se produit sur mon bouton, alors exécute les instructions associées.


        Donc pour résumer, lorsque l'on souhaite écouter un événement, il faut spécifier une cible, un type d'événement, et un bloc d'instruction.


        Note : comme je vous l'ai dit, cette approche est dépréciée, et ce pour de multiples raisons. La première est que vous mélangez du HTML et du JS, ce qui n'est pas une très bonne idée car cela complique la lecture et la compréhension du code, et tend à le rendre moins maintenable (anti-pattern plat de spaghetti). Ce qui marche pour une ligne de code n'est pas forcément bon pour un programme entier...


        En revanche : il est bon de voir cette méthode pour deux raisons. La première est que vous pouvez encore croiser cette syntaxe sur Internet, ou pire, dans un de vos futurs projets pros. Il vous faudra donc comprendre ce que c'est. La deuxième, et non des moindres, c'est que certains frameworks ont réintégré cette approche, mais avec du code qui n'est pas "vraiment" du HTML. Nous verrons plus tard que les frameworks modernes ont une syntaxe assez proche de ce que nous venons de voir, mais avec une mécanique très différente. Donc habituez-vous à être à l'aise avec toutes les syntaxes, afin de ne jamais être désappointé.

        • Événements et méthodes du DOM

          Une approche un peu plus "moderne" consiste à utiliser les méthodes natives des éléments du DOM pour exécuter une fonction contenant le bloc d'instruction à exécuter. Le JS sera complètement extrait du HTML, et on va enfin pouvoir écrire du code sans mélanger HTML et Javascript :

          <button id="testEvent">Cliquez-moi !</button>
          <script>
          let monBouton = document.getElementById('testEvent'); /* Ciblage de l'élément */
          monBouton.onclick = afficheMessage; /* Utilisation de la méthode onclick sur l'élément, qui va appeler une fonction */
          function afficheMessage(){ /*Définition de la fonction contenant notre bloc d'instructions */
          alert('Vous venez de me cliquer');
          }
          </script>

          Cet extrait de code fait exactement la même chose que l'exemple précédent, mais on a une structuration plus propre, et un cloisonnement HTML/JS plus qu'apprécié. En revanche, on se retrouve obligé de créer une fonction pour notre simple alert. Ce qui rallonge le code inutilement, car on va devoir écrire une fonction spécifique à une seule action. Hors on a vu que les fonctions étaient utiles quand un code était dupliqué à plusieurs reprises. Ce vice de conception va me permettre de vous montrer une notion importante en programmation événementielle : les fonctions anonymes.


          Voici le même exemple utilisant une écriture plus compacte :

          <button id="testEvent">Cliquez moi !</button>
          <script>
          document.getElementById('testEvent').onclick = function(){ /* Le déclenchement de l'évenment appel une fonction directement associée, donc pas besoin de l'identifier */
          alert('Vous venez de me cliquer'); /* Et hop ! */
          }
          </script>

          Avec cet exemple, vous pouvez constater que :

          • le code est beaucoup plus court (pas de variable, pas de nommage de fonction)
          • le ciblage, l'événement et les instructions sont gérés en un seul "morceau", ce qui rend le code plus digeste.
          • Méthode spécialisée : le gestionnaire d’événements

            La dernière méthode que nous allons voir pour gérer les événements et celle que vous devez retenir et utiliser en priorité. Elle consiste à passer par une méthode spécialisée dans la gestion des événements : c'est ce que l'on appelle un gestionnaire d'événements. Cette méthode s'applique sur n'importe quel élément du DOM ou du BOM, et permet une gestion plus fine de vos événements. 


            La méthode addEventListener()

            Comme nous venons de le voir, la méthode addEventListener() se définit sur un élément ciblé préalablement. On n'aura donc pas à utiliser le préfixe on, car cette méthode est déjà spécialisée dans la gestion des événements. On va donc pouvoir déterminer le type d'événement "directement" (onclick deviendra click), ce qui permet de raccourcir le code est de le rendre plus clair.

            Cette méthode prends 3 paramètres :

            1. le type d'événement (souris, clavier, etc...)
            2. la fonction à exécuter quand l'événement est déclenché (anonyme, ou pas)
            3. la gestion de la propagation de l'événement (moins utilisé, on verra ça un peu plus tard)


            Voici un exemple d'utilisation simple :

            <button id="testEvent">Cliquez moi !</button>
            <script>
            document.getElementById('testEvent').addEventListener('click', function(){
            alert('Vous venez de me cliquer');
            });
            </script>

            Pour l'instant, c'est tout ce qu'il y a à savoir sur les différents types de gestion des événements. Les trois approches fonctionnent à peu près toutes de la même manière, mais vous devez privilégier la méthode addEventListener().


            Voici un petit schéma récapitulatif :

            Important : la fonction qui est exécutée lors du déclenchement de l'événement est une fonction de rappel (callback en anglais). Vous croiserez ce terme très souvent par la suite. Un callback est une fonction qui est passé en paramètre d'une autre fonction. La fonction passée en paramètre sera alors exécutée par la fonction principale dans certains cas uniquement. Ici, ce sera lors du déclenchement d'un événement. Voici une page sur les fonctions de rappel sur le MDN.

            Voici la page du MDN pour la méthode addEventListener().



            La méthode removeEventListener()

            Il se peut dans certains cas que vous souhaitiez retirer l'écoute d'un événement préalablement créé. Pour cela vous pourrez utiliser la méthode removeEventListener(). Cela fonctionne de la même manière que addEventListener(), et aura pour effet de "débrancher" l'écoute d'un évènement sur un élément particulier. 

            Note : la méthode removeEventListener() nécessite l'utilisation de fonction non-anonymes.


            <button id="testEvent">Cliquez moi !</button>
            <script>
            document.getElementById('testEvent').addEventListener('click', afficheMessage); /* On branche l'écouteur */

            function afficheMessage(){
            alert('Vous venez de me cliquer');
            document.getElementById('testEvent').removeEventListener('click', afficheMessage); /* On débranche l'écouteur */
            }
            </script>
            Dans cet exemple, la fonction afficheMessage() ne sera exécutée que lors du premier clic, car elle contient une instruction qui débranche l'écouteur d'événement du bouton, et sa fonction associée.
            • Objet Event

              L'objet Event est automatiquement passé à votre callback en premier paramètre. C'est un objet émis par le navigateur, qui contient tous les détails techniques concernant l'évènement qui vient de se produire.


              Voici notre objet event, il vous donne accès à toutes les informations concernant un événement.



              Propriétés

              Voici quelques exemples de propriétés intéressantes de l'objet Event :

              • coordonnées X/Y de l'endroit ou a été émis l'événement (lors d'un clic par exemple)
              • timestamp : l'heure à laquelle l'évènement a été déclenché
              • target : référence à l'objet qui a envoyé l'événement
              • trusted : indique si l'événement est émis par le navigateur, ou bien par votre propre code (utilisée pour empêcher les abus, tel que les popups abusives qui s'ouvrent de manière programmatique par exemple par exemple)
              • etc...


              Pour visualiser le contenu de l'objet  event envoyé à votre callback, vous pouvez copier ce code :

              <button id="testEvent">Cliquez moi !</button>
              <script>
              document.getElementById('testEvent').addEventListener('click', function(e){ /* Ici la lettre n'a aucune importance, c'est une convention pour event */
              console.log(e);
              });
              </script>

              Et donc, lorsque vous cliquerez sur le bouton, vous obtiendrez quelque chose comme ceci dans la console (avec Chrome) :

              On voit clairement toutes les informations caractérisant l'événement.


              Ces informations pourront vous être utiles dans certains cas, mais cela reste assez rare d'en avoir besoin en JS front-end. En revanche, cet objet vous permet de bien cerner le fonctionnement des événements, ce qui est toujours bon à prendre ! Voici la liste complètes des propriétés de l'objet Event.


              A finir :


              Exemple pour clic droit ou clic molette : https://www.geeksforgeeks.org/javascript-mouseevent-button-property/

              Lien vers la doc


              Méthodes


              preventdefault : https://developer.mozilla.org/fr/docs/Web/API/Event/preventDefault

              stopPropagation : https://developer.mozilla.org/fr/docs/Web/API/Event/stopPropagation

              • Événements souris

                Un des types d'événements les plus courant sera le clic souris, comme nous l'avons déjà vue. Mais la souris peut émettre d'autres types d'événements, en voici un récapitulatif :

                • click : cliquer (appuyer puis relâcher) sur l'élément
                • dblclick : double-cliquer sur l'élément
                • mouseover : faire entrer le curseur sur l'élément
                • mouseout : faire sortir le curseur de l'élément
                • mousedown : appuyer (sans relâcher) sur le bouton gauche de la souris sur l'élément
                • mouseup : relâcher le bouton gauche de la souris sur l'élément
                • mousemove : faire déplacer le curseur sur l'élément

                Souvent, un événement et composé de plusieurs sous-événements. Par exemple, le clic, c'est un mousedown suivi d'un mouseup. Ceci est extrêmement logique. Voici une illustration des différentes phases composant un click et un dblclick :


                Décomposition d’événements "composites"

                Voici un lien vers la documentation officielle sur les événements liés à la souris. Vous trouverez aussi un lien vers ce qui concerne les événements liés à la molette (wheel en anglais).

                Note : pour le clic droit, nous verrons ça plus tard avec l'objet Event. L'utilisation des autres boutons que celui du clic gauche reste assez marginale en développement web.

              • Événements clavier

                Bien que moins répandue que la souris en développement web, l'utilisation du clavier est désormais incontournable. Certains comportements sont acquis par les utilisateurs, tels que :
                • appuyer sur la touche Echap pour fermer une fenêtre modale
                • réagir en temps réel à une saisie utilisateur
                • etc..


                Vous aurez donc du mal à vous en passer. Nous allons voir que les événements du clavier sont un peu plus complexes que ceux de la souris. Il y a de nombreuses possibilités (toutes les touches du clavier, en gros), et la normalisation de cet aspect n'est pas aussi simple que celui de la souris.

                Note : vous verrez plus tard que l'on code désormais de moins en moins en vanillaJS, mais cela peut encore s'avérer nécessaire. L'utilisation de bibliothèque ou framework (type JQuery ou VueJS) vous simplifierons grandement la tâche, mais il est bon de connaître la mécanique interne de JS avant d'utiliser ce genre d'outils.

                Les types d'événements du clavier sont assez simple, vous allez en retrouver seulement trois :
                • keydow : une touche est "enfoncée"
                • keyup : une touche est "relâchée"
                • keypress : une touche est "pressée" (enfoncée puis relâchée)


                Attention : l'événement keypress est déprécié, utilisez plutôt keyup à la place.


                On a donc la même logique que pour la souris :


                Voici la documentation officielle sur les événements du clavier.


                Comment savoir quelle touche a été pressée par l'utilisateur ?

                Là où ça se corse un petit peu, c'est quand on va vouloir connaitre quelle touche a été pressée par l'utilisateur. Pour cela, on va devoir utiliser les propriétés de l'objet Event.


                Plusieurs propriétés peuvent vous permettre de connaitre la touche qui a été pressée. Certaines touches (telles que les lettres par exemple) sont faciles à identifier, tandis que d'autres touches plus "particulières" risque de vous générer quelques bugs d'inter compatibilité entre navigateurs. 


                Voici les propriétés de l'objet Event qui permettent de connaitre la touche pressée par l'utilisateur :

                • keyCode : renvoie le code Unicode de la touche qui a déclenché l'événement (ex : la touche / renverra le code 191).
                • key : renvoie le nom des touches (enter, shift, 0, 1, a, b,....)
                • charCode Renvoie le code Unicode de la touche qui a déclenché l'événement keypress.
                • code : renvoie le nom des touches (Enter, Shift, Digit0, Digit1, KeyA, KeyB,...)
                • which : renvoie charCode dans l'événement keypress, ou keyCode dans l'événement keydown, keyup.


                Comme vous pouvez le constater, les différences sont.... subtiles. À vous de trouver la solution la plus adaptée à votre problème et à votre environnement. En revanche, le MDN préconise l'utilisation de key.


                Les codes Unicode :



                Voici un exemple avec la touche Echap, pour fermer une fenêtre modale :

                <meta charset="UTF-8" />
                <style>
                #modal{
                border:solid 1px black;
                margin:25px auto;
                width:400px;
                background-color: #ddd;
                text-align: justify;
                padding:10px;
                }
                </style>
                <div id="modal">
                <h3>Ceci est une fenêtre modale</h3>
                <p>Elle doit disparaître lorsque l'utilisateur appuie sur la touche Echap</p>
                <hr />
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus beatae accusamus animi quidem vero. Nihil enim, quia exercitationem placeat obcaecati amet qui nulla non, quam ad maiores odio facere voluptas!</p>
                </div>
                <script>
                document.body.addEventListener('keyup', function(e){ /* L'événement est rattaché au body */
                if(e.key == 'Escape'){ /* On vérifie la valeur de la propriété key de l'objet event */
                document.getElementById('modal').style.display = 'none'; /* Et on exécute ce que l'on veut */
                }
                });
                </script>


                On aurait aussi pu utiliser la propriété keyCode :

                if(e.keyCode == 27){
                document.getElementById('modal').style.display = 'none';
                }

                Important : voici un lien intéressant pour connaitre les autres valeur des codes des touches du clavier : https://keycode.info/

              • Formulaire

                Comme vous le savez, les formulaires sont un élément clé de vos pages web. Ils représentent quasiment les seuls "input" dont vos utilisateurs disposent pour interagir avec votre serveur. De ce fait, ils ont un fonctionnement assez poussé, et disposent d'événements particuliers. Nous allons en voir quelques-uns.


                Focus et blur

                Le focus est un événement qui se déclenche quand un utilisateur vient de cliquer dans une balise input, avant de commencer sa saisie. Cela peut être utile pour différentes choses, comme par exemple mettre un élément en surbrillance, ou afficher une information. Le blur est l'inverse, c'est l'événement qui est déclenché lorsque qu'un élément perd le focus.


                Voici un exemple :

                <meta charset="UTF-8" />
                <input type="text" id="testFocus" /><span style="display:none;"> Attention à l'ortographe !</span>
                <script>
                let span = document.querySelector('span');

                document.getElementById('testFocus').addEventListener('focus', function(){
                console.log(`L'utilisateur vient de mettre le focus sur le champ texte`)
                span.style.display = 'inline';
                })
                document.getElementById('testFocus').addEventListener('blur', function(){
                console.log(`L'utilisateur vient de quitter le champ texte`);
                span.style.display = 'none';
                })
                </script>

                Vous pouvez aussi utiliser focusin et focusout qui sont sensiblement les mêmes. Il est possible de faire la même chose en CSS avec la pseudo-classe :focus, mais dans ce cas vous serez limités à des modifications de style (voir un exemple). 

                Note : il y a aussi la méthode .focus(), qui n'a rien à voir avec les événements, mais qui donne le focus à un élément de manière programmatique. Pratique lorsque vous voulez éviter à l'utilisateur de devoir cliquer dans un champ de texte avant de commencer à écrire. Ne confondez pas les deux ;)


                Change
                L'événement change est spécialisé pour les liste déroulantes select. Cet événement est déclenché lorsque l'utilisateur change l'option sélectionnée dans la liste des options disponibles :

                <select>
                <option>Abricot</option>
                <option>Banane</option>
                <option>Cerise</option>
                <option>Datte</option>
                </select>
                <br />
                Vous avez choisi : <span></span>
                <script>
                let select = document.querySelector('select');
                let span = document.querySelector('span');

                select.addEventListener('change', function(){
                span.innerHTML = select.value;
                })
                </script>

                Tout simplement ! 

                Malgré sa simplicité, cet événement est très utile car le click serait trop ambiguë à gérer.
                L'événement change peut aussi être utilisé sur d'autres éléments. Par exemple sur les input de type range.

                Submit
                L'événement submit est déclenché lorsque l'utilisateur soumet un formulaire. Il est donc rattaché à la balise form. Cet événement est très utilisé dans la validation de formulaire. C'est à dire que l'on va faire un contrôle de saisie utilisateur côté client avant d'envoyer les données vers le serveur (double vérification afin d'éviter trop d'aller/retour client/serveur, et d'envoyer n'importe quoi au backend). Pour empêcher la soumission automatique du formulaire, on utilisera la méthode preventDefault() de l'objet Event. Ce qui aura pour conséquences de stopper le fonctionnement normal de l'événement submit, afin de pouvoir exécuter les contrôles de saisie avant la soumission automatique. Si tous les champs ont été remplis correctement par l'utilisateur, on pourra alors soumette le formulaire de manière programmatique, avec l'utilisation de la méthode submit() sur l'élément form.

                <form id="formTest" action="https://webboy.fr">
                <input type="text" id="champTexte" />
                <input type="submit" value="Soumettre le formulaire" />
                </form>
                <script>
                let form = document.getElementById('formTest');
                let champTexte = document.getElementById('champTexte');

                form.addEventListener('submit', function (e) {
                e.preventDefault();
                value = champTexte.value;

                if (value == '') {
                console.error('Vous devez saisir une valeur')
                } else {
                form.submit();
                }
                })
                </script>

                Note : cette approche à tendance à disparaitre, surtout avec les frameworks modernes et le fonctionnement en API. Le bouton de soumission (qui est en réalité un bouton "classique") exécutera un simple script, qui va réaliser les actions suivantes :
                1. contrôle de saisie des input
                2. construction d'un objet JSON
                3. envoie de l'objet JSON à une API


                Il n'y aura donc pas de soumission classique, effectuée par le navigateur web. Votre script émettra une requête HTTP, via la programmation asynchrone. On reparlera de tout ça plus tard, mais ne vous étonnez pas si vous ne croisez pas souvent l'utilisation de l'événement submit dans des codes récents.

              • Chargement du DOM et des ressources externes

                C'est un des événements les plus importants, car lorsque l'on souhaite travailler avec le DOM en JavaScript, il faut attendre que celui-ci soit entièrement chargé dans le navigateur. Cela peut prendre un certains temps, en fonction du contenu de la page web, et de la qualité de votre connexion. On va donc conditionner l'exécution d'un script au fait que le document soit entièrement chargé.

                Voici les différentes phases de chargement et de rendu lorsque l'on souhaite afficher une page web :



                Il existe des nuances selon les événements, mais voici les deux principaux :

                1. DOMContentLoaded : est émis lorsque le document racine est bien chargé (cqfd : la page HTML principale)
                2. load : est émis lorsque toutes les ressources externes à la page HTML sont chargées (fichiers JS, CSS, images, etc...)


                DOMContentLodaded sera rattaché à l'objet document (DOM), tandis que load sera rattaché à l'objet window (BOM).


                Différence entre les événements DOMContentLoaded et load :



                Voici un exemple concret de l'utilisation de ce genre d'événements. Cette page HTML charge volontairement des images lourdes afin de générer un temps de chargement relativement long.


                <!-- La balise de script est placé volontairement AVANT le reste de la page -->
                <script>

                /* Script exécuté AVANT que le DOM soit prêt */
                displayInfos(`le DOM et les ressources ne sont pas prêts, JavaScript ne peut pas manipuler correctement le DOM`);


                /* Script exécuté APRES que le DOM soit prêt */
                document.addEventListener('DOMContentLoaded', function () {
                displayInfos(`le DOM est chargé, mais les fichiers externes n'ont pas forcément fini de télécharger`);
                })

                /* Script exécuté une fois que TOUTES LES RESSOURCES sont prêtes */
                window.addEventListener('load', function () {
                displayInfos(`tous les fichiers externes sont chargés`);
                })

                function displayInfos(m) {
                let date = new Date();
                let imgs = document.querySelectorAll('img'); /* Ces lignes de code dépendent du chargement du DOM */
                let paragraphes = document.querySelectorAll('p'); /* Ces lignes de code dépendent du chargement du DOM */
                console.error(`${date} (${date.getMilliseconds()}ms) : ${m}`);
                console.log(imgs);
                console.log(paragraphes);
                }

                </script>
                <meta charset="UTF-8">
                <img src="https://www.la-poze-travel.com/wp-content/uploads/2019/10/calo-des-moro-majorque-6-min.jpg" />
                <img
                src="https://www.acs-ami.com/fr/blog/wp-content/uploads/2013/09/quelques-idees-reussir-voyage-famille-destinations-lointaines.png" />
                <img src="https://www.voyage-prive.com/s/images/visual/login/backgrounds/2048x1463-seychelles.jpg" />
                <img src="https://www.mexique-voyages.com/wp-content/uploads/voyage-mexique-agence-terra-maya-e1578696459556.jpg" />
                <img
                src="https://i1.wp.com/onholidaysagain.com/wp-content/uploads/2019/09/Pr%C3%A9parer-son-voyage-aux-Maldives.jpg?fit=1170%2C783&ssl=1" />
                <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Maxime incidunt labore, accusamus, ad doloribus, explicabo
                illo aspernatur quae possimus id ducimus officiis sapiente non eaque voluptates iste vero delectus? Maxime.</p>
                <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Maxime incidunt labore, accusamus, ad doloribus, explicabo
                illo aspernatur quae possimus id ducimus officiis sapiente non eaque voluptates iste vero delectus? Maxime.</p>


                Donc faites attention, si vous souhaitez exécuter un script qui ne travaille que sur le DOM de la page HTML, utilisez plutôt DOMContentLoaded, et si vous avez besoin de travailler avec toutes les ressources (ce qui est plus long), privilégiez load

                Vous pouvez retrouver ces informations dans l'onglet réseau de la console :



                Important : dans tous les cas, pensez bien à attendre le téléchargement des ressources nécessaires avant de lancer l'exécution de vos scripts, sinon, ils ne trouveront pas les éléments de votre page web. C'est une notion vraiment cruciale. Vous allez vous faire avoir plus d'une fois, donc pensez-y !
              • Scroll

                L'événement scroll est assez utilisé pour en parler un peu. C'est un événement qui est émit par le navigateur lorsque l'utilisateur est en train de scroller (descendre ou monter) dans la fenêtre du navigateur. 

                Attention, ce n'est pas un événement émis par la molette de la souris, mais bien par le navigateur


                Voir aussi la méthode scroll : https://developer.mozilla.org/en-US/docs/Web/API/Element/scroll


                Cet événement peut être utilisé par exemple pour :

                • les backtotop (pour pouvoir remonter en haut d'une page en un clic, très utilisé aujourd’hui)
                • les fenêtres modales marketing (celles qui vous demandent de laisser votre email)
                • etc...


                L'événement scroll est souvent utilisé avec des propriétés de mesures de la page, tel que scrollTop par exemple.


                Liens vers la doc :

              • Propagation des événements : capture / bubbling


                Bien qu'assez peu utilisé au quotidien, vous devez bien comprendre la notion de propagation des événements, car cela peut vous jouer des tours dans certains cas - inextricables - si vous n'avez pas compris ce concept. Je vous rassure, cela reste assez rare.


                Les phases de propagation

                Quand un événement est déclenché dans le navigateur, il va se propager dans tout le DOM afin d'être "attrapé" par les éléments qui sont concernés. Si par exemple vous cliquez sur un bouton, l'événement - déclenché par le navigateur - va parcourir toutes les balises, en partant de la balise racine html. C'est la phase descendante, c'est la phase de capture.

                Une fois que l'événement a atteint la balise qui contient le gestionnaire d'événement le plus profond dans le DOM, il va alors remonter vers l'élément racine html. C'est la phase de bubbling (ou bouillonnement).


                La méthode addEventListener est conçue pour déclencher votre fonction de rappel pendant la phase de bouillonnement. C'est le réglage par défaut. Mais vous pouvez changer ce comportement grâce au troisième paramètre de cette dernière :

                addEventListener(event, function, propagation) <-- troisième paramètre ! :)

                Par défaut, propagation vaut false, ce qui veut dire que c'est la phase de bubbling qui sera retenue pour le déclenchement effectif de l'événement. Il vous suffit donc de passer ce paramètre à true si vous souhaitez déclencher l'événement durant la phase de capture.

                Ce concept peut être utile quand vous avez plusieurs éléments qui s'imbriquent, superposés les uns sur les autres, et qu'ils écoutent tous les deux le même événement.


                Dans ce cas-là lequel doit être déclenché en premier ? Par défaut, c'est d'abord la vidéo, et ensuit la div. Mais vous pouvez modifier ce comportement.


                 Je n'ai pas trouvé de cas vraiment concret d'utilisation à vous proposer, mais j'ai déjà croisé ce genre de problématiques dans mon passé, il me semble... 


                Voici un exemple :

                Il suffira de changer le paramètre pour constater l'ordre de déclenchement des événements.

                <meta charset="utf-8" />
                <style>
                ul, li{
                cursor:pointer;
                }
                </style>
                <ul>
                <li>Abricot</li>
                <li>Banane</li>
                <li>Cerise</li>
                <li>Datte</li>
                </ul>
                <script>
                let ul = document.querySelector('ul');
                let lis = document.querySelectorAll('li');

                ul.addEventListener('click', function () {
                console.log('Vous avez cliqué dans la liste');
                this.style.backgroundColor = 'yellow';
                }, true) /* Utilisation de la phase de capture pour être détecté en premier */

                lis.forEach((li) => {
                li.addEventListener('click', function () {
                console.log(`Vous avez choisi ${this.innerHTML}`);
                lis.forEach((li) => li.style = '');
                this.style.backgroundColor = 'green';
                }, false) /* Utilisation de la phase de bubbling, c'est le réglage par défaut */
                });
                </script>


                La méthode stopPropagation()

                On peut aussi stopper la propagation d'un événement de manière programmatique, via l'utilisation de la méthode de l'objet Event : .stopPropagation(). Celle-ci va avoir pour effet de stopper la propagation de l'événement aux éléments du DOM plus profond. Ils ne pourront donc pas réagir au clic. C'est une pratique qui peut s'avérer utile dans certains cas. Mais cela reste assez marginal aussi.

                Voyons ce que ça donne dans notre exemple :

                Remplacez seulement le gestionnaire d'événement du ul.

                ul.addEventListener('click', function (e) {
                console.log('Vous avez cliqué dans la liste');
                this.style.backgroundColor = 'yellow';
                e.stopPropagation(); /* Les points de liste n'attraperont jamais le clic */
                }, true)


                Résumé


                Deux phases :

                1. capture : descente dans le DOM (de HTML vers l'élément qui a un écouteur le plus profond dans le dom)
                2. bubbling (bouillonnement) : remonté vers l'élément racine (balise <html>)


                => Possibilité de changer la phase prise en compte par le gestionnaire d'événement en jouant sur le troisième paramètre (qui est un booléen).


                Une méthode stopPropagation() pour stopper la propagation d'un événement à l'intérieur du DOM.