b) Interactions avec le DOM
C'est quoi le DOM ?
Le Document Object Model (DOM) est une structure de données, sous forme d'arbre, représentant les éléments HTML d'une page web.
Une page web est automatiquement réaffichée quand une manipulation JS met à jour un objet issu du DOM.
Le DOM donne accès aux éléments HTML ainsi qu'à leur style. Il est donc possible de mettre à jour tant l'HTML que le CSS d'une page web.

Comment accéder à un élément HTML en JS ?
Introduction
Il existe plusieurs moyens d'accéder à un élément HTML via des méthodes offertes par le DOM.
Nous allons voir ensemble les façons les plus pratiques.
querySelector()
Cette méthode retourne le 1er élément qui correspond à un sélecteur CSS.
Voici un exemple :
html<button id="myBtn2">Click please</button><div class="message"></div>
Voici le code JS permettant d'accéder au éléments donnés ci-dessus :
jslet btn2 = document.querySelector("#myBtn2"); // HTML id attributelet msg = document.querySelector(".message"); // CSS class namelet duplicateMsg = document.querySelector("div"); // HTML tag name
Les CSS sélecteurs sont importants en JS, tout comme en CSS :
#
: permet l'accès via la propriété htmlid
..
: permet l'accès via une classe qui aurait été donnée à l'élément HTML (via la propriétéclass
).TAG_NAME
: permet l'accès à un élément via le nom de la balise associée à l'élément HTML.
Notons que pour modifier un élément HTML pour lequel nous avons obtenu une référence, il suffit de changer une de ses propriétés. On utilise pour cela le nom des propriétés associées à l'élément HTML.
Par exemple, si l'on souhaite changer le texte de btn2
, il suffit de changer sa propriété innerText
ou innerHTML
:
jsbtn2.innerText = "I have been clicked";
Une fois cette ligne exécutée par le browser, comme le DOM a été modifié, le bouton serait automatiquement réaffiché avec le nouveau texte "I have been clicked"
.
getElementById()
Cette méthode retourne l'élément dont la propriété HTML nommée id
contient la valeur donnée en paramètre.
Voici un exemple :
html<button id="myBtn1">Click please</button>
Voici comment on pourrait accéder à cet élément :
jslet btn1 = document.getElementById("myBtn1");
querySelectorAll()
Cette méthode retourne tous les éléments qui correspondent à un sélecteur CSS, sous forme d'une NodeList
.
Voici un exemple :
html<button id="myBtn1">Click please</button><button id="myBtn2">Click please</button><button id="myBtn3">Click please</button>
Voici comment on pourrait accéder à ces éléments afin de mettre à jour leurs textes :
jsconst buttons = document.querySelectorAll("button");buttons.forEach((btn) => {btn.innerText = "Hacked!";});
Autres méthodes
Il existe bien sûr d'autres méthodes pour accéder aux éléments HTML.
Nous pensons que si vous retenez querySelector
& querySelectorAll
, il n'est pas nécessaire d'en connaître d'autres.
Néanmoins, n'hésitez pas à explorer la documentation MDN sur l'interface Document [23.].
La programmation événementielle
Pour réaliser une bonne IHM, nous allons faire de la programmation événementielle. Nous allons écrire du code pour décrire ce qui doit être fait en fonction d'un clic, du passage d'une souris...
On va ajouter des écouteurs d'événements ("event listeners") sur des éléments du DOM pour définir des actions qui seront à réaliser une fois l'événement soulevé.
Vous avez déjà expérimenté des événements qui amènent à des actions par défaut, par exemple :
- lors d'un clic sur un bouton de type "submit" d'un formulaire : les données sont envoyées au serveur et la page est rafraichie.
- lors d'un clic sur un "hyperlink" : on est redirigé vers une nouvelle page (où l'on voyage parfois aussi à l'intérieur de la même page).
Certains types d'événements sont dits "cancelable events". Pour ces événements, il est possible de stopper l'action par défaut. Nous allons prochainement découvrir comment nous pourrions empêcher de rafraichir une page lors du clic sur le bouton "submit" d'un formulaire.
Flux des événements du DOM
Il est possible que plusieurs écouteurs d'événements soient actifs au sein d'une IHM.
Voici comment le browser traite les événements :
- Dans la phase de capture : l'événement est capturé et propagé des éléments ancêtres vers l'élément cible de l'événement.
- Dans la "target phase" : l'événement est géré par l'élément cible.
- Dans la "bubbling phase" : l'événement est propagé de l'élément cible vers ses ancêtres qui pourront eux-aussi gérer cet événement si nécessaire.

