Même à l'ère des frameworks comme React et Vue, une compréhension solide de la manipulation directe du DOM reste une compétence indispensable. C'est le cœur de ce que font les frameworks en coulisses, la base pour construire des Web Components, et la seule approche pour les projets en JavaScript pur (vanilla JS). Les API DOM modernes sont étonnamment puissantes et élégantes, vous permettant de réaliser des interfaces dynamiques sans dépendances externes complexes comme jQuery.

Sélectionner des Éléments du DOM

Sélecteurs Modernes et Efficaces
// Pour un élément unique
const entete = document.querySelector('.header');
const boutonSoumission = document.getElementById('submit-btn');
const premierArticle = document.querySelector('article:first-of-type');

// Pour plusieurs éléments (retourne une NodeList)
const cartes = document.querySelectorAll('.card');
const liensNav = document.querySelectorAll('nav a');

// Itérer sur une NodeList
cartes.forEach(carte => {
  carte.classList.add('charge');
});

// Convertir en tableau pour utiliser toutes les méthodes Array
const tableauCartes = [...document.querySelectorAll('.card')];
const cartesVisibles = tableauCartes.filter(c => !c.hidden);

Modifier les Éléments du DOM

Contenu, Attributs et Classes CSS
const el = document.querySelector('.hero-title');

// Contenu textuel (sécurisé — pas d'injection HTML)
el.textContent = 'Bonjour, Monde!';

// Contenu HTML (⚠️ Risque XSS avec les entrées utilisateur)
el.innerHTML = '<strong>Bonjour</strong>, Monde!';

// Attributs
el.setAttribute('role', 'heading');
el.getAttribute('data-id');
el.removeAttribute('hidden');

// Dataset (attributs data-*)
el.dataset.userId = '123';    // Définit data-user-id="123"
console.log(el.dataset.userId); // "123"

// Classes CSS
el.classList.add('active', 'visible');
el.classList.remove('chargement');
el.classList.toggle('mode-sombre');
el.classList.contains('active');  // true/false
el.classList.replace('ancienne-classe', 'nouvelle-classe');

// Styles en ligne
el.style.color = '#6366f1';
el.style.setProperty('--accent', '#22d3ee');

Créer et Insérer des Éléments Dynamiquement

Création Dynamique d'Éléments
// Créer un nouvel élément
const carte = document.createElement('div');
carte.className = 'card';
carte.innerHTML = `
  <h3>${titre}</h3>
  <p>${description}</p>
`;

// Insérer dans le DOM
contenant.appendChild(carte);                    // À la fin
contenant.prepend(carte);                        // Au début
contenant.insertBefore(carte, elementReference); // Avant un élément spécifique

// Méthodes d'insertion modernes
element.before(nouvelElement);    // Avant l'élément
element.after(nouvelElement);     // Après l'élément
element.replaceWith(nouvelElement); // Remplace l'élément

// Supprimer du DOM
element.remove();

// Cloner un élément existant
const clone = modele.cloneNode(true); // true = clone en profondeur

Gérer les Événements du DOM

Utilisation de `addEventListener`
const bouton = document.querySelector('#submit');

// Ajouter un écouteur d'événement
bouton.addEventListener('click', (event) => {
  event.preventDefault();
  console.log('Cliqué!', event.target);
});

// Supprimer un écouteur d'événement (doit utiliser une fonction nommée)
function gererClic(e) { /* ... */ }
bouton.addEventListener('click', gererClic);
bouton.removeEventListener('click', gererClic);

// Événements courants
element.addEventListener('click', gestionnaire);        // Clic de souris
element.addEventListener('input', gestionnaire);        // Changements en temps réel dans les champs de saisie
element.addEventListener('change', gestionnaire);       // La saisie perd le focus
element.addEventListener('submit', gestionnaire);       // Soumission de formulaire
element.addEventListener('keydown', gestionnaire);      // Touche pressée
element.addEventListener('scroll', gestionnaire);       // Défilement
element.addEventListener('load', gestionnaire);         // Ressource chargée

Délégation d'Événements

Au lieu d'attacher un écouteur d'événement à chaque élément enfant, il est souvent plus performant et plus flexible d'ajouter un seul écouteur au parent. Vous pouvez ensuite utiliser la propriété event.target pour déterminer quel enfant spécifique a déclenché l'événement. Cette approche est particulièrement utile pour les listes dynamiques où de nouveaux éléments sont ajoutés ou supprimés du DOM.

Modèle de Délégation d'Événements
// ❌ Mauvaise pratique — un écouteur par élément
document.querySelectorAll('.card').forEach(carte => {
  carte.addEventListener('click', gererClicCarte);
});

// ✅ Bonne pratique — un seul écouteur sur le conteneur parent
document.querySelector('.card-grid').addEventListener('click', (e) => {
  const carte = e.target.closest('.card');
  if (!carte) return; // Le clic n'était pas sur une carte

  const id = carte.dataset.id;
  gererClicCarte(id);
});

L'Élément `