Le DOM : comprendre l'arbre et sélectionner des éléments

Première leçon du cours DOM et événements, en accès libre : environ 15 minutes, 3 exercices et 3 questions de quiz. C'est la leçon de base du catalogue ; dans l'espace étudiant, elle est réécrite pour ton profil.

Objectifs

  • Expliquer ce qu'est le DOM et son lien avec le HTML
  • Charger un script au bon moment (defer, type="module")
  • Sélectionner des éléments avec querySelector et querySelectorAll

Arbre du DOMSélection d'éléments

Quand le navigateur charge une page, il lit le HTML et construit en mémoire un arbre d’objets : le DOM (Document Object Model). Chaque balise devient un objet élément, avec des propriétés et des méthodes. JavaScript peut lire et modifier cet arbre ; le navigateur met alors l’affichage à jour automatiquement.

<body>
  <h1>Boutique</h1>
  <ul class="produits">
    <li class="produit" data-id="12">Sac <span class="prix">59 €</span></li>
    <li class="produit" data-id="15">Gourde <span class="prix">12 €</span></li>
  </ul>
</body>

Ici, body a deux enfants (h1 et ul), ul a deux enfants li, etc. L’onglet Éléments de l’inspecteur montre exactement cet arbre, dans son état actuel (y compris les modifications faites par JavaScript), alors que « Afficher le code source » montre le HTML d’origine.

Charger le script au bon moment

Un script ne peut manipuler que des éléments déjà construits. La solution moderne :

<head>
  <script src="app.js" defer></script>         <!-- exécuté après l'analyse du HTML -->
  <!-- ou -->
  <script type="module" src="app.js"></script> <!-- les modules sont différés par défaut -->
</head>

Sans defer ni type="module", un script placé dans le <head> s’exécute avant que le <body> existe : vos sélections renverront null.

Sélectionner avec les sélecteurs CSS

Vous connaissez déjà les sélecteurs CSS : ils servent aussi en JavaScript.

// premier élément correspondant, ou null s'il n'y en a pas
const titre = document.querySelector("h1");
const liste = document.querySelector(".produits");
const sac = document.querySelector('[data-id="12"]');

// tous les éléments correspondants : une NodeList
const produits = document.querySelectorAll(".produit");
console.log(produits.length);            // 2

for (const p of produits) {              // une NodeList se parcourt avec for...of
  console.log(p.textContent);
}
produits.forEach(p => console.log(p.dataset.id));  // ou forEach

// pour utiliser map/filter, on convertit en vrai tableau
const ids = [...produits].map(p => p.dataset.id);  // ["12", "15"]

La NodeList renvoyée par querySelectorAll est statique : elle ne se met pas à jour si on ajoute des éléments ensuite. Il faut refaire la sélection.

document.getElementById("panier") reste courant pour un id (sans le #). Les anciennes méthodes getElementsByClassName renvoient des collections « vivantes » au comportement plus surprenant : préférez querySelectorAll.

Chercher dans un élément et naviguer

const premier = document.querySelector(".produit");
premier.querySelector(".prix");     // cherche seulement à l'intérieur de ce li

premier.parentElement;              // le <ul>
premier.children;                   // ses éléments enfants
premier.nextElementSibling;         // le li suivant
premier.closest("ul");              // l'ancêtre le plus proche qui correspond (ou lui-même)
premier.matches(".produit");        // true : l'élément correspond-il au sélecteur ?

closest sera très utile pour les événements, dans la leçon sur la délégation.

Prévoir l’absence

const banniere = document.querySelector(".banniere-promo");
if (banniere) {
  banniere.hidden = false;
}
// ou avec le chaînage optionnel pour une lecture :
const texte = document.querySelector(".slogan")?.textContent ?? "";

Appeler une méthode sur null provoque l’erreur classique Cannot read properties of null. Si vous la voyez, vérifiez votre sélecteur (faute de frappe, point oublié devant une classe) et le moment de chargement du script.

Tester dans la console

Ouvrez la console du navigateur sur n’importe quelle page et tapez document.querySelectorAll("a").length : vous venez d’interroger le DOM. C’est le meilleur terrain de jeu pour expérimenter.

Exercices

Les solutions et les tests restent sur le serveur. Dans l'espace étudiant, ton code est exécuté et corrigé, et le tuteur donne des indices avant la solution.

  1. CodeDifficulté 1JavaScript dans le navigateur2 indices

    Construire un sélecteur CSS

    Logique pure (sans DOM) : écrivez construireSelecteur({ tag, id, classes }) qui renvoie le sélecteur CSS correspondant. Tous les champs sont facultatifs ; l’ordre est balise, puis #id, puis les classes préfixées par un point. Exemple : { tag: "li", classes: ["produit", "promo"] } donne "li.produit.promo".

    function construireSelecteur({ tag = "", id, classes = [] } = {}) {
      // votre code
    }
  2. CodeDifficulté 2Page HTML dans le navigateur2 indices

    Sélectionner et compter

    Dans le script : sélectionnez tous les .produit, puis écrivez dans #compteur le texte "3 produits" (le nombre doit être calculé). Ajoutez ensuite la classe promo-visible à chaque produit qui contient un élément .promo.

    <p id="compteur"></p>
    <ul>
      <li class="produit">Sac <span class="promo">-20 %</span></li>
      <li class="produit">Gourde</li>
      <li class="produit">Lampe <span class="promo">-10 %</span></li>
    </ul>
    <script>
      // votre code
    </script>
  3. QCMDifficulté 11 indice

    Résultat d'une sélection vide

    Que renvoie document.querySelector(".inexistant") ?

    • Une NodeList vide
    • null
    • undefined

Quiz de fin de leçon

  1. Pourquoi ajouter defer à une balise

    • Pour charger le script plus tard dans la journée
    • Pour l'exécuter après l'analyse complète du HTML
    • Pour le rendre asynchrone vis-à-vis du serveur
  2. Comment appliquer map à une NodeList ?

    • liste.map(...)
    • [...liste].map(...)
    • liste.toArray().map(...)
  3. Que fait element.closest(“.carte”) ?

    • Renvoie l'enfant .carte le plus proche
    • Renvoie l'élément lui-même ou son ancêtre le plus proche qui correspond
    • Renvoie le voisin suivant

La suite du cours

  1. Modifier le DOM : contenu, classes, attributs et création d'éléments20 min
  2. Écouter les événements20 min
  3. Propagation et délégation d'événements15 min
  4. Formulaires, état de l'interface et stockage local20 min

DOM et événements · Intermédiaire · 3 h 30