Séance 5 — Réagir au clic

Quand le code modifie la page

  • Attraper un élément de la page depuis le JavaScript
  • Changer son texte depuis le code
  • Faire réagir un bouton au clic

1. Le pont entre les deux mondes

Jusqu’ici, deux mondes séparés :

  • Le HTML, que le visiteur voit
  • Le JavaScript, qui parle tout seul dans la console

Aujourd’hui, on construit le pont. Il tient en deux instructions :

const titre = document.querySelector("h1"); // 1. ATTRAPER un élément
titre.textContent = "Nouveau titre";        // 2. LE MODIFIER

C’est tout. Vous venez de voir l’essentiel de la séance.

2. Attraper un élément

const titre = document.querySelector("h1");
Morceau Sens
document La page entière
.querySelector(…) « cherche-moi le premier élément qui correspond »
"h1" Ce qu’on cherche, écrit comme un sélecteur CSS
ImportantBonne nouvelle : vous savez déjà écrire des sélecteurs

querySelector prend exactement la même chose que le CSS :

document.querySelector("h1");        // la première balise <h1>
document.querySelector(".intro");    // le premier élément class="intro"
document.querySelector("#compteur"); // l'élément id="compteur"

Le CSS de la séance 3 vous ressert immédiatement.

class ou id ?

class id
Combien d’éléments ? Plusieurs Un seul dans toute la page
En CSS / JS .nom #nom
Sert surtout à Styler Attraper depuis le JS
AstuceNotre convention pour le reste du cours

Quand un élément doit être manipulé par le JavaScript, on lui donne un id. Ça rend le code clair : en lisant le HTML, on sait tout de suite quels éléments sont « vivants ».

<p id="message">…</p>
const message = document.querySelector("#message");

3. Modifier le texte

element.textContent = "Le nouveau texte";

Étape 1 — Premier essai

Créez seance05.html :

seance05.html
<!DOCTYPE html>
<html lang="fr">
  <head>
    <meta charset="UTF-8" />
    <title>Séance 5</title>
  </head>
  <body>
    <h1 id="titre">Titre de départ</h1>
    <p id="message">Message de départ</p>

    <script src="app.js"></script>
  </body>
</html>

Et app.js :

app.js
const titre = document.querySelector("#titre");
const message = document.querySelector("#message");

titre.textContent = "Modifié par le JavaScript !";
message.textContent = "Moi aussi.";

Lancez Live Server : les deux textes ont changé, alors que le HTML contient toujours les anciens.

NoteCe que vous venez de faire

Le fichier HTML n’a pas été modifié. Ouvrez-le : il contient toujours « Titre de départ ».

Ce qui a changé, c’est la page telle qu’elle est affichée en mémoire dans le navigateur. C’est ça, la programmation web : le HTML donne l’état de départ, le JavaScript le transforme ensuite.

AvertissementErreur classique : null

Si la console affiche :

Cannot set properties of null (setting 'textContent')

cela veut dire que querySelector n’a rien trouvé et a renvoyé null. Trois causes possibles :

  1. Faute de frappe dans le nom : #titre vs #Titre
  2. Le # oublié : querySelector("titre") cherche une balise <titre>
  3. Le <script> est placé trop haut, avant l’élément. Il doit être juste avant </body>.

Exercice 5.1

Ajoutez dans le HTML un paragraphe <p id="date">…</p>, et faites-le afficher depuis le JavaScript : Nous sommes en 2026.

seance05.html
<p id="date">chargement…</p>
app.js
const date = document.querySelector("#date");
date.textContent = "Nous sommes en 2026.";

4. Réagir à un clic

Étape 2 — Le bouton

Ajoutez un bouton dans le HTML, avant le <script> :

seance05.html
<button id="monBouton">Clique-moi</button>

Et dans app.js :

app.js
const monBouton = document.querySelector("#monBouton");

monBouton.addEventListener("click", () => {
  console.log("On a cliqué !");
});

Ouvrez la console, cliquez plusieurs fois sur le bouton.

Décortiquons

