Cours JavaScript et TypeScript · Module 8: Événements et DOM
Synthèse - Les événements en JavaScript
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 :
- Les bases des gestionnaires d'événements - comment écouter les actions de l'utilisateur
- L'objet Event - comment obtenir des informations détaillées sur les événements
- La propagation des événements - comment les événements "bouillonnent" à travers le DOM
- La délégation d'événements - la gestion efficace de nombreux éléments
- Les différents types d'événements - souris, clavier, formulaires
- La gestion de la mémoire - la suppression des écouteurs d'événements
- L'optimisation des performances - throttling, debouncing
- Les Custom Events - la création de ses propres événements
- Les techniques avancées - gestes tactiles, event bus
- 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. 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 :