Cours JavaScript et TypeScript · Module 8: Événements et DOM

Synthèse - Les événements en JavaScript

4 min de lecture

Tout comme tous les systèmes de Jurassic Park doivent coopérer entre eux, les événements en JavaScript relient les différentes parties d'une application en un tout cohérent et interactif.

« Avant de te confier les clés du centre de contrôle, faisons une dernière ronde », dit Ray Arnold. Tout au long de ce module, tu as appris à brancher des capteurs, à lire leurs rapports et à faire le ménage derrière eux. Mais un savoir dispersé sur plus d'une dizaine de leçons s'estompe facilement, alors rassemblons-le en un seul endroit et vérifions que toutes les pièces s'emboîtent.

Concepts clés

Les événements sont une partie fondamentale de la création d'applications web interactives. Nous avons découvert :

  1. Les bases des gestionnaires d'événements - comment écouter les actions de l'utilisateur
  2. L'objet Event - comment obtenir des informations détaillées sur les événements
  3. La propagation des événements - comment les événements "bouillonnent" à travers le DOM
  4. La délégation d'événements - la gestion efficace de nombreux éléments
  5. Les différents types d'événements - souris, clavier, formulaires
  6. La gestion de la mémoire - la suppression des écouteurs d'événements
  7. L'optimisation des performances - throttling, debouncing
  8. Les Custom Events - la création de ses propres événements
  9. Les techniques avancées - gestes tactiles, event bus
  10. Les tests - comment tester le code lié aux événements

Le trajet d'un événement dans le DOM

Un événement du DOM passe par trois phases. D'abord le capturing, c'est-à-dire la capture qui descend de window jusqu'à la cible, puis la phase de cible, et enfin le bubbling, c'est-à-dire le bouillonnement qui remonte. Les événements qui ne bouillonnent pas, comme mouseenter ou focus, terminent leur voyage sur la cible. Voici une courte expérience qui montre cet ordre :

1const sector = document.getElementById('sector-b');
2const gate = document.getElementById('gate-b6');
3
4sector.addEventListener('click', () => console.log('1. Secteur (capturing)'), { capture: true });
5gate.addEventListener('click', () => console.log('2. Portail (target)'));
6sector.addEventListener('click', () => console.log('3. Secteur (bubbling)'));

Un clic sur le portail, qui se trouve à l'intérieur du secteur, affichera les messages dans l'ordre 1, 2, 3. Le même élément sector entend donc l'événement deux fois, une fois en descendant et une fois en remontant. L'appel à stopPropagation() interrompt ce voyage à n'importe quel moment.

Un seul capteur au lieu de cent

La technique la plus importante du module est la délégation : un seul écouteur sur le parent gère les événements de tous les éléments descendants, y compris ceux qu'on ajoute plus tard.

1gallery.addEventListener('click', (e) => {
2  const card = e.target.closest('.dinosaur-card');
3  if (card) showDinosaurDetails(card.dataset.dinoId);
4});

Ça fonctionne grâce au bouillonnement : un clic sur n'importe quel élément de la carte arrive jusqu'à la galerie, et closest() retrouve la carte à laquelle il appartient. Ne confonds pas la délégation avec le bubbling lui-même. Le bubbling est un mécanisme du navigateur, et la délégation, une technique qui en tire parti.

Des options à garder sous la main

Le troisième argument de la méthode addEventListener() est un objet d'options. Trois d'entre elles sont revenues tout au long du module :

1button.addEventListener('click', handler, { once: true });
2window.addEventListener('touchmove', trackFinger, { passive: true });
3panel.addEventListener('keydown', onKey, { signal: controller.signal });

L'option once crée un écouteur à usage unique, que le navigateur supprime après le premier appel. L'option passive promet que l'écouteur n'appellera pas preventDefault(), donc le défilement n'a pas besoin de l'attendre. L'option signal lie l'écouteur à un AbortController, si bien qu'un seul abort() retire tout un groupe de capteurs.

Applications pratiques

Dans les applications réelles, les événements permettent :

  • Des interfaces utilisateur interactives
  • La validation des formulaires en temps réel
  • La communication entre composants
  • L'optimisation des performances
  • La création d'applications accessibles à tous les utilisateurs

Checklist avant chaque nouvel écouteur

Mon conseil : avant d'écrire addEventListener(), réponds à quatre questions. Quel événement attends-tu vraiment ? Où placer l'écouteur, sur l'élément ou sur son parent ? Comment et quand vas-tu le supprimer ? L'événement se déclenche-t-il si souvent qu'il a besoin de throttling ou de l'option passive ? Ces quatre questions éliminent la plupart des erreurs que tu as rencontrées dans ce module.