monBouton . addEventListener ( "click" ,  () => { … } )
└───┬────┘   └──────┬───────┘   └──┬──┘    └────┬────┘
    │               │              │            └── QUOI FAIRE
    │               │              └─────────────── QUAND (l'événement)
    │               └────────────────────────────── « mets-toi à l'écoute de… »
    └────────────────────────────────────────────── SUR QUI

Ça se lit : « sur le bouton, écoute l’événement "click" et, quand il arrive, fais ce qui est entre les accolades ».

Note() => { … } : la formule à recopier telle quelle

Ce petit dessin bizarre s’appelle une fonction fléchée. Pour aujourd’hui, retenez seulement que c’est un paquet d’instructions à exécuter plus tard.

On l’étudiera pour de bon à la séance 9. En attendant, recopiez la forme :

element.addEventListener("click", () => {
  // votre code ici
});

Et surtout, n’oubliez pas la fin : }); — accolade, parenthèse, point-virgule.

AstuceAstuce anti-erreur

VS Code ferme automatiquement les parenthèses et les accolades. Écrivez donc la ligne complète d’abord, puis revenez placer votre code à l’intérieur. Et formatez avec Shift+Alt+F : si l’indentation part en biais, c’est qu’il manque une fermeture quelque part.

5. Le grand classique : le compteur

C’est l’exercice fondateur. Il combine tout ce que vous savez : une variable, un événement, une modification de la page.

Étape 3 — Compter les clics

seance05.html
<h2 id="score">0</h2>
<button id="plus">+1</button>
app.js
const score = document.querySelector("#score");
const plus = document.querySelector("#plus");

let compteur = 0;

plus.addEventListener("click", () => {
  compteur = compteur + 1;
  score.textContent = compteur;
});

Cliquez : le nombre monte. 🎉

ImportantLes 3 points à bien comprendre
  1. let compteur = 0; est à L’EXTÉRIEUR du addEventListener. Si on le mettait dedans, il serait remis à 0 à chaque clic et le compteur afficherait toujours 1.

  2. compteur = compteur + 1 : on lit l’ancienne valeur, on ajoute 1, on la remet dans la même boîte. (Raccourci courant : compteur++.)

  3. Deux choses différentes : compteur est la valeur en mémoire, et score.textContent est ce qui est affiché. Modifier la première ne met pas la seconde à jour toute seule : il faut explicitement recopier.

Exercice 5.2 — Le bouton -1

Ajoutez un deuxième bouton qui retire 1 au compteur.

seance05.html
<h2 id="score">0</h2>
<button id="plus">+1</button>
<button id="moins">-1</button>
app.js
const score = document.querySelector("#score");
const plus = document.querySelector("#plus");
const moins = document.querySelector("#moins");

let compteur = 0;

plus.addEventListener("click", () => {
  compteur = compteur + 1;
  score.textContent = compteur;
});

moins.addEventListener("click", () => {
  compteur = compteur - 1;
  score.textContent = compteur;
});

let compteur est déclaré une seule fois, et les deux écouteurs travaillent sur la même boîte.

Exercice 5.3 — Le bouton « remise à zéro »

Ajoutez un troisième bouton Reset qui remet le compteur à 0.

seance05.html
<button id="reset">Reset</button>
app.js
const reset = document.querySelector("#reset");

reset.addEventListener("click", () => {
  compteur = 0;
  score.textContent = compteur;
});

6. Changer aussi l’apparence

On peut modifier le style d’un élément depuis le JavaScript :

titre.style.color = "red";
titre.style.backgroundColor = "yellow";
AvertissementAttention aux noms qui changent

En CSS, on écrit background-color. En JavaScript, on écrit backgroundColor : le tiret disparaît et la lettre suivante devient une majuscule.

CSS JavaScript
color .style.color
background-color .style.backgroundColor
font-size .style.fontSize
text-align .style.textAlign

Et la valeur est toujours du texte : "20px", pas 20.

La méthode propre : changer de classe

Plutôt que de bricoler des styles un par un, on prépare une classe en CSS et on l’ajoute ou l’enlève depuis le JavaScript.

style.css
.alerte {
  color: white;
  background-color: #c0392b;
  padding: 12px;
  border-radius: 8px;
}
app.js
message.classList.add("alerte");    // met la classe
message.classList.remove("alerte"); // l'enlève
message.classList.toggle("alerte"); // l'ajoute si absente, l'enlève si présente
AstucePourquoi c’est mieux

Le style reste dans le fichier CSS, là où on le cherche. Le JavaScript ne fait que dire « cet élément est maintenant en alerte », sans se mêler des couleurs. Chaque fichier reste à sa place.

Exercice 5.4 — L’interrupteur

Faites un bouton Mode sombre qui, à chaque clic, bascule la page entre fond clair et fond sombre.

Indices : la classe s’applique sur document.body, et toggle est fait pour ça.

style.css
.sombre {
  background-color: #1e1e1e;
  color: #f0f0f0;
}
seance05.html
<button id="theme">Mode sombre</button>
app.js
const theme = document.querySelector("#theme");

theme.addEventListener("click", () => {
  document.body.classList.toggle("sombre");
});

document.body désigne directement la balise <body> : pas besoin de querySelector.

toggle fait le travail des deux : premier clic → ajoute, deuxième clic → enlève. Sans lui, il faudrait une condition… ce qu’on apprend à la séance 6 !

7. À toi de jouer

Exercice 5.5 — Prédire le résultat

Que se passe-t-il si on clique 3 fois sur le bouton ?

const affichage = document.querySelector("#affichage");
const bouton = document.querySelector("#bouton");

bouton.addEventListener("click", () => {
  let total = 0;
  total = total + 10;
  affichage.textContent = total;
});

L’affichage montre 10 après le premier clic… et 10 après le deuxième, et 10 après le troisième.

Pourquoi ? let total = 0; est à l’intérieur du addEventListener. La variable est donc recréée à zéro à chaque clic, puis on lui ajoute 10.

Pour que le total s’accumule, il faut sortir la variable :

let total = 0;

bouton.addEventListener("click", () => {
  total = total + 10;
  affichage.textContent = total;
});

C’est l’erreur la plus fréquente de cette séance. Retenez la question à se poser : « cette variable doit-elle survivre entre deux clics ? »

Exercice 5.6 — Le compteur de café ☕

Faites une page complète, cafe.html + cafe.css + cafe.js, qui affiche :

  • Un titre Compteur de cafés
  • Un grand nombre, au départ 0
  • Un bouton ☕ Encore un ! qui ajoute 1
  • Un bouton Remise à zéro
  • Un paragraphe qui affiche Coût total : X.XX € (un café = 1,10 €), mis à jour à chaque clic
cafe.html
<!DOCTYPE html>
<html lang="fr">
  <head>
    <meta charset="UTF-8" />
    <title>Compteur de cafés</title>
    <link rel="stylesheet" href="cafe.css" />
  </head>
  <body>
    <h1>Compteur de cafés</h1>

    <p id="nombre" class="grand">0</p>
    <p id="cout">Coût total : 0.00 €</p>

    <button id="ajouter">☕ Encore un !</button>
    <button id="reset">Remise à zéro</button>

    <script src="cafe.js"></script>
  </body>
</html>
cafe.css
body {
  font-family: system-ui, Arial, sans-serif;
  max-width: 700px;
  margin: 0 auto;
  padding: 24px;
  text-align: center;
}

.grand {
  font-size: 72px;
  font-weight: bold;
  color: #6f4e37;
  margin: 0;
}

button {
  font-size: 18px;
  padding: 10px 16px;
  margin: 4px;
  border-radius: 8px;
}
cafe.js
const nombre = document.querySelector("#nombre");
const cout = document.querySelector("#cout");
const ajouter = document.querySelector("#ajouter");
const reset = document.querySelector("#reset");

const PRIX_CAFE = 1.1;
let cafes = 0;

ajouter.addEventListener("click", () => {
  cafes = cafes + 1;
  nombre.textContent = cafes;
  cout.textContent = `Coût total : ${(cafes * PRIX_CAFE).toFixed(2)} €`;
});

reset.addEventListener("click", () => {
  cafes = 0;
  nombre.textContent = cafes;
  cout.textContent = "Coût total : 0.00 €";
});

Deux remarques :

  • PRIX_CAFE en majuscules : c’est une convention pour dire « cette valeur ne changera jamais ». Ça se voit tout de suite dans le code.
  • On répète les mêmes 3 lignes dans les deux boutons. Ça vous agace ? Tant mieux : c’est exactement le problème que les fonctions résolvent (séance 9).

8. Fiche mémo

Attraper un élément

const el = document.querySelector("#monId");
const el = document.querySelector(".maClasse");
const el = document.querySelector("h1");

Le modifier

el.textContent = "nouveau texte";
el.style.color = "red";
el.classList.add("alerte");
el.classList.remove("alerte");
el.classList.toggle("alerte");

Réagir à un clic

bouton.addEventListener("click", () => {
  // ce qu'il faut faire
});

Les 2 pièges

  • null dans la console → le sélecteur ne trouve rien, ou le <script> n’est pas en bas du <body>
  • Une variable déclarée dans l’écouteur est remise à zéro à chaque clic

9. Avant la prochaine séance