Appearance
Module 12 : JavaScript – Création dynamique avancée et gestion de la visibilité
Introduction
Ce module approfondit la création dynamique d'éléments dans le DOM en leur associant des identifiants et des écouteurs d'événements de façon dynamique. Il explore également les différentes techniques pour afficher, masquer ou supprimer des éléments HTML avec des animations CSS fluides.
Objectifs du cours
- Créer des éléments HTML dynamiquement et leur associer un
idet unaddEventListener - Générer un catalogue de produits à partir d'un tableau d'objets via
createElement()etappendChild() - Mettre en page un catalogue avec Flexbox
- Afficher et masquer des éléments avec des animations CSS (
@keyframes) - Distinguer les trois méthodes de gestion de la visibilité :
visibility: hidden,display: noneetremove()
Théorie
1 : Associer un ID et un EventListener à un élément créé dynamiquement
Définition
Lorsqu'on crée un élément HTML via
createElement(), on peut lui attribuer un attributiddynamique et lui associer un écouteur d'événement viaaddEventListener(), exactement comme on le ferait sur un élément déjà présent dans le HTML. En fait, un élément créé avec createElement() est un objet DOM standard, exactement comme celui récupéré avec getElementById().
Exemple
javascript
// getElementById: obtenir un bouton déjà présent dans le HTML et lui associer des propriétés et un événement
const bouton = document.getElementById('monBouton');
bouton.classList.add('btn', 'btn-primary');
bouton.textContent = 'Enregistrer';
bouton.addEventListener('click', gererClick);
// createElement : Créer un nouveau bouton dynamiquement, lui attribuer un id et lui associer un événement click
const nouveauBouton = document.createElement('button');
nouveauBouton.id = 'btn-dynamique-1';
nouveauBouton.classList.add('btn', 'btn-secondary');
nouveauBouton.textContent = 'Enregistrer';
nouveauBouton.addEventListener('click', gererClick);
// On doit ensuite ajouter ce nouveau bouton au DOM pour qu'il soit visible et interactif
let elementParent = document.getElementById('form1');
elementParent.appendChild(nouveauBouton);Résultat final est le même :
html
<!-- Si on click sur ce bouton, l'événement est déclenché -->
<button id="monBouton" class="btn btn-primary">Enregistrer</button>
Exemple pratique : créer un bouton avec un ID et un événement de clic
HTML
html
<div id="zone-boutons"></div>
<p id="message"></p>CSS
css
.btn-dynamique {
padding: 10px 20px;
background-color: #3498db;
color: white;
border: none;
cursor: pointer;
border-radius: 5px;
font-size: 1em;
}
.btn-dynamique:hover {
background-color: #2980b9;
}JavaScript
javascript
function gererClicBouton(event) {
const message = document.getElementById('message');
message.textContent = 'Le bouton « ' + event.currentTarget.id + ' » a été cliqué !';
}
function init() {
const zoneBoutons = document.getElementById('zone-boutons');
const bouton = document.createElement('button');
bouton.id = 'btn-action-1';
bouton.textContent = 'Cliquez-moi';
bouton.classList.add('btn-dynamique');
bouton.addEventListener('click', gererClicBouton);
zoneBoutons.appendChild(bouton);
}
addEventListener('load', init);Note : La variable
eventdans la fonction gestionnaire fait référence à l'élément qui a déclenché l'événement, ce qui permet d'accéder à sonidsans avoir besoin d'une variable globale.
Points importants
- L'
idpeut être construit dynamiquement :bouton.id = 'btn-action-' + compteur - L'
addEventListeners'attache à l'élément avant de l'ajouter au DOM.- Donc si on crée un élément avec
createElement(), on peut lui associer unidet unaddEventListener()immédiatement, même s'il n'est pas encore dans la page.
- Donc si on crée un élément avec
- Une variable créée par getElementById() ou createElement() est un objet DOM complet, avec toutes les propriétés et méthodes disponibles
Exercices pratiques
Voir l'exercice 1
2 : Afficher et masquer un élément avec une animation CSS
Définition
On peut afficher ou masquer un élément HTML de façon animée en combinant des
@keyframesCSS avec des classes qu'on ajoute ou retire via JavaScript.
Contexte d'utilisation
Cette technique est couramment utilisée pour : des menus déroulants, des fenêtres modales, des messages de confirmation, des galeries d'images, ou tout contenu à révéler progressivement à l'utilisateur.
Étape 1 : Définir les classes CSS et les keyframes
css
/* État initial : caché */
.boite-image {
display: none;
}
/* Classe appliquée dynamiquement pour rendre visible avec animation */
.boite-image-visible {
display: block;
animation: glisserApparition 0.5s ease forwards;
}
/* Keyframe : glissement depuis le haut avec fondu */
@keyframes glisserApparition {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}Étape 2 : Préparer le code HTML
html
<button id="btn-toggle">Afficher l'image</button>
<div class="boite-image" id="boiteImage">
<img src="https://placehold.co/300x200/3498db/ffffff?text=Image+Exemple" alt="Exemple d'image animée">
</div>Étape 3 : Faire le code JavaScript
javascript
function gererAffichage() {
const boiteImage = document.getElementById('boiteImage');
const bouton = document.getElementById('btn-toggle');
if (boiteImage.classList.contains('boite-image-visible')) {
// L'image est visible → on la cache
boiteImage.classList.remove('boite-image-visible');
boiteImage.style.display = 'none';
bouton.textContent = 'Afficher l\'image';
} else {
// L'image est cachée → on la rend visible avec animation
// On doit d'abord retirer le display:none AVANT d'ajouter la classe d'animation
boiteImage.style.display = 'block';
boiteImage.classList.add('boite-image-visible');
bouton.textContent = 'Masquer l\'image';
}
}
function init() {
const bouton = document.getElementById('btn-toggle');
bouton.addEventListener('click', gererAffichage);
}
addEventListener('load', init);Important : Il faut toujours appliquer
display: block(ou retirerdisplay: none) avant d'ajouter la classe d'animation. Un élément avecdisplay: nonen'est pas rendu par le navigateur, donc l'animation ne se déclenchera pas.
Points importants
forwardsdansanimation: glisserApparition 0.5s ease forwardssignifie que l'état final de l'animation est conservé une fois terminée- La logique du bouton (texte + état) est gérée entièrement en JavaScript
classList.contains()permet de vérifier l'état actuel avant d'appliquer une action- Les
@keyframespermettent de définir des étapes intermédiaires (from,to, ou des pourcentages)
Différences avec les autres méthodes de gestion de la visibilité
En CSS et JavaScript, il existe trois approches principales pour gérer la visibilité d'un élément, chacune ayant un comportement distinct sur le rendu de la page et sur la présence de l'élément dans le DOM.
Méthode 1 : visibility: hidden — Invisible, mais présent dans le flux
L'élément est rendu invisible, mais il conserve son espace dans le document. Les éléments autour de lui ne bougent pas.
CSS
css
.invisible {
visibility: hidden;
}HTML
html
<p>Paragraphe avant l'image</p>
<img id="imgVisibility" src="https://placehold.co/200x100/e74c3c/ffffff?text=Image" alt="Image cachée">
<p>Paragraphe après l'image</p>
<button id="btn-visibility">Cacher (visibility)</button>JavaScript
javascript
function cacherVisibility() {
const image = document.getElementById('imgVisibility');
image.classList.add('invisible');
}
function init() {
const bouton = document.getElementById('btn-visibility');
bouton.addEventListener('click', cacherVisibility);
}
addEventListener('load', init);Résultat : L'image disparaît visuellement, mais son espace est conservé. Le paragraphe « après » ne remonte pas.
Méthode 2 : display: none — Hors du flux, mais présent dans le DOM
L'élément est retiré du flux du document : il n'est plus visible et n'occupe plus d'espace. Il reste cependant dans le code HTML et est toujours accessible en JavaScript.
CSS
css
.cache {
display: none;
}HTML
html
<p>Paragraphe avant l'image</p>
<img id="imgDisplay" src="https://placehold.co/200x100/e67e22/ffffff?text=Image" alt="Image cachée">
<p>Paragraphe après l'image</p>
<button id="btn-display">Cacher (display)</button>JavaScript
javascript
function cacherDisplay() {
const image = document.getElementById('imgDisplay');
image.classList.add('cache');
}
function init() {
const bouton = document.getElementById('btn-display');
bouton.addEventListener('click', cacherDisplay);
}
addEventListener('load', init);Résultat : L'image disparaît et le paragraphe « après » remonte immédiatement à sa place. L'image est toujours accessible via
getElementById('imgDisplay').
Méthode 3 : remove() — Suppression complète du DOM
L'élément est complètement retiré du DOM. Il n'est plus accessible via
getElementById()à moins d'avoir conservé une référence avant sa suppression.
HTML
html
<p>Paragraphe avant l'image</p>
<img id="imgRemove" src="https://placehold.co/200x100/9b59b6/ffffff?text=Image" alt="Image supprimée">
<p>Paragraphe après l'image</p>
<button id="btn-remove">Retirer du DOM</button>JavaScript
javascript
function supprimerElement() {
const image = document.getElementById('imgRemove');
if (image !== null) {
image.remove();
}
}
function init() {
const bouton = document.getElementById('btn-remove');
bouton.addEventListener('click', supprimerElement);
}
addEventListener('load', init);Important : Cette opération est irréversible dans le flux de la page. Pour réafficher l'élément, il faudrait le recréer avec
createElement()ou avoir conservé une référence avant l'appel àremove(). La vérificationif (image !== null)évite une erreur si le bouton est cliqué plusieurs fois.
Tableau comparatif des trois méthodes
visibility: hidden | display: none | remove() | |
|---|---|---|---|
| Visible dans la page | ✗ | ✗ | ✗ |
| Conserve son espace | ✓ | ✗ | ✗ |
| Reste dans le DOM | ✓ | ✓ | ✗ |
| Accessible en JS | ✓ | ✓ | ✗ |
| Réversible facilement | ✓ | ✓ | ✗ |
Exercice pratique
Voir l'exercice 2
3 : HTML à partir d'un tableau d'objets
Définition
On peut parcourir un tableau d'objets JavaScript et créer, pour chaque objet, un ensemble d'éléments HTML assemblés via
createElement()etappendChild(), formant ainsi un contenu riche généré entièrement en JavaScript.
Contexte d'utilisation
Cette approche est idéale pour afficher des données structurées : catalogue de produits, liste d'employés, galerie de films, etc. Elle sépare clairement les données (le tableau) de la présentation (les éléments créés).
Exemple pratique : catalogue de voitures
On dispose d'un tableau d'objets en mémoire et on souhaite l'afficher sous forme de cartes dans la page.
HTML Soit une zone dans la page web réservée à afficher un catalogue de voitures :
html
<section id="catalogue"></section>CSS Le code CSS est déjà créé à l'avance, en fonction de la structure HTML que nous allons générer :
css
#catalogue {
display: flex;
flex-wrap: wrap;
gap: 20px;
padding: 20px;
}
.carte-voiture {
width: 260px;
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}
.carte-voiture img {
width: 100%;
height: 160px;
object-fit: cover;
display: block;
}
.carte-voiture .info {
padding: 12px;
}
.carte-voiture .info h3 {
margin: 0 0 6px 0;
}
.carte-voiture .info .prix {
font-weight: bold;
color: #2c3e50;
margin: 4px 0;
}
.carte-voiture .info .description {
font-size: 0.9em;
color: #555;
margin: 4px 0;
}
.btn-acheter {
display: block;
width: 100%;
padding: 10px;
background-color: #2ecc71;
color: white;
border: none;
cursor: pointer;
font-size: 1em;
}
.btn-acheter:hover {
background-color: #27ae60;
}JavaScript
Le code javascript sera responsable de parcourir le tableau d'objets voitures, de créer une carte pour chaque voiture, et de les ajouter à la section #catalogue. Chaque carte contiendra un bouton "ACHETER" qui affichera une alerte avec le nom de la voiture sélectionnée.
javascript
const voitures = [
{
id: 0,
marque: 'Toyota Corolla',
prix: 28000,
description: 'Fiable et économique, parfaite pour la ville.',
image: 'https://placehold.co/260x160/cccccc/000000?text=Toyota+Corolla'
},
{
id: 1,
marque: 'Honda Civic',
prix: 31000,
description: 'Confortable et performante sur tous les terrains.',
image: 'https://placehold.co/260x160/aaaaaa/ffffff?text=Honda+Civic'
},
{
id: 2,
marque: 'BMW Série 3',
prix: 55000,
description: 'Le plaisir de conduire à l\'état pur.',
image: 'https://placehold.co/260x160/333333/ffffff?text=BMW+Serie+3'
}
];
/**
* Crée et retourne un élément HTML article représentant une carte de voiture complète.
* La carte inclut une image cliquable avec dataset, les informations de la voiture et un bouton d'achat.
* @param voiture - L'objet voiture contenant id, marque, prix, description et image
* @returns L'élément article représentant la carte de voiture
*/
function creerCarteVoiture(voiture) {
// Créer la carte principale
const carte = document.createElement('article');
carte.classList.add('carte-voiture');
carte.id = 'voiture-' + voiture.id;
// Créer l'image
const image = document.createElement('img');
image.src = voiture.image;
image.alt = 'Photo de ' + voiture.marque;
// Créer la zone d'informations
const info = document.createElement('div');
info.classList.add('info');
const titre = document.createElement('h3');
titre.textContent = voiture.marque;
const prix = document.createElement('p');
prix.classList.add('prix');
prix.textContent = voiture.prix + ' $';
const description = document.createElement('p');
description.classList.add('description');
description.textContent = voiture.description;
// Assembler la zone d'informations
info.appendChild(titre);
info.appendChild(prix);
info.appendChild(description);
// Créer le bouton ACHETER
const bouton = document.createElement('button');
bouton.classList.add('btn-acheter');
bouton.textContent = 'ACHETER';
// Construire un id unique pour le bouton
bouton.id = 'btn-voiture-' + voiture.id;
// Lui associer un événement de clic
bouton.addEventListener('click', gererBtnAchat);
// Assembler la carte complète
carte.appendChild(image);
carte.appendChild(info);
carte.appendChild(bouton);
// Ici, on est pas obligé d'ajouter la carte au DOM, on peut juste la retourner et l'ajouter plus tard
// Donc, cette fonction devient générique : elle prend un objet voiture et retourne une carte complète, sans se soucier de l'endroit où elle sera ajoutée.
return carte;
}
function init() {
const catalogue = document.getElementById('catalogue');
// Parcourir le tableau de voitures et créer une carte pour chaque voiture
for (const v of voitures) {
// Construire le code HTML de la voiture, à partir de l'objet v, et retourner la carte complète.
const carte = creerCarteVoiture(v);
// Ajouter la carte au catalogue (site web)
catalogue.appendChild(carte);
}
}
addEventListener('load', init);Points importants
- Chaque carte reçoit un
idunique construit à partir de l'idde l'objet :'voiture-' + voiture.id - La fonction
creerCarteVoiture()retourne une carte complète avant de l'ajouter au DOM - Le bouton reçoit lui aussi un
idunique pour pouvoir le cibler individuellement si nécessaire toLocaleString('fr-CA')formate le nombre selon les conventions françaises canadiennes (espaces comme séparateurs de milliers)
4 : Dataset : stocker de l'information dans une balise HTML
Dataset
En javascript, un dataset est un objet qui permet de stocker des données personnalisées directement dans les attributs d'un élément HTML. Ces données sont accessibles via la propriété
datasetde l'élément, ce qui facilite la transmission d'informations entre la création de l'élément et son gestionnaire d'événement, sans recourir à des variables globales ou à des closures.
Lorsqu'on utilise createElement() pour créer un élément HTML, on peut lui ajouter des attributs personnalisés en utilisant la syntaxe element.dataset.nomAttribut = valeur. Ces données deviendront des attributs HTML de la balise créée et seront accessibles par javascript lorsque l'utilisateur interagit avec cet élément, notamment dans les gestionnaires d'événements.
En gros, ça permet de stocker des informations directement dans le HTML pour les récupérer facilement lors d'un événement, sans devoir créer des variables globales ou autres mécanismes.
Soi le code HTML suivant :
html
<div id="div1">
<img id="image1" src="voiture.jpg" alt="Voiture">
</div>On peut ajouter des données personnalisées à l'image ou à d'autres éléments de la page en utilisant dataset :
javascript
const image = document.getElementById('image1');
image.dataset.marque = 'Toyota';
image.dataset.prix = '45000';Résultat dans le HTML :
html
<div id="div1">
<img id="image1" src="voiture.jpg" alt="Voiture" data-marque="Toyota" data-prix="45000">
</div>Exemple : si on avait un evenement click sur cette image, on pourrait récupérer les données du dataset pour afficher une alerte avec la marque et le prix de la voiture :
javascript
function gererClicImage(event) {
const marque = event.currentTarget.dataset.marque; // Récupère 'Toyota'
const prix = event.currentTarget.dataset.prix; // Récupère '45000'
alert('Marque : ' + marque + '\nPrix : ' + prix);
}| Dataset javascript | Code HTML correspondant |
|---|---|
element.dataset.nomAttribut = valeur | <tag data-nom-attribut="valeur"> |
image.dataset.marque = 'Toyota' | <img data-marque="Toyota" src=".."> |
Contexte d'utilisation
Cette technique est utile lorsque vous créez dynamiquement des éléments et que vous voulez que chaque élément porte ses propres données, accessibles lors d'un événement sans avoir à rechercher dans un tableau global.
Exemples pratiques
À partir de l'exemple du catalogue de voitures, modifions le code pour rendre les images cliquables et leur ajouter des attributs dataset :
javascript
const voitures = [
{
id: 0,
marque: 'Toyota Corolla',
prix: 28000,
description: 'Fiable et économique, parfaite pour la ville.',
image: 'https://placehold.co/260x160/cccccc/000000?text=Toyota+Corolla'
},
{
id: 1,
marque: 'Honda Civic',
prix: 31000,
description: 'Confortable et performante sur tous les terrains.',
image: 'https://placehold.co/260x160/aaaaaa/ffffff?text=Honda+Civic'
},
{
id: 2,
marque: 'BMW Série 3',
prix: 55000,
description: 'Le plaisir de conduire à l\'état pur.',
image: 'https://placehold.co/260x160/333333/ffffff?text=BMW+Serie+3'
}
];
function creerCarteVoiture(voiture) {
// Créer la carte principale
const carte = document.createElement('article');
carte.classList.add('carte-voiture');
carte.id = 'voiture-' + voiture.id;
// Créer l'image
const image = document.createElement('img');
image.src = voiture.image;
image.alt = 'Photo de ' + voiture.marque;
// Ajouter les attributs dataset
image.dataset.marque = voiture.marque;
image.dataset.description = voiture.description;
// Ajouter l'événement de clic
image.addEventListener('click', gererClicImage);
// Créer la zone d'informations
const info = document.createElement('div');
info.classList.add('info');
const titre = document.createElement('h3');
titre.textContent = voiture.marque;
const prix = document.createElement('p');
prix.classList.add('prix');
prix.textContent = voiture.prix + ' $';
const description = document.createElement('p');
description.classList.add('description');
description.textContent = voiture.description;
// Assembler la zone d'informations
info.appendChild(titre);
info.appendChild(prix);
info.appendChild(description);
// Créer le bouton ACHETER
const bouton = document.createElement('button');
bouton.classList.add('btn-acheter');
bouton.textContent = 'ACHETER';
// Construire un id unique pour le bouton
bouton.id = 'btn-voiture-' + voiture.id;
// Lui associer un événement de clic
bouton.addEventListener('click', gererBtnAchat);
// Assembler la carte complète
carte.appendChild(image);
carte.appendChild(info);
carte.appendChild(bouton);
return carte;
}
// Gestionnaire d'événement pour le clic sur l'image
// On récupère les données du dataset pour afficher une alerte avec la marque et la description de la voiture
function gererClicImage(event) {
const marque = event.currentTarget.dataset.marque;
const description = event.currentTarget.dataset.description;
alert('Marque : ' + marque + '\nDescription : ' + description);
}
function init() {
const catalogue = document.getElementById('catalogue');
// Parcourir le tableau de voitures et créer une carte pour chaque voiture
for (const v of voitures) {
const carte = creerCarteVoiture(v);
catalogue.appendChild(carte);
}
}
addEventListener('load', init);Note :
image.dataset.marque = voiture.marquecrée l'attribut HTMLdata-marquesur l'élément<img>. Lors du clic,event.currentTarget.dataset.marquepermet de récupérer cette valeur.
Points importants
- Les attributs
datasetsont accessibles viaelement.dataset.nomAttribut - Ils correspondent aux attributs HTML
data-nom-attribut(avec conversion camelCase) - Cette méthode évite les closures et permet une séparation claire entre données et logique d'événement
Exercices pratiques
Exercice 1 : Gestion des clics d'images dynamiques
Énoncé
Au chargement de la page (fonction initialiser()), appeler une fonction nommée "CreerImage()". Cette fonction sera responsable de crée dynamiquement 3 images et de les ajouter dans la page web, dans le main. Vous devez préparer une page web avec un id sur le main.
- Lors de la création des images, faite le avec une boucle for et donner, à chaque image, un ID unique (exemple :
img-1,img-2,img-3). - Associe un seul gestionnaire d'événement
clickà toutes ces images. - Lorsque l'utilisateur clique sur une image :
- Si c'est la première fois que cette image est cliquée, ajoute son ID au tableau global
imagesCliquees - Si l'image a déjà été cliquée, affiche un alert avec le message "Cette image a déjà été cliquée"
- Si c'est la première fois que cette image est cliquée, ajoute son ID au tableau global
Le but de cet exercice est d'être capable de générer dynamiquement des éléments HTML lors du chargement de la page, de leur attribuer des ID uniques, et d'associer un même gestionnaire d'événement à tous les éléments créés, tout en gérant un état global avec un tableau qui enregistre les éléments (leur id) déjà cliqués.
Éléments à considérer
- Utilise
createElement()pour créer les images dynamiquement - Un seul
addEventListenerpour toutes les images (donc un seul gestionnaire de clic qui gère les trois images) - Utilise un tableau global
imagesCliqueespour stocker les IDs des images déjà cliquées - Vérifie si l'ID est déjà dans le tableau avant de l'ajouter
- Utilise ces images pour tester, considérant qu'elles sont nommés volontairement
1.png,2.png,3.pngpour être capable de les associés à l'intérieur d'une boucle for gràce à l'index de la boucle :img.src = './images/Module12/' + (i + 1) + '.png' - Voir l'image Linux
- Voir l'image Mac
- Voir l'image Windows
- Utilise ces images pour tester, considérant qu'elles sont nommés volontairement
Exemple d'un résultat attendu :
J'ai ajouté beaucoup de CSS, mais le principe est simplement d'afficher 3 images et se savoir si l'utilisateur a déjà cliqué ou pas sur une image. 
Exercice 2 : Panneau d'information animé
Énoncé
Crée un bouton Afficher les informations qui, au clic, affiche un
<div>contenant un titre1, un paragraphe de bienvenue et une image. L'apparition au complet (la div) doit être animée avec un effet de fondu et d'agrandissement (opacity + scale). Le bouton doit aussi servir à masquer le panneau si celui-ci est déjà affiché.
Critères à respecter :
- L'animation d'apparition utilise
@keyframesavecopacityettransform: scale() - Le texte du bouton change : Afficher les informations si l'élément est masqué, Masquer les informations si l'élément est affiché
- La div existe avec tout son code HTML. Par contre, elle est doit être cachée par défaut via une classe qui utilise
display: none. Donc, au chargement de la page, elle est dans le code, mais pas visible.
Concepts attendus dans cet exercice :
- Des classes CSS crées à l'avance pour gérer l'état visible/invisible et l'animation
- Un gestionnaire d'événement qui gère à la fois l'affichage et le masquage du panneau, ainsi que le changement de texte du bouton
- Utilisation de
event.currentTargetpour accéder au bouton cliqué et changer son texte en fonction de l'état du panneau d'information
Résultat attendu :

