Le DOM est la carte. Chaque élément est un bâtiment. Chaque attribut est une adresse.
11.1 Sélection d'Éléments
Méthodes de Base
// Par ID (unique)
const titre = document.getElementById('titre-principal');
// Par classe (collection live)
const cameras = document.getElementsByClassName('camera');
// Par balise
const boutons = document.getElementsByTagName('button');
Méthodes Modernes (CSS Selectors)
// Premier élément correspondant
const camera = document.querySelector('.camera.active');
// Tous les éléments correspondants
const toutesCameras = document.querySelectorAll('.camera');
// Sélections complexes
const camActives = document.querySelectorAll('.camera.active:not(.offline)');
const premierLi = document.querySelector('ul > li:first-child');
11.2 Manipulation d'Éléments
Création
// Créer un élément
const nouvelleDiv = document.createElement('div');
nouvelleDiv.className = 'camera';
nouvelleDiv.textContent = 'Camera #1';
// Créer avec dataset
nouvelleDiv.dataset.id = 'cam-001';
nouvelleDiv.dataset.status = 'active';
Ajout au DOM
const container = document.getElementById('container');
// À la fin
container.appendChild(nouvelleDiv);
// Avant un élément
const reference = document.querySelector('.reference');
container.insertBefore(nouvelleDiv, reference);
// Positions précises
reference.insertAdjacentElement('beforebegin', nouvelleDiv); // Avant
reference.insertAdjacentElement('afterend', nouvelleDiv); // Après
Suppression
// Méthode moderne
element.remove();
// Ancienne méthode
parent.removeChild(element);
// Remplacer
parent.replaceChild(nouveau, ancien);
Clonage
const clone = element.cloneNode(true); // true = avec enfants
11.3 Modification de Contenu
Texte vs HTML
// Sécurisé (échappe le HTML)
element.textContent = '<script>alert("xss")</script>';
// Affiche: <script>alert("xss")</script>
// Dangereux (exécute le HTML)
element.innerHTML = '<strong>Nouveau</strong> contenu';
Classes
const el = document.querySelector('.camera');
el.classList.add('active', 'enregistrement');
el.classList.remove('offline');
el.classList.toggle('cache');
el.classList.contains('active'); // true/false
el.classList.replace('vieux', 'nouveau');
Attributs
// Standard
el.setAttribute('src', 'image.jpg');
const src = el.getAttribute('src');
el.removeAttribute('alt');
// Data attributes (recommandé)
el.dataset.cameraId = '123';
el.dataset.status = 'active';
console.log(el.dataset.cameraId); // '123'
Style (à éviter - utiliser des classes)
el.style.color = 'red';
el.style.backgroundColor = '#000';
el.style.display = 'none';
11.4 Parcours du DOM
Relations
const enfant = document.querySelector('.enfant');
// Parents
enfant.parentElement;
enfant.closest('.parent-selector'); // Le plus proche correspondant
// Enfants
parent.children; // Éléments seulement
parent.childNodes; // Tous les nœuds (texte, commentaires)
parent.firstElementChild;
parent.lastElementChild;
// Frères
enfant.previousElementSibling;
enfant.nextElementSibling;
11.5 Événements
Écouteur d'Événements
const bouton = document.querySelector('button');
function handleClick(event) {
console.log('Clic!', event.target);
event.preventDefault(); // Empêche comportement par défaut
}
bouton.addEventListener('click', handleClick);
bouton.removeEventListener('click', handleClick); // Même fonction requise
Délégation d'Événements (pour éléments dynamiques)
// Écouter sur un parent stable
document.addEventListener('click', (event) => {
if (event.target.matches('.btn-dynamique')) {
console.log('Bouton dynamique cliqué');
}
// Si le bouton a des enfants
const bouton = event.target.closest('.btn-dynamique');
if (bouton) {
console.log('Bouton trouvé via closest');
}
});
Événements Courants
// Souris
'click', 'dblclick', 'mousedown', 'mouseup', 'mousemove'
// Clavier
'keydown', 'keyup'
// Formulaire
'submit', 'change', 'input', 'focus', 'blur'
// Document
'DOMContentLoaded', 'load', 'resize', 'scroll'
Événements Personnalisés
// Créer
const event = new CustomEvent('alerte', {
detail: { message: 'Intrusion!' },
bubbles: true
});
// Déclencher
element.dispatchEvent(event);
// Écouter
element.addEventListener('alerte', (e) => {
console.log(e.detail.message);
});
11.6 Exemple Complet : Système de Surveillance
<div class="surveillance">
<div id="cameras"></div>
<button id="ajouter">Ajouter Caméra</button>
<div id="logs"></div>
</div>
class SurveillanceSystem {
constructor() {
this.cameras = [];
this.init();
}
init() {
this.container = document.getElementById('cameras');
this.btnAjouter = document.getElementById('ajouter');
this.logs = document.getElementById('logs');
this.btnAjouter.addEventListener('click', () => this.ajouterCamera());
// Délégation pour les boutons dynamiques
this.container.addEventListener('click', (e) => {
if (e.target.classList.contains('btn-remove')) {
this.supprimerCamera(e.target.closest('.camera'));
}
});
}
ajouterCamera() {
const id = this.cameras.length + 1;
// Créer l'élément
const camera = document.createElement('div');
camera.className = 'camera active';
camera.dataset.id = id;
// Contenu
camera.innerHTML = `
<h3>Camera ${id}</h3>
<p>Status: <span class="status">active</span></p>
<button class="btn-toggle">Toggle</button>
<button class="btn-remove">×</button>
`;
// Ajouter au DOM
this.container.appendChild(camera);
this.cameras.push(camera);
// Log
this.log(`Camera ${id} ajoutée`);
}
supprimerCamera(cameraEl) {
cameraEl.remove();
this.log(`Camera ${cameraEl.dataset.id} supprimée`);
}
log(message) {
const entry = document.createElement('div');
entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
this.logs.prepend(entry);
}
}
// Initialisation
document.addEventListener('DOMContentLoaded', () => {
new SurveillanceSystem();
});
Points Clés
- Sélection :
querySelector/querySelectorAll(moderne) - Création :
createElement+appendChild/insertAdjacentElement - Modification :
textContent(sécurisé),classList(classes),dataset(data-attrs) - Événements :
addEventListener+ délégation pour éléments dynamiques - Parcours :
parentElement,children,closest(),previous/nextElementSibling
Règle d'or : Pour les éléments dynamiques, utiliser la délégation d'événements.