Flux de traitement d'un événement [R.26]_
Les écouteurs d'événements
Introduction
Il est possible de gérer des événements de plusieurs façons.
Via des méthodes
Vous pouvez ajouter des écouteurs d'événements à l'aide de la méthode addEventListener()
.
Vous pouvez enlever des écouteurs d'événements à l'aide de la méthode removeEventListener()
.
Voici un exemple :
html<html><head><title>Demo : click event management to update a button</title></head><body><button id="myBtn1">Click please</button><button id="myBtn2">Click please</button><button id="myBtn3">Remove extra actions on button 2</button><button id="myBtn4">Click please</button><script src="index.js"></script></body></html>
Voici comment on pourrait gérer des clics sur ces boutons :
jsconst btn1 = document.querySelector('#myBtn1');const btn2 = document.querySelector('#myBtn2');const buttons = document.querySelectorAll('button');const btn3 = buttons[2]; // fancy way to get a reference...const btn4 = document.querySelector('#myBtn4');btn1.addEventListener('click', () => {btn1.innerText = 'myBtn1 : I have been clicked !';console.log('onClickHandlerForBtn1::click');});btn2.addEventListener('click', onClickHandlerForBtn2);btn2.addEventListener('click', onClickHandlerForBtnExtra);btn3.addEventListener('click', onClickHandlerForBtn3);function onClickHandlerForBtn2() {btn2.innerText = 'myBtn2 : I have also been clicked';console.log('onClickHandlerForBtn2::click');}function onClickHandlerForBtn3() {btn2.removeEventListener('click', onClickHandlerForBtnExtra);console.log('onClickHandlerForBtn3::click');}function onClickHandlerForBtnExtra() {console.log('onClickHandlerForBtnExtra::click');}btn4.onclick = function() {btn4.innerText = 'myBtn4 : You clicked on me : )';console.log('onClickHandlerForBtn4::click');};
N'hésitez pas à exécuter ce code.
Comment faire ?
Au sein de votre répertoire /web2/tutorial
, vous pourriez créer un répertoire dom-events
, et y ajouter un fichier index.html
contenant l'HTML ci-dessus.
Puis vous pourriez ajouter un fichier index.js
contenant le JS ci-dessus.
Utilisez Live Server pour lancer index.html
et accédez à la console de votre browser pour voir ce qui se passe lors de clic sur chacun des boutons.
Via des propriétés
👎 Il est aussi possible d'ajouter des écouteurs d'événements à l'aide de propriétés, mais nous ne le recommandons pas.
jsbtn4.onclick = function () {btn4.innerText = "You clicked on me : )";console.log("btn.onclick::anonymous function");};
Sur internet, vous trouverez beaucoup d'exemples de gestion d'événements à l'aide de propriétés.
👍 Si vous veniez à utiliser ce genre de code, nous vous recommandons un refactor vers l'utilisation de addEventListenner
.
Les callbacks & la programmation fonctionnelle
Les écouteurs d'événements ont besoin de préciser une action asynchrone, une action qui sera à réaliser le moment venu.
Pour spécifier cette action asynchrone, nous faisons ce que nous appelons de la programmation fonctionnelle.
A la fonction addEventListenner
, nous lui passons en paramètre une autre fonction que nous appelons une callback
.
Une callback
sera donc la fonction qui sera appelée le moment venu. Dans le cadre de la fonction addEventListenner
, la callback
sera appelée lorsque l'événement sera traité par l'élément HTML cible.
Dans ce code-ci :
js1const btn1 = document.querySelector('#myBtn1');2const btn2 = document.querySelector('#myBtn2');3const buttons = document.querySelectorAll('button');4const btn3 = buttons[2]; // fancy way to get a reference...5const btn4 = document.querySelector('#myBtn4');67btn1.addEventListener('click', () => {8btn1.innerText = 'myBtn1 : I have been clicked !';9console.log('onClickHandlerForBtn1::click');10});11btn2.addEventListener('click', onClickHandlerForBtn2);12btn2.addEventListener('click', onClickHandlerForBtnExtra);13btn3.addEventListener('click', onClickHandlerForBtn3);1415function onClickHandlerForBtn2() {16btn2.innerText = 'myBtn2 : I have also been clicked';17console.log('onClickHandlerForBtn2::click');18}1920function onClickHandlerForBtn3() {21btn2.removeEventListener('click', onClickHandlerForBtnExtra);22console.log('onClickHandlerForBtn3::click');23}2425function onClickHandlerForBtnExtra() {26console.log('onClickHandlerForBtnExtra::click');27}2829btn4.onclick = function() {30btn4.innerText = 'myBtn4 : You clicked on me : )';31console.log('onClickHandlerForBtn4::click');32};
On voit que les callback, le 2ème paramètre d'addEventListener
, peuvent être soit des fonctions "arrow" ou anonymes, soit des fonctions nommées.
⚡ Lorsque vous indiquez une callback, il est important que vous omettiez les parenthèses de la fonction. Sinon, cela ne fonctionnera pas ! Vous devez donner la définition d'une fonction, pas l'appel d'une fonction !
Création d'une IHM classique
Introduction
Tout au long du cours, nous développons de manière incrémentale, via une série de tutoriels, un site pour une pizzeria.
Dans votre repo web2
, veuillez créer le répertoire /tutorials/pizzeria/hmi/classic
.
Nous allons maintenant développer la version classique du site d'une pizzeria dans le dossier classic.
Veuillez ajouter dans le dossier classic
ces 3 répertoires :
/tutorials/pizzeria/hmi/classic/img
: c'est là que seront reprises les photos ;/tutorials/pizzeria/hmi/classic/sound
: c'est là que les fichiers sonores seront ajoutés ;/tutorials/pizzeria/hmi/classic/stylesheets
: c'est là que le CSS sera donné.
Par la suite de ce tutoriel, nous considérons que tous les chemins absolus démarrent du répertoire /tutorials/pizzeria/hmi/classic
(ou /web2/tutorials/pizzeria/hmi/classic
si l'on considère le nom du répertoire du repo).
Veuillez ajouter ces 3 images dans /img
:
-
Photo à utiliser comme background [R.29]
-
SVG à utiliser comme favicon (ou icône de votre site web)
-
Logo à utiliser dans le footer
Veuillez ajouter la musique du site dans /sound
:
Les abréviations Emmet
Nous allons d'abord créer la structure des éléments de la page au sein d'un nouveau fichier /index.html
.
Pour générer le corps de sa page HTML, on peut utiliser une abréviation Emmet au sein de VS Code ; pour cela, commencez à taper html:5
et utilisez l'autocompletion (ou saisie automatique) dans le fichier index.html
(il suffit de cliquer sur html:5
qui apparaît dans la liste associée à l'autocompletion). Donnez le titre Pizzeria à votre page web.
Les abréviations Emmet permettent donc d'automatiser l'écriture d'HTML.
En savoir plus sur les abréviations Emmet : https://docs.emmet.io/abbreviations/ [R.31]
Création de la structure de l'IHM
Nous allons ajouter un header, un main et un footer à notre page web.
Le header reprendra un simple texte ("We love Pizza").
Le main contiendra seulement une balise audio
pour offrir un lecteur contenant la chanson Pizza Spinoza.
Le footer présentera un texte ("But we also love JS") et le logo de JS.
Voici ce que devrait donner à ce stade-ci votre index.html
:
html<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Pizzeria</title></head><body><header><h1>We love Pizza</h1></header><main><audio id="audioPlayer" controls autoplay><sourcesrc="./sound/Infecticide-11-Pizza-Spinoza.mp3"type="audio/mpeg"/>Your browser does not support the audio element.</audio></main><footer><h1>But we also love JS</h1><img src="./img/js-logo.png" alt="" /></footer></body></html>
Veuillez exécuter cette page web. Même si ce n'est pas très esthétique, tous les éléments sont présents.
Mise en forme
A l'aide de CSS, nous allons mettre en forme notre page web via un nouveau fichier à créer : /stylesheets/style.css
.
Nous souhaitons que le layout de la page fasse toujours, au minimum, la hauteur complète du navigateur ; pour ce faire nous allons :
- utiliser un body repris comme un un élément Flexbox faisant 100% de hauteur.
- paramétrer le
main
pour lui permettre de remplir l'espace disponible.
Ainsi, le footer donnera l'effet d'être "sticky" en bas de page.
De plus, nous allons ajouter pizza.jpg
comme background de l'élément html
.
Voici le code de /stylesheets/style.css
(veuillez l'ajouter dans votre fichier) :
csshtml, body {height: 100%;margin: 0;}body {/*to easily deal with sticky footer*/display: flex;flex-direction: column;background-image : url(../img/pizza.jpg);background-size : cover;}header{text-align: center;}main{text-align: center;/*to easily deal with sticky footer:grow the main to fill the space*/flex: 1 0 auto;}footer{text-align: center;}footer img {height: 50px;}footer h1{color: white;}
Pour appliquer la stylesheet à index.html
, il suffit d'ajouter cette balise dans index.html
à la fin de la balise head
:
html<link rel="stylesheet" href="./stylesheets/style.css" />
Pour ajouter cette balise, il est possible de juste taper l'abréviation Emmet "link:css
" dans VS Code. Il ne reste plus qu'à ajouter le chemin vers le fichier au sein de href
. Dans la valeur de href
, si vous tapez ./
, vous verrez tous les fichiers et répertoires disponibles.
👍 Il est recommandé d'utiliser un chemin relatif dans href
et d'utiliser la saisie automatique (autocompletion) afin de ne pas se tromper dans l'écriture du chemin d'un fichier.
Il est temps d'ajouter le fichier favicon comme logo pour notre site.
Tapez l'abréviation Emmet link:favicon
à la fin de la balise head
d'index.html
.
Une balise de ce genre doit avoir été ajoutée :
html<linkrel="shortcut icon"href="./img/pizza-svgrepo-com.svg"type="image/svg+xml"/>
La page web de la pizzeria devrait paraître pas trop mal à ce stade ci.
Ajout d'interactivité
Nous souhaitons maintenant rendre cette page un peu plus interactive.
Nous nous sommes rendu compte que les clients de la pizzeria ont des difficultés à cliquer juste sur le bouton Play/Pause du lecteur.
Dès lors, nous allons permettre aux visiteurs de cliquer n'importe où sur la page pour démarrer ou stopper la musique.
Nous allons ajouter un script index.js
gérant les clics des utilisateurs sur la page :
jsconst body = document.querySelector("body");body.addEventListener("click", startOrStopSound);function startOrStopSound() {const myAudioPlayer = document.querySelector("#audioPlayer");if (myAudioPlayer.paused) myAudioPlayer.play();else myAudioPlayer.pause();}
Ici, à l'aide d'un script JS et du DOM, nous pouvons accéder à l'HTMLAudioElement
contenu dans la page web. Nous avons ensuite accès à toutes les propriétés et fonctions mises à disposition par cet objet.
Pour ajouter le fichier JS externe à la page HTML à la fin de la balise body
, vous pouvez utiliser une abréviation Emmet "script:src
" et il ne vous restera plus qu'à indiquer le chemin vers index.js
au sein de src
.
html<script src="./index.js"></script>
Voila, vous devriez pouvoir bien exécuter la HomePage
du site de la pizzeria qui traite des clics n'importe où sur la page.
Ajout d'une librairie externe
Nous souhaiterions ajouter une librairie externe à notre application et l'utiliser afin d'afficher une petite animation sur notre HomePage
.
Après quelques recherches dans google, nous découvrons la librairie Animate.css [R.32].
En lisant la documentation, nous voyons que pour ajouter la librairie à notre application, il suffit d'ajouter cette balise à une page HTML :
html<linkrel="stylesheet"href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/>
Et pour utiliser cette librairie, nous pouvons avoir un titre qui rebondit en utilisant une classe CSS de cette façon, directement au sein d'une page HTML :
html<h1 class="animate__animated animate__bounce">We love Pizza</h1>
Toujours en lisant la documentation, si nous souhaitons ajouter un délai au rebondissement, nous pouvons le faire de cette façon, à l'aide d'une classe CSS :
html<h1 class="animate__animated animate__bounce animate__delay-2s">But we also love JS</h1>
Veuillez mettre à jour votre page index.html
:
html1<!DOCTYPE html>2<html lang="en">3<head>4<meta charset="UTF-8" />5<meta name="viewport" content="width=device-width, initial-scale=1.0" />6<title>Pizzeria</title>7<link rel="icon" href="./img/pizza-svgrepo-com.svg" type="image/svg+xml" />8<link rel="stylesheet" href="./stylesheets/style.css" />9<link10rel="stylesheet"11href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"12/>13</head>14<body>15<header>16<h1 class="animate__animated animate__bounce">We love Pizza</h1>17</header>1819<main>20<p>My HomePage</p>21<p>22Because we love JS, you can also click on the header to stop / start the23music ; )24</p>2526<audio id="audioPlayer" controls autoplay>27<source28src="./sound/Infecticide-11-Pizza-Spinoza.mp3"29type="audio/mpeg"30/>31Your browser does not support the audio element.32</audio>33</main>3435<footer>36<h1 class="animate__animated animate__bounce animate__delay-2s">37But we also love JS38</h1>39<img src="./img/js-logo.png" alt="" />40</footer>4142<script src="./index.js"></script>43</body>44</html>
Nous avons très facilement ajouté deux animations à notre application web sans effort, en nous reposant sur une librairie externe.
Si tout fonctionne bien, faites un commit de votre repo (web2
) avec comme message : classic-hmi tutorial
.
En cas de souci, vous pouvez accéder au code final de ce tutorial ici : classic-hmi.
Exercice 2.2 : interaction avec le DOM
Veuillez réaliser une application web permettant d'afficher un compteur de clics sur votre page web.
Affichez le message suivant sur votre page web :
- Au 5ème clic jusqu'au 9ème clic : "Bravo, bel échauffement !"
- Au 10ème clic et au-delà : "Vous êtes passé maître en l'art du clic !"
N'oubliez pas, bien sûr, d'afficher le compteur de clics sur votre page.
Veuillez créer un nouveau projet dans votre repository local et votre web repository (normalement appelé web2
) nommé /exercises/2.2
. Quand votre application est finalisée, veuillez faire un commit
de votre code avec comme message : 2.2 : HMI : dom interaction
.
🤝 Tips
- Vous avez besoin d'un container pour afficher de l'information.
Vous pouvez utiliser la propriété
innerHtml
outextContent
d'un paragraphe<p>
ou d'un<span>
pour afficher votre compteur. - Vous pouvez faire de même pour afficher votre message.
- Vous pouvez ajouter un gestionnaire d'événement sur l'objet
window
de votre navigateur.
L'objet event
L'objet event
est automatiquement passé à la callback d'un écouteur d'événement.
Il est très utile, pour deux raisons principalement :
- Stopper l'action par défaut suite à un événement.
- Lorsqu'on attache une même callback à une multitude d'éléments, pour retrouver la cible de l'événement.
Voici un exemple où l'on souhaite découvrir l'id de la div
lorsque la souris quitte celle-ci. index.html
contient 6 divs :
html<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Demo : mouse-over event management to update a div</title><link rel="stylesheet" href="./main.css"><body><div class="message" id="msgBox1">Waiting for the call to a welcome function...</div><div class="message" id="msgBox2">Waiting for the call to a welcome function...</div><div class="message" id="msgBox3">Waiting for the call to a welcome function...</div><div class="message" id="msgBox4">Waiting for the call to a welcome function...</div><div class="message" id="msgBox5">Waiting for the call to a welcome function...</div><div class="message" id="msgBox6">Waiting for the call to a welcome function...</div><script src="index.js" ></script></body></html>
Un peu de style pour bien visualiser les 6 divs au sein de main.css
:
css.message {padding: 1rem;margin: 1rem;border: solid 1px black;}
Voici comment on pourrait gérer les mouvements de la souris au sein de index.js
:
jsconst divs = document.querySelectorAll(".message");divs.forEach((div) => {div.addEventListener("mouseover", () => {div.innerText = "Hello world!";});div.addEventListener("mouseout", (e) => {div.innerText = `You have left the div wit id ${e.target.id}`;});});
L'objet event
a été nommé e
ici, mais nous aurions pu lui donner le nom que l'on souhaitait.
👍 Pour éviter la confusion, il est recommandé de l'appeler e
(ou éventuellement event
).
e.target
est l'élément HTML qui lance la propagation de l'événement dans le DOM tree.
Parfois on préfère utiliser e.currentTarget
qui est l'élément HTML sur lequel est attaché l'écouteur d'événements.
N'hésitez pas à exécuter le code ci-dessus, si vous le souhaitez, en créant les 3 fichiers nécessaires.
Voici un exemple partiel de gestion de formulaire où l'on utilise l'objet event
pour stopper l'action par défaut qui est d'envoyer les données au serveur (indiqué par la propriété action
du formulaire) et de recharger la page :
js// code to get the reference to the form shall be imaginedconst onSubmit = (e) => {console.log("onSubmit::");e.preventDefault();};myForm.addEventListener("submit", onSubmit);
Exercice 2.3.1 : objet event & formulaire
Veuillez réaliser une application web permettant d'afficher un formulaire demandant votre souhait de l'instant et un bouton pour le soumettre.
Veuillez créer un nouveau projet dans votre repository local et votre web repository (normalement appelé web2
) nommé /exercises/2.3.1
.
Lorsqu'on clique pour soumettre son souhait, veuillez faire disparaître le formulaire et afficher le souhait soumis. Attention, vous devez vous assurer que la page n'est pas rechargée lors de la soumission du formulaire.
Quand votre application est finalisée, veuillez faire un commit
de votre code avec comme message : 2.3.1 : event object & form
.
🤝 Tips
- Pour faire disparaître un container (une
div
par exemple), vous pourriez utiliser sa propriétéstyle.display
et la mettre ànone
. - Pour faire apparaître du contenu dans un container, (une
div
par exemple), vous pourriez utiliser sa propriétéinnerText
.
🍬 Si vous souhaitez aller plus loin
Une fois un souhait fait, vous pourriez afficher un bouton permettant de réafficher le formulaire demandant un souhait.
Exercice 2.3.2 : objet event & multiples éléments
Veuillez réaliser une application web permettant d'afficher la couleur associée à une div parmi environ un millier de divs.
Veuillez créer un nouveau projet dans votre repository local et votre web repository (normalement appelé web2
) nommé /exercises/2.3.2
.
La page HTML contenant environ un millier de divs vous est offerte : Fichier HTML de base
Il ne vous reste plus qu'à ajouter l'interactivité :
- Quand on clique sur une div, vous devez l'agrandir et afficher à l'intérieur sa couleur (elle peut apparaître en RGB, par exemple :
rgb(255. 153. 255)
). - Vous devez faire cela en utilisant l'objet
event
.
Quand votre application est finalisée, veuillez faire un commit
de votre code avec comme message : 2.3.2 : event object & multiple divs
.
🤝 Tips
- N'hésitez pas à récupérer une liste de toutes les divs via
querySelectorAll
. - Vous pourriez, sur base de cette liste, attacher un écouteur de clics sur chaque div :
addEventListener
. - La callback passée à
addEventListener
vous donne accès à la cible de l'événement via l'objetevent
.
🍬 Si vous souhaitez aller plus loin
Si vous le souhaitez, vous pourriez faire en sorte que lorsqu'on clique une nouvelle fois sur une div, celle-ci revienne à sa taille initiale et n'affiche plus sa couleur.
Les timers & actions
setTimeout(f,t)
permet l'exécution d'une callback f
à l'expiration d'un timer, après t
ms.
clearTimeout()
permet de stopper l'exécution d'une callback qui a été appelée via setTimeout()
.
Voici un exemple :
html<html><head><title>Demo : timer management</title></head><body><button id="myBtn1">Show pop-up after 2s timer</button><button id="myBtn2">Clear planned action</button><script src="index.js"></script></body></html>
js1const btn1 = document.querySelector("#myBtn1");2const btn2 = document.querySelector("#myBtn2");34btn1.addEventListener("click", delayedAlert);5btn2.addEventListener("click", clearAlert);67let timeoutID;8const delayInSeconds = 2;9const delayInMiliSeconds = delayInSeconds * 1000;1011function delayedAlert() {12timeoutID = setTimeout(() => {13alert(`You asked for this popup ${delayInSeconds}s ago!`);14}, delayInMiliSeconds);15}1617function clearAlert() {18clearTimeout(timeoutID);19}
N'hésitez pas à exécuter ce code, si vous le souhaitez, en créant les 2 fichiers nécessaires.
Normalement, si vous cliquez sur le 1er bouton, puis avant deux secondes sur le deuxième bouton, aucun pop-up ne sera lancé.
Exercice 2.4.1 : timer pour lancer une action
Veuillez réaliser une application web permettant d'afficher le temps qu'il faut pour qu'un utilisateur clique 10 fois sur un bouton :
- Le jeu démarre dès que la souris de l'utilisateur passe sur le bouton.
- Si 5 secondes après que l'utilisateur soit passé sur le bouton, l'utilisateur n'a pas terminé son 10ème clic, veuillez afficher un message de type : "Game over, you did not click 10 times within 5s !".
- Si l'utilisateur a terminé ses 10 clics avant 5s, veuillez afficher :"You win ! You clicked 10 times within X ms" où X est une valeur entière.
Veuillez créer un nouveau projet dans votre repository local et votre web repository (normalement appelé web2
) nommé /exercises/2.4.1
.
Quand votre application est finalisée, veuillez faire un commit
de votre code avec comme message : 2.4.1 : run action within timer
.
🤝 Tips
- Quelle action doit être programmée dans le temps ? Peut-être celle en cas d'échec, lorsque le temps est écoulé...
- Quid si l'utilisateur réussi à cliquer suffisamment vite ? Peut-être faut il annuler l'action programmée...
Les intervalles de temps & actions répétées
setInterval(f,t)
permet l'exécution d'une callback f
tous les t
ms.
clearInterval()
permet de stopper les appels à la callback qui ont été programmés via setInterval()
.
On souhaiterait programmer une horloge, voici un simple exemple :
html<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Demo : interval management to provide a clock</title></head><body><span></span><br /><button>Stop or resume the clock</button><script src="./index.js"></script></body></html>
js1const btn = document.querySelector("button");2const clockHolder = document.querySelector("span");34btn.addEventListener("click", stopOrResumeClock);56var myIntervalId;78startClock();910function startClock() {11myIntervalId = setInterval(printCurrentTime, 1000);12}1314function printCurrentTime() {15const now = new Date();16const time = now.toLocaleTimeString();17clockHolder.innerText = time;18}1920function stopOrResumeClock() {21if (myIntervalId) {22clearInterval(myIntervalId);23myIntervalId = undefined;24} else startClock();25}
N'hésitez pas à exécuter ce code si vous le souhaitez en créant les 2 fichiers nécessaires.
La gestion d'intervalles, de cette façon, est l'ancêtre des animations en JS !
Si vous souhaitez consulter la documentation MDN concernant la gestion d'événements, afin d'approfondir certains éléments, la voici :
Exercice 2.4.2 : séquence d'événements différés dans le temps
Veuillez réaliser une application web permettant d'afficher un feu rouge.
Votre feu rouge devra continuellement alterner l'affichage de ce cycle de trois couleurs :
- rouge pendant 2 secondes
- orange pendant 2 secondes
- vert pendant 2 secondes
- orange pendant 2 secondes
- rouge pendant 2 secondes
- ...
Voila à quoi pourrait ressembler votre application web :

Veuillez créer un nouveau projet dans votre repository local et votre web repository (normalement appelé web2
) nommé /exercises/2.4.2
. Quand votre application est finalisée, veuillez faire un commit
de votre code avec comme message : 2.4.2 : timed events
.
🤝 Tips
- Vous avez besoin d'un container pour afficher une couleur.
Vous pourriez utiliser la propriété
style.backgroundColor
d'unediv
. - Comment afficher une
div
vide avec une bordure ? N'hésitez pas à vous inspirer de ce morceau de code :
js<divclass="red"style="display: inline-block; min-width: 50px; min-height: 50px; border:1px solid black"></div>
Introduction au projet
Dans le cadre de ce cours, nous souhaitions que vous puissiez vous exercer au développement d'une application qui vous tient à coeur.
C'est pourquoi, nous vous demandons de réfléchir à une application que vous souhaiteriez développer.
Pour aborder certains concepts, vous allez créer une application web mettant en œuvre :
- Une thématique qui vous tient à cœur ;
- Une RESTful API tournant sous Node.js & Express ;
- Un frontend animé utilisant les opérations offertes par votre RESTful API et éventuellement des APIs tierces.
Pour votre frontend animé, l'animation sera en 2D, 3D, sous forme de jeux ou de simples effets visuels.
A ce stade-ci, nous vous proposons d'écrire l'objectif du projet que vous souhaitez développer et d'identifier un titre pour votre projet. La description de votre projet (~15 lignes) devrait répondre à ces questions :
- quel type d'organisation (équipe sportive, bibliothèque, amis, famille…) serait prise en charge par votre application ?
- Pourquoi cette application vous tient à cœur ?
Au sein de votre répertoire /web2/
, veuillez créer un répertoire /web2/project
, et y ajouter un fichier README.md
contenant le titre du projet qui vous tiendrait à coeur de développer ainsi que la courte description de son objectif.
Pour décider de l'objectif de votre projet, vous pouvez vous inspirer de ce qui a été fait les années précédentes par les étudiants de Vinci en consultant la vitrine de projets.
Voici quelques autres exemples d'applications que vous pourriez réaliser :
- une gestion de critiques de livres ;
- une gestion d'une équipe sportive (gestion des achats ou autres de l'équipe) ;
- un jeux vidéo (multi-joueurs ou pas) dont les utilisateurs et leurs scores seraient gérés par une RESTful API ;
- Un jeu de devinette d'un mot sur base du dessin d'un des joueurs ;
- …
Quand votre README
est finalisé, veuillez faire un commit
avec comme message : 2.6 : project description & title
.