Dans le bac à sable ci-dessous, tu testeras en direct un clic, un événement personnalisé et la délégation. Dans les prochaines leçons, nous reviendrons aux Custom Events et à la méthode dispatchEvent(), tu découvriras les API DOM avancées avec les observateurs, et pour finir, tu construiras le projet final : un panneau de contrôle interactif du parc.

Souviens-toi : tout comme Ray Arnold surveille tous les systèmes de Jurassic Park, tu dois gérer les événements avec sagesse dans tes applications !

Code de cette leçon : index.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <title>Synthèse - Les événements en JavaScript</title>
6    <style>
7        body { font-family: Arial, sans-serif; background: linear-gradient(135deg, #2c3e50, #34495e); color: white; padding: 20px; }
8        .summary-box { background: rgba(0,0,0,0.7); padding: 30px; border-radius: 15px; margin: 20px 0; }
9        h1 { text-align: center; color: #3498db; }
10        h2 { color: #3498db; margin-top: 30px; }
11        .concept-list { list-style: none; padding: 0; }
12        .concept-list li { background: rgba(52, 152, 219, 0.1); padding: 15px; margin: 10px 0; border-left: 4px solid #3498db; border-radius: 6px; }
13        .code-example { background: #000; padding: 15px; border-radius: 8px; font-family: monospace; font-size: 14px; margin: 10px 0; overflow-x: auto; }
14        .highlight { color: #f39c12; font-weight: bold; }
15        .demo-btn { padding: 12px 24px; background: #27ae60; color: white; border: none; border-radius: 6px; cursor: pointer; margin: 10px 5px; font-size: 16px; }
16        .demo-btn:hover { background: #2ecc71; }
17        #interactive-demo { background: rgba(46, 204, 113, 0.1); padding: 20px; border-radius: 10px; text-align: center; margin: 20px 0; }
18    </style>
19</head>
20<body>
21    <div class="summary-box">
22        <h1>Les événements en JavaScript - Synthèse</h1>
23
24        <p style="font-size: 18px; text-align: center; color: #bdc3c7;">
25            Just as all systems in Jurassic Park must work together,
26            events in JavaScript connect different parts of an application into a cohesive, interactive whole.
27        </p>
28
29        <h2>Concepts clés</h2>
30        <ul class="concept-list">
31            <li><strong>Event Listeners</strong> - Listening for user actions (<code>addEventListener</code>)</li>
32            <li><strong>Event Object</strong> - Informations détaillées sur l'événement (target, type, coordinates)</li>
33            <li><strong>Event Propagation</strong> - Bubbling et capturing dans l'arbre DOM</li>
34            <li><strong>Event Delegation</strong> - Gestion efficace de nombreux éléments</li>
35            <li><strong>Mouse & Keyboard Events</strong> - Handling different types of interaction</li>
36            <li><strong>Form Events</strong> - Submit, input, change, focus/blur</li>
37            <li><strong>Throttling & Debouncing</strong> - Performance optimization</li>
38            <li><strong>Custom Events</strong> - Creating custom events</li>
39            <li><strong>Touch Gestures</strong> - Handling mobile devices</li>
40            <li><strong>Performance</strong> - Passive listeners, Intersection Observer</li>
41        </ul>
42
43        <h2>Exemples pratiques</h2>
44
45        <div class="code-example">
46// Podstawowy event listener
47button.addEventListener('click', function(e) {
48    console.log('Clicked!', e.target);
49});
50
51// Event delegation
52container.addEventListener('click', (e) => {
53    if (e.target.matches('.dino-btn')) {
54        handleDinoClick(e.target.dataset.dino);
55    }
56});
57
58// Debouncing pour search
59const debouncedSearch = debounce((query) => {
60    searchDinosaurs(query);
61}, 300);
62input.addEventListener('input', (e) => {
63    debouncedSearch(e.target.value);
64});
65
66// Custom Event
67const event = new CustomEvent('parkAlert', {
68    detail: { type: 'security', message: 'Alert!' }
69});
70document.dispatchEvent(event);
71        </div>
72
73        <h2>Applications dans les applications réelles</h2>
74        <ul class="concept-list">
75            <li>Interactive user interfaces</li>
76            <li>Validation de formulaires en temps réel</li>
77            <li>Communication between components</li>
78            <li>Performance optimization (scroll, resize)</li>
79            <li>Creating accessible applications (keyboard navigation)</li>
80            <li>Intégration avec des frameworks (React, Vue, Angular)</li>
81        </ul>
82
83        <div id="interactive-demo">
84            <h3>Démonstration interactive</h3>
85            <p>Teste tous les concepts appris :</p>
86            <button class="demo-btn" onclick="demoClick()">Événement click</button>
87            <button class="demo-btn" onclick="demoCustom()">Custom Event</button>
88            <button class="demo-btn" onclick="demoDelegation()">Délégation</button>
89            <div id="demo-output" style="margin-top: 20px; font-family: monospace; color: #3498db;"></div>
90        </div>
91
92        <h2>Étapes suivantes</h2>
93        <ul class="concept-list">
94            <li>Pratique l'event delegation dans tes projets</li>
95            <li>Implement throttling/debouncing for better performance</li>
96            <li>Experiment with custom events for inter-module communication</li>
97            <li>Test event handlers using testing frameworks</li>
98            <li>Learn patterns from popular libraries (RxJS, Redux)</li>
99        </ul>
100
101        <div style="background: rgba(46, 204, 113, 0.1); padding: 20px; border-radius: 10px; margin-top: 30px; text-align: center;">
102            <h3>Félicitations !</h3>
103            <p style="font-size: 18px;">
104                Tu connais maintenant les principales techniques de gestion des événements en JavaScript : tu peux créer
105                des applications web entièrement interactives !
106            </p>
107            <p style="color: #bdc3c7;">
108                Remember: just as Ray Arnold monitors all Jurassic Park systems,
109                you must wisely manage events in your applications!
110            </p>
111            <div style="font-size: 48px; margin: 20px 0;">◆</div>
112        </div>
113    </div>
114
115    <script>
116        console.log('Parc Jurassique - Les événements en JavaScript - Synthèse');
117
118        let demoCount = 0;
119
120        function demoClick() {
121            demoCount++;
122            showDemo(`Click Event #${demoCount} - addEventListener works!\nBasic user interaction`);
123            console.log('Click event triggered');
124        }
125
126        function demoCustom() {
127            const customEvent = new CustomEvent('dinoEvent', {
128                detail: { dinosaur: 'T-Rex', action: 'roar' }
129            });
130
131            document.addEventListener('dinoEvent', (e) => {
132                showDemo(`Custom Event emitted!\n${e.detail.dinosaur} says ${e.detail.action}\nCommunication between components`);
133            }, { once: true });
134
135            document.dispatchEvent(customEvent);
136            console.log('Custom event dispatched');
137        }
138
139        function demoDelegation() {
140            showDemo(`Event Delegation active!\nOne listener for many elements\nBetter performance`);
141            console.log('Event delegation demonstrated');
142        }
143
144        function showDemo(message) {
145            const output = document.getElementById('demo-output');
146            output.textContent = message;
147            output.style.animation = 'none';
148            setTimeout(() => {
149                output.style.animation = 'fadeIn 0.5s ease';
150            }, 10);
151        }
152
153        // Démonstration throttle/debounce
154        function throttle(func, limit) {
155            let inThrottle;
156            return function(...args) {
157                if (!inThrottle) {
158                    func.apply(this, args);
159                    inThrottle = true;
160                    setTimeout(() => inThrottle = false, limit);
161                }
162            };
163        }
164
165        // Log du scroll (throttled)
166        const throttledScroll = throttle(() => {
167            console.log('Scroll position:', window.scrollY);
168        }, 500);
169
170        window.addEventListener('scroll', throttledScroll, { passive: true });
171
172        console.log('All JavaScript event concepts practiced!');
173        console.log('Système prêt pour la production');
174        console.log('Pour aller plus loin : Frameworks (React, Vue), Patterns (Observer, PubSub)');
175    </script>
176
177    <style>
178        @keyframes fadeIn {
179            from { opacity: 0; transform: translateY(-10px); }
180            to { opacity: 1; transform: translateY(0); }
181        }
182    </style>
183</body>
184</html>

Tu as repéré une erreur dans cette leçon ?

Teste tes connaissances

Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.

  1. 1. Quelle technique permet de gérer les événements de nombreux éléments enfants avec un seul écouteur sur le parent ?

Tâches pratiques dans le jeu

  • Clique dans l'ordre

    Place les phases de propagation des événements dans le DOM dans le bon ordre :

  • Tri horizontal

    Place les fragments de code pour ajouter un écouteur d'événement à usage unique :

Articles utiles