Exercice 3 : Comparaison des méthodes de visibilité
Énoncé
Crée une page web contenant trois images identiques, chacune accompagnée d'un bouton. Chaque bouton applique une méthode de visibilité différente sur son image :
- Bouton 1 →
visibility: hidden- Bouton 2 →
display: none- Bouton 3 →
remove()Sous les trois images, ajoute un texte « Je suis en bas » pour observer visuellement comment chaque méthode affecte la position des éléments voisins.
Critères à respecter :
- Structure HTML uniquement avec les extraits nécessaires
- Chaque bouton utilise
addEventListenerdans la fonctioninit()
Exercice 4 : Gestion d'un inventaire avec datasets
Énoncé
Créez une page web qui affiche dynamiquement une liste de boutons représentant différents articles d'inventaire. Chaque bouton doit contenir des informations stockées dans des datasets (prix et quantité en stock). Au clic sur un bouton, affichez une alerte avec le nom de l'article, son prix et sa quantité en stock récupérés via les propriétés dataset.
Critères à respecter :
- Utilisez un tableau d'objets JavaScript pour définir les articles (nom, prix, stock)
- Créez les boutons dynamiquement avec
createElement()etappendChild() - Ajoutez les datasets aux boutons :
bouton.dataset.prix = article.prixetbouton.dataset.stock = article.stock - Un seul gestionnaire d'événement pour tous les boutons
- Dans le gestionnaire, utilisez
event.currentTarget.datasetpour récupérer les informations
Code de départ :
HTML (insérez ce code dans le body de votre page) :
html
<div id="inventaire"></div>CSS (styles.css) :
css
body {
font-family: Arial, sans-serif;
padding: 20px;
}
h1 {
text-align: center;
}
#inventaire {
display: flex;
flex-wrap: wrap;
gap: 10px;
}JavaScript (scripts.js) :
javascript
const articles = [
{
nom: 'Ordinateur portable',
prix: 1200,
stock: 5
},
{
nom: 'Souris sans fil',
prix: 25,
stock: 20
},
{
nom: 'Clavier mécanique',
prix: 80,
stock: 15
}
];
// Reste du code JavaScript à compléter pour créer les boutons et gérer les clics, etc.Concepts attendus :
- Création dynamique d'éléments
- Utilisation des datasets pour stocker des données personnalisées
- Gestion d'événements sur des éléments créés dynamiquement
Corrigés
Sera déposé sous peu.
Corrigé Exercice 1
html
<main id="main">
... Le code JavaScript va créer les images dynamiquement et les ajouter ici ...
</main>css
#main {
display: flex;
gap: 20px;
padding: 20px;
}
.cliquee {
opacity: 0.5;
}javascript
// Création du tableau global pour stocker les IDs des images déjà cliquées
const imagesCliquees = [];
// Gestionnaire d'événement pour le clic sur les images
function gererClicImage(event) {
//On récupère l'id de l'image cliquée à partir de event.currentTarget.id
const idImage = event.currentTarget.id;
// Si l'id de l'image est déjà dans le tableau, on affiche une alerte
if (imagesCliquees.includes(idImage)) {
alert('Cette image a déjà été cliquée');
} else {
// sinon, c'est que c'est la première fois que l'image est cliquée, on ajoute son id au tableau
event.currentTarget.classList.add('cliquee');
imagesCliquees.push(idImage);
console.log('Image cliquée pour la première fois : ' + idImage);
}
}
function CreerImage() {
const main = document.getElementById('main');
for (let i = 0; i < 3; i++) {
const img = document.createElement('img');
img.src = './images/' + (i + 1) + '.png';
img.id = 'img-' + (i + 1);
img.addEventListener('click', gererClicImage);
main.appendChild(img);
}
}
function init() {
CreerImage();
}
addEventListener('load', init);Corrigé Exercice 2
html
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exercice 2 - Panneau d'information animé</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header>
<h1>Exercice 2 : Panneau d'information animé</h1>
<p>Cliquez sur le bouton pour afficher ou masquer le panneau d'informations avec animation.</p>
</header>
<main>
<button id="btn-toggle">Afficher les informations</button>
<div id="panneau-info">
<h2>Bienvenue sur notre site !</h2>
<p>Nous sommes ravis de vous accueillir. Découvrez nos services et produits de qualité.</p>
<img src="https://placehold.co/400x250/3498db/ffffff?text=Image de Bienvenue" alt="Image de bienvenue">
</div>
</main>
<script src="scripts.js"></script>
</body>
</html>css
/* Styles pour l'exercice 2 - Panneau d'information animé */
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f8f9fa;
line-height: 1.6;
}
header {
text-align: center;
margin-bottom: 40px;
}
h1 {
color: #2c3e50;
font-size: 2em;
margin-bottom: 10px;
}
header p {
color: #7f8c8d;
font-size: 1.1em;
}
main {
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
}
#btn-toggle {
padding: 12px 24px;
font-size: 1.1em;
background-color: #3498db;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
transition: background-color 0.3s ease;
font-weight: bold;
}
#btn-toggle:hover {
background-color: #2980b9;
}
#panneau-info {
display: none;
background-color: white;
padding: 30px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
max-width: 500px;
text-align: center;
border: 2px solid #3498db;
}
/* Classe appliquée dynamiquement pour l'animation d'apparition */
#panneau-info.visible {
display: block;
animation: apparitionPanneau 0.6s ease forwards;
}
/* Classe pour l'animation de disparition */
#panneau-info.disparition {
display: block;
animation: disparitionPanneau 0.6s ease forwards;
}
#panneau-info h2 {
color: #2c3e50;
margin-bottom: 15px;
font-size: 1.5em;
}
#panneau-info p {
color: #555;
margin-bottom: 20px;
font-size: 1.1em;
}
#panneau-info img {
width: 100%;
max-width: 400px;
height: auto;
border-radius: 8px;
margin: 20px 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* Animation de fondu et d'agrandissement */
@keyframes apparitionPanneau {
from {
opacity: 0;
transform: scale(0.8);
}
to {
opacity: 1;
transform: scale(1);
}
}
/* Animation de disparition (inverse de l'apparition) */
@keyframes disparitionPanneau {
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.8);
}
}javascript
// Exercice 2 : Panneau d'information animé
function gererAffichagePanneau() {
const panneau = document.getElementById('panneau-info');
const bouton = document.getElementById('btn-toggle');
if (panneau.classList.contains('visible')) {
// Le panneau est visible → le masquer avec animation
panneau.classList.remove('visible');
panneau.classList.add('disparition');
bouton.textContent = 'Afficher les informations';
} else {
// Le panneau est caché → l'afficher avec animation
panneau.style.display = 'block';
panneau.classList.add('visible');
panneau.classList.remove('disparition');
bouton.textContent = 'Masquer les informations';
}
}
function init() {
const bouton = document.getElementById('btn-toggle');
bouton.addEventListener('click', gererAffichagePanneau);
console.log('Exercice 2 initialisé - Panneau d\'information animé prêt');
}
// Initialiser au chargement de la page
addEventListener('load', init);Corrigé Exercice 3
html
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exercice 3 - Comparaison des méthodes de visibilité</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Comparaison des méthodes de visibilité</h1>
<div class="container">
<div class="section">
<img id="img1" src="https://placehold.co/200x150/3498db/ffffff?text=Image 1" alt="Image 1">
<button id="btn1">Masquer avec visibility: hidden</button>
</div>
<div class="section">
<img id="img2" src="https://placehold.co/200x150/e74c3c/ffffff?text=Image 2" alt="Image 2">
<button id="btn2">Masquer avec display: none</button>
</div>
<div class="section">
<img id="img3" src="https://placehold.co/200x150/2ecc71/ffffff?text=Image 3" alt="Image 3">
<button id="btn3">Supprimer avec remove()</button>
</div>
</div>
<p id="texte-bas">Je suis en bas</p>
<script src="scripts.js"></script>
</body>
</html>css
body {
font-family: Arial, sans-serif;
max-width: 1000px;
margin: 0 auto;
padding: 20px;
background-color: #f8f9fa;
}
h1 {
text-align: center;
color: #2c3e50;
margin-bottom: 30px;
}
.container {
display: flex;
justify-content: space-around;
gap: 20px;
margin-bottom: 40px;
}
.section {
text-align: center;
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
flex: 1;
}
img {
width: 200px;
height: 150px;
object-fit: cover;
border-radius: 4px;
margin-bottom: 15px;
}
button {
padding: 10px 15px;
background-color: #3498db;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
button:hover {
background-color: #2980b9;
}
#texte-bas {
text-align: center;
font-size: 18px;
font-weight: bold;
color: #2c3e50;
padding: 20px;
background-color: #ecf0f1;
border-radius: 4px;
}
/* Classes pour les méthodes de visibilité */
.invisible {
visibility: hidden;
}
.cache {
display: none;
}javascript
// Exercice 3 : Comparaison des méthodes de visibilité
function masquerVisibility() {
const img = document.getElementById('img1');
img.classList.add('invisible');
}
function masquerDisplay() {
const img = document.getElementById('img2');
img.classList.add('cache');
}
function supprimerElement() {
const img = document.getElementById('img3');
if (img) {
img.remove();
}
}
function init() {
// Associer les événements aux boutons
document.getElementById('btn1').addEventListener('click', masquerVisibility);
document.getElementById('btn2').addEventListener('click', masquerDisplay);
document.getElementById('btn3').addEventListener('click', supprimerElement);
}
// Initialiser au chargement de la page
addEventListener('load', init);Corrigé Exercice 4
javascript
// Exercice 4 : Gestion d'un inventaire avec datasets
// Tableau d'objets contenant les données des articles
// Chaque article possède un nom, un prix et une quantité en stock
const articles = [
{
nom: 'Ordinateur portable',
prix: 1200,
stock: 5
},
{
nom: 'Souris sans fil',
prix: 25,
stock: 20
},
{
nom: 'Clavier mécanique',
prix: 80,
stock: 15
}
];
/**
* Gestionnaire d'événement pour le clic sur un article
* Récupère les données stockées dans le dataset du bouton cliqué
* et affiche une alerte avec le nom, le prix et le stock de l'article
*
* @param event - L'objet événement contenant la référence au bouton cliqué
*/
function gererClicArticle(event) {
// Récupérer le nom du bouton (déjà visible)
const nom = event.currentTarget.textContent;
// Récupérer le prix du dataset
const prix = event.currentTarget.dataset.prix;
// Récupérer le stock du dataset
const stock = event.currentTarget.dataset.stock;
// Afficher une alerte avec les informations récupérées
alert('Article: ' + nom + '\nPrix: ' + prix + ' $\nStock: ' + stock + ' unités');
}
/**
* Crée dynamiquement les boutons pour chaque article du tableau
* Ajoute les prix et stocks dans les datasets
* Associe le gestionnaire d'événement à chaque bouton
*/
function creerBoutonsArticles() {
// Récupérer le conteneur où ajouter les boutons
const inventaire = document.getElementById('inventaire');
// Parcourir le tableau d'articles
for (const article of articles) {
// Créer un élément button
const bouton = document.createElement('button');
// Définir le texte du bouton (le nom de l'article)
bouton.textContent = article.nom;
// Ajouter une classe CSS au bouton
bouton.classList.add('btn-article');
// Ajouter les données dans le dataset du bouton
// Ces données deviennent des attributs HTML data-*
bouton.dataset.prix = article.prix;
bouton.dataset.stock = article.stock;
// Associer le gestionnaire d'événement de clic au bouton
bouton.addEventListener('click', gererClicArticle);
// Ajouter le bouton au conteneur (dans le DOM)
inventaire.appendChild(bouton);
}
}
/**
* Fonction d'initialisation appelée au chargement de la page
* Lance la création des boutons d'articles
*/
function init() {
creerBoutonsArticles();
}
// Associer la fonction init() à l'événement 'load' du navigateur
addEventListener('load', init);