Le DOM vu de JavaScript
window, document, querySelector et modification du DOM.
Objectifs
À la fin de cette leçon, vous saurez :
- situer window et document dans l'environnement navigateur ;
- sélectionner des éléments avec
querySelector(All)en réutilisant vos sélecteurs CSS ; - modifier contenu, attributs, classes — en respectant la séparation JS/CSS ;
- créer et insérer des éléments dynamiquement.
🔗 Pour vous rafraîchir la mémoire : du HTML aux pixels
La scène : ce que le navigateur donne à votre JavaScript
Quand votre page charge un script, le navigateur lui fournit un environnement riche dont deux objets globaux structurent tout :
window → la fenêtre elle-même : dimensions, alert(), localStorage,
setTimeout... Tout le global vit dedans.
document → LA PAGE CHARGÉE : la porte d'entrée vers le DOM.
Souvenez-vous du chapitre 15 : le DOM est l'arbre d'objets construit par le parseur. Votre code ne touche jamais aux fichiers HTML : il lit et modifie CET ARBRE, puis le moteur relance layout/paint pour refléter les changements. Le cycle complet :
votre script modifie le DOM → le navigateur recalcule → les pixels changent
Testez immédiatement en console (F12) sur n'importe quelle page :
window.innerWidth // largeur de la fenêtre
document.title // le titre de l'onglet
document.body // l'élément body, objet complet
Sélectionner : querySelector réutilise VOS connaissances CSS
L'API de sélection prend des sélecteurs CSS complets — tout le chapitre CSS redevient utile :
<h1 id="titre">Mon site</h1>
<p class="intro">Bienvenue.</p>
<ul id="liste"><li>Un</li><li>Deux</li></ul>
document.querySelector("#titre"); // premier correspondant
document.querySelector(".intro");
document.querySelector("nav a.actif"); // sélecteurs composés acceptés !
document.querySelectorAll("#liste li"); // TOUS les résultats (NodeList)
Deux API jumelles à distinguer :
| Renvoie | Si rien trouvé | |
|---|---|---|
querySelector | LE premier élément | null |
querySelectorAll | une NodeList (itérable avec for...of) | NodeList vide |
Le null est le piège quotidien du DOM :
document.querySelector("#inexistant").textContent = "x";
// TypeError: Cannot set properties of null
Vous reconnaissez l'erreur du chapire débogage ! Le réflexe défensif systématique :
const el = document.querySelector("#inexistant");
if (el) {
el.textContent = "x";
}
Modifier : contenu, attributs, classes
const titre = document.querySelector("#titre");
titre.textContent = "Nouveau titre"; // texte pur (sécuritaire)
titre.setAttribute("lang", "fr"); // attribut quelconque
titre.classList.add("actif"); // classe : add / remove / toggle
titre.style.color = "navy"; // style direct (usage ponctuel)
Précisions qui comptent :
- préférez
textContentàinnerHTMLpour du texte : innerHTML interprète le HTML reçu (risque XSS si la valeur vient de l'utilisateur — chapitre sécurité) ; - préférez
classListaux manipulations directes declassName: add/remove/toggle sont lisibles et composables ; - la règle d'architecture : le style se gère dans le CSS ; JS se contente d'ajouter/retirer des CLASSES.
element.style.xreste réservé aux valeurs calculées dynamiquement.
/* côté CSS */
.titre-actif { color: crimson; border-bottom: 2px solid; }
/* côté JS */
titre.classList.toggle("titre-actif"); // on/off : le style vit dans styles.css
Créer et insérer
Trois gestes toujours identiques : créer un élément détaché, le remplir, l'accrocher dans l'arbre :
const li = document.createElement("li"); // 1. créé HORS de la page
li.textContent = "Trois"; // 2. rempli
document.querySelector("#liste").appendChild(li); // 3. accroché → apparaît
Entre les gestes 1 et 3, l'élément existe en mémoire sans être affiché — c'est ce qui permet de le construire complètement avant l'insertion. Vous utiliserez cette triade en boucle dans le défi final du chapitre.
Exercice
- Sur votre CV, en console : changez le h1, ajoutez une classe au header, vérifiez visuellement.
- Écrivez
document.title += " — brouillon"et observez l'onglet. - Créez dynamiquement une
<ul>de vos trois commandes terminal préférées (createElement × 4). - Que renvoie
document.querySelector("#inexistant")? EtquerySelectorAll("#inexistant")? Testez AVANT de répondre. - Comptez les mots de tous vos paragraphes avec querySelectorAll + for...of + split.
Résumé
- window = fenêtre/globals ; document = porte d'entrée du DOM.
- querySelector(All) réutilise les sélecteurs CSS ; null possible → testez.
- Modifier = textContent / setAttribute / classList ; le style vit en CSS.
- Créer = createElement → remplir → appendChild.
Correction disponibleCherchez d’abord par vous-même.Voir la correction
Correction
Réponses détaillées
Question 4. querySelector("#inexistant") renvoie null (rien trouvé). Mais querySelectorAll renvoie une NodeList vide — un objet valide, itérable, simplement sans élément dedans. Conséquence pratique opposée : le premier exige un test avant usage, le second se boucle sans danger (for (const el of rien) ne fait juste rien). Cette asymétrie explique beaucoup de TypeError mystérieuses chez les débutants.
Question 5.
let total = 0;
for (const p of document.querySelectorAll("p")) {
total += p.textContent.split(/\s+/).filter(Boolean).length;
}
console.log(total);
Ingrédients connus : accumulateur, parcours, split vu au chapitre chaînes. Vous venez d'écrire un mini-analyseur de page en six lignes — c'est exactement ce genre de script que la console permet de prototyper en trente secondes.
Piège fréquent observé
Sélectionner AVANT que la page ne soit prête : un script placé dans <head> s'exécute avant que le body existe → querySelector renvoie null partout. Solutions : placer le <script> en fin de body (faites-le dès maintenant), ou attendre DOMContentLoaded. Symptôme reconnaissable entre mille : « mon script marche depuis la console mais pas depuis le fichier ».