Traverser le DOM en JavaScript
La traversée du DOM (Document Object Model) est une compétence fondamentale pour les développeurs web utilisant JavaScript. Maîtriser la traversée du DOM vous permettra de manipuler les pages web de manière dynamique, en créant des expériences utilisateur interactives et réactives. Ce guide vous fournira des explications détaillées et de nombreux exemples de code pour vous aider à devenir compétent en traversée du DOM.
Introduction à la traversée du DOM
Le DOM représente la structure d’une page web sous forme d’arbre de nœuds. Chaque nœud correspond à un élément ou à un morceau de contenu de la page. Traverser le DOM consiste à se déplacer entre ces nœuds pour accéder aux éléments ou les manipuler.
Comprendre l’arbre DOM
Avant de plonger dans les méthodes de traversée, il est crucial de comprendre la structure de l’arbre DOM. Voici un document HTML simple pour l’illustrer :
<!DOCTYPE html>
<html>
<head>
<title>DOM Traversal Example</title>
</head>
<body>
<div id="container">
<p class="text">Hello, World!</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
</body>
</html>Dans ce document, l’élément <code><body></code> contient un <code><div></code> avec un id de "container", qui contient à son tour un élément <code><p></code> et un <code><ul></code> avec des enfants `` <li>`.
Méthodes de traversée de base
Accéder aux nœuds enfants
Imaginez que vous avez un blog avec plusieurs articles, et que chaque article a des commentaires. Vous voulez compter les commentaires d’un article spécifique.
<!DOCTYPE html>
<html>
<head>
<title>Accessing Child Nodes</title>
</head>
<body>
<div id="blog-post">
<h2>Blog Post Title</h2>
<p>Some interesting content...</p>
<div class="comments">
<p>Comment 1</p>
<p>Comment 2</p>
<p>Comment 3</p>
</div>
</div>
<script>
const commentsContainer = document.querySelector('.comments');
const comments = commentsContainer.children; // Only includes element nodes
// Display the number of comments
console.log(`Number of comments: ${comments.length}`);
</script>
</body>
</html>Ce code sélectionne le <code><div></code> avec la classe "comments" et affiche le nombre d’éléments de commentaire qu’il contient. Remarque : children ne renvoie que les nœuds éléments, tandis que childNodes inclut les nœuds texte et commentaire. Pour une traversée limitée aux éléments, préférez children.
Naviguer vers les nœuds parents
Imaginez que vous avez une liste d’articles dans un panier d’achat et que vous voulez trouver l’élément conteneur d’un article spécifique.
<!DOCTYPE html>
<html>
<head>
<title>Navigating to Parent Nodes</title>
</head>
<body>
<div id="shopping-cart">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
<script>
const cartItem = document.querySelector('li');
const parent = cartItem.parentNode;
// Display the parent node
console.log(`The parent of the first cart item is a: ${parent.tagName}`);
</script>
</body>
</html>Ce code sélectionne le premier élément <code><li></code> et affiche le nom de balise de son nœud parent. Pour une navigation limitée aux éléments, parentElement est souvent préférable à parentNode, car il ignore les nœuds texte et renvoie null si le parent n’est pas un élément.
Nœuds frères
Imaginez que vous avez une liste de tâches où vous pouvez marquer les tâches comme terminées, puis passer à la tâche suivante..
<!DOCTYPE html>
<html>
<head>
<title>Task List Navigation</title>
<style>
.task {
margin: 10px;
padding: 10px;
border: 1px solid #ccc;
}
.completed {
text-decoration: line-through;
color: gray;
}
</style>
</head>
<body>
<div class="task-list">
<div class="task">
<p>Task 1: Do the laundry</p>
<button class="complete-task">Complete Task</button>
</div>
<div class="task">
<p>Task 2: Buy groceries</p>
<button class="complete-task">Complete Task</button>
</div>
<div class="task">
<p>Task 3: Clean the house</p>
<button class="complete-task">Complete Task</button>
</div>
</div>
<script>
document.querySelectorAll('.complete-task').forEach(button => {
button.addEventListener('click', () => {
const task = button.parentElement;
task.classList.add('completed');
button.disabled = true;
const nextTask = task.nextElementSibling;
if (nextTask) {
console.log(`Next task: ${nextTask.querySelector('p').textContent}`);
} else {
console.log('No more tasks available');
}
});
});
</script>
</body>
</html>Ce code fournit une liste de tâches où chaque tâche possède un bouton "Complete Task". Lorsqu’une tâche est marquée comme terminée, son texte est barré et le bouton est désactivé. Il affiche également la description de la tâche suivante. S’il n’y a plus de tâches, il indique qu’il n’y en a plus. De même, previousElementSibling et nextElementSibling ignorent les nœuds texte, ce qui les rend plus sûrs pour une traversée limitée aux éléments que previousSibling et nextSibling.
Techniques avancées de traversée
Trouver des éléments par classe ou par balise
Imaginez que vous créez un tableau de bord qui répertorie tous les utilisateurs et que vous voulez trouver et compter tous les éléments utilisateur.
<!DOCTYPE html>
<html>
<head>
<title>Finding Elements by Class or Tag</title>
</head>
<body>
<div class="user">User 1</div>
<div class="user">User 2</div>
<div class="user">User 3</div>
<script>
const users = document.getElementsByClassName('user');
// Display the number of users
console.log(`Number of users: ${users.length}`);
</script>
</body>
</html>Ce code compte et affiche le nombre d’éléments ayant la classe user.
Méthodes de sélecteur de requête
Imaginez que vous avez un site d’actualités et que vous voulez mettre en évidence tous les titres.
<!DOCTYPE html>
<html>
<head>
<title>Query Selector Methods</title>
</head>
<body>
<div id="news">
<h1 class="headline">Headline 1</h1>
<h1 class="headline">Headline 2</h1>
<h1 class="headline">Headline 3</h1>
</div>
<script>
const headlines = document.querySelectorAll('.headline');
// Highlight all headlines
headlines.forEach(headline => {
headline.style.color = 'red';
});
// Display the number of headlines
console.log(`Number of headlines: ${headlines.length}`);
</script>
</body>
</html>Ce code sélectionne tous les éléments avec la classe headline, change leur couleur en rouge et affiche le nombre de ces éléments.
Traverser à l’aide de fonctions récursives
Créons un exemple concret de traversée récursive. Nous utiliserons un système de commentaires imbriqués comme exemple, où chaque commentaire peut avoir des réponses.
<!DOCTYPE html>
<html>
<head>
<title>Recursive Traversal</title>
<style>
.comment {
margin: 10px;
padding: 10px;
border: 1px solid #ccc;
}
.reply {
margin-left: 20px;
border-left: 2px solid #aaa;
}
</style>
</head>
<body>
<div class="comments">
<div class="comment">
<p>Comment 1</p>
<div class="reply">
<p>Reply 1-1</p>
<div class="reply">
<p>Reply 1-1-1</p>
</div>
</div>
<div class="reply">
<p>Reply 1-2</p>
</div>
</div>
<div class="comment">
<p>Comment 2</p>
<div class="reply">
<p>Reply 2-1</p>
</div>
</div>
</div>
<script>
function traverseComments(node) {
if (!node) return; // Guard against null/undefined
if (node.nodeType === Node.ELEMENT_NODE && node.classList.contains('comment')) {
console.log(`Comment: ${node.querySelector('p').textContent}`);
}
if (node.nodeType === Node.ELEMENT_NODE && node.classList.contains('reply')) {
console.log(`Reply: ${node.querySelector('p').textContent}`);
}
for (let i = 0; i < node.childNodes.length; i++) {
traverseComments(node.childNodes[i]);
}
}
traverseComments(document.querySelector('.comments'));
</script>
</body>
</html>Ce code représente un système de commentaires imbriqués avec des commentaires et des réponses. La fonction traverseComments parcourt récursivement chaque commentaire et chaque réponse, en affichant leur contenu textuel. La structure imbriquée permet des réponses aux réponses, démontrant un cas d’utilisation réel de la traversée récursive. Incluez toujours une vérification de null/undefined au début des fonctions récursives afin d’éviter les erreurs lorsque le sélecteur initial ne renvoie rien.
Exemples pratiques
Ces exemples combinent la traversée du DOM avec des techniques de manipulation courantes pour illustrer des flux de travail réels.
Créer une liste de tâches dynamique
Imaginez que vous avez une liste de tâches où les utilisateurs peuvent ajouter de nouvelles tâches.
<!DOCTYPE html>
<html>
<head>
<title>Dynamic To-Do List</title>
<style>
.info { color: darkgreen; }
</style>
</head>
<body>
<div id="todo-list">
<h2>To-Do List</h2>
<ul id="tasks">
<li>Task 1</li>
<li>Task 2</li>
</ul>
<input type="text" id="task-input" placeholder="Add a new task" />
<button id="add-button">Add Task</button>
</div>
<script>
const tasks = document.getElementById('tasks');
const input = document.getElementById('task-input');
const button = document.getElementById('add-button');
button.addEventListener('click', () => {
const newTask = input.value.trim();
if (newTask) {
const li = document.createElement('li');
li.textContent = newTask;
tasks.appendChild(li);
input.value = '';
console.log('Added new task to the to-do list');
}
});
</script>
</body>
</html>Ce code permet aux utilisateurs d’ajouter de nouvelles tâches à une liste de tâches en saisissant du texte dans un champ de saisie et en cliquant sur un bouton.
Mettre à jour les attributs d’un élément
Imaginez que vous avez une liste de produits et que vous voulez marquer les produits comme "favoris" lorsqu’ils sont cliqués.
<!DOCTYPE html>
<html>
<head>
<title>Updating Element Attributes</title>
<style>
.favorite { font-weight: bold; color: gold; }
.info { color: darkblue; }
</style>
</head>
<body>
<h4>Click on the list item below to see the result!</h4>
<ul id="product-list">
<li>Product 1</li>
<li>Product 2</li>
<li>Product 3</li>
</ul>
<script>
const productList = document.getElementById('product-list');
productList.addEventListener('click', (event) => {
if (event.target.tagName === 'LI') {
event.target.classList.toggle('favorite');
console.log(`Toggled favorite status for: ${event.target.textContent}`);
}
});
</script>
</body>
</html>Ce code permet aux utilisateurs de marquer des produits comme "favoris" en cliquant dessus, en modifiant leur apparence à l’aide d’une classe favorite.
INFO
Réduisez au minimum l’accès au DOM pour améliorer les performances. Regroupez les manipulations du DOM afin de réduire les reflows et les repaints.
Conclusion
Maîtriser la traversée du DOM est essentiel pour créer des applications web dynamiques et interactives. En comprenant et en utilisant les différentes méthodes et techniques de navigation et de manipulation du DOM, vous pouvez améliorer l’expérience utilisateur et la fonctionnalité de vos projets web.
Practice
Which of the following methods can be used to traverse the DOM in JavaScript?