Zum Inhalt springen

JavaScript: Das DOM traversieren

Das Traversieren des DOM (Document Object Model) ist eine grundlegende Fähigkeit für Webentwickler, die JavaScript verwenden. Wenn Sie das DOM-Traversieren beherrschen, können Sie Webseiten dynamisch manipulieren und interaktive sowie reaktionsfähige Benutzererlebnisse schaffen. Dieser Leitfaden bietet Ihnen ausführliche Erklärungen und mehrere Codebeispiele, damit Sie das Traversieren des DOM sicher beherrschen.

Einführung in das DOM-Traversieren

Das DOM stellt die Struktur einer Webseite als Baum aus Knoten dar. Jeder Knoten entspricht einem Element oder einem Inhaltsteil auf der Seite. Beim Traversieren des DOM bewegt man sich zwischen diesen Knoten, um auf Elemente zuzugreifen oder sie zu manipulieren.

Den DOM-Baum verstehen

Bevor Sie sich mit Traversierungs-Methoden beschäftigen, ist es wichtig, die Struktur des DOM-Baums zu verstehen. Hier ist ein einfaches HTML-Dokument zur Veranschaulichung:


html
<!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>

In diesem Dokument enthält das <code><body></code>-Element ein <code><div></code>` mit der `id` "container", das wiederum ein <code><p></code>``-Element und ein `` <code><ul></code> mit `<code><li></code>-Kindern enthält.

Grundlegende Traversierungs-Methoden

Auf Kindknoten zugreifen

Stellen Sie sich vor, Sie haben einen Blog mit mehreren Beiträgen, und jeder Beitrag hat Kommentare. Sie möchten die Kommentare für einen bestimmten Beitrag zählen.


html
<!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>

Dieser Code wählt das `` <div>mit der Klasse "comments" aus und zeigt die Anzahl der Kommentar-Elemente darin an. Hinweis:childrengibt nur Elementknoten zurück, währendchildNodesauch Text- und Kommentarknoten enthält. Für Traversierung nur über Elemente istchildren` die bessere Wahl.

Zu übergeordneten Knoten navigieren

Stellen Sie sich vor, Sie haben eine Liste von Artikeln in einem Warenkorb und möchten das Container-Element eines bestimmten Artikels finden.


html
<!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>

Dieser Code wählt das erste `` <li>-Element aus und zeigt den Tag-Namen seines übergeordneten Knotens an. Für die Navigation nur über Elemente wird oft parentElementgegenüberparentNodebevorzugt, da es Textknoten überspringt undnull` zurückgibt, wenn der Elternknoten kein Element ist.

Geschwisterknoten

Stellen Sie sich vor, Sie haben eine Aufgabenliste, in der Sie Aufgaben als erledigt markieren und dann zur nächsten Aufgabe wechseln können.


html
<!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>

Dieser Code stellt eine Aufgabenliste bereit, in der jede Aufgabe eine Schaltfläche „Complete Task“ hat. Wenn eine Aufgabe als erledigt markiert wird, wird der Text durchgestrichen und die Schaltfläche deaktiviert. Außerdem wird die Beschreibung der nächsten Aufgabe angezeigt. Wenn keine weiteren Aufgaben vorhanden sind, wird darauf hingewiesen, dass keine weiteren Aufgaben verfügbar sind. Ebenso überspringen previousElementSibling und nextElementSibling Textknoten, wodurch sie für die Traversierung nur über Elemente sicherer sind als previousSibling und nextSibling.

Erweiterte Traversierungs-Techniken

Elemente nach Klasse oder Tag finden

Stellen Sie sich vor, Sie erstellen ein Dashboard, das alle Benutzer auflistet, und Sie möchten alle Benutzerelemente finden und zählen.


html
<!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>

Dieser Code zählt die Anzahl der Elemente mit der Klasse user und zeigt sie an.

Query-Selector-Methoden

Stellen Sie sich vor, Sie haben eine Nachrichtenseite und möchten alle Überschriften hervorheben.


html
<!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>

Dieser Code wählt alle Elemente mit der Klasse headline aus, ändert ihre Farbe auf Rot und zeigt die Anzahl dieser Elemente an.

Traversieren mit rekursiven Funktionen

Lassen Sie uns ein praxisnahes Beispiel für rekursive Traversierung erstellen. Wir verwenden als Beispiel ein verschachteltes Kommentarsystem, bei dem jeder Kommentar Antworten haben kann.


html
<!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>

Dieser Code stellt ein verschachteltes Kommentarsystem mit Kommentaren und Antworten dar. Die Funktion traverseComments durchläuft rekursiv jeden Kommentar und jede Antwort und zeigt deren Textinhalt an. Die verschachtelte Struktur ermöglicht Antworten auf Antworten und demonstriert damit einen realen Anwendungsfall rekursiver Traversierung. Fügen Sie am Anfang rekursiver Funktionen immer eine Prüfung auf null/undefined ein, um Fehler zu vermeiden, wenn der anfängliche Selektor nichts zurückgibt.

Praktische Beispiele

Diese Beispiele kombinieren DOM-Traversierung mit gängigen Manipulationstechniken, um reale Arbeitsabläufe zu demonstrieren.

Eine dynamische To-do-Liste erstellen

Stellen Sie sich vor, Sie haben eine To-do-Liste, in die Benutzer neue Aufgaben hinzufügen können.


html
<!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>

Dieser Code ermöglicht es Benutzern, einer To-do-Liste neue Aufgaben hinzuzufügen, indem sie Text in ein Eingabefeld eingeben und auf eine Schaltfläche klicken.

Elementeigenschaften aktualisieren

Stellen Sie sich vor, Sie haben eine Produktliste und möchten Produkte beim Anklicken als „Favorit“ markieren.


html
<!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>

Dieser Code ermöglicht es Benutzern, Produkte durch Anklicken als „Favorit“ zu markieren und ihr Erscheinungsbild mithilfe einer favorite-Klasse zu ändern.

INFO

Minimieren Sie den DOM-Zugriff, um die Leistung zu verbessern. Fassen Sie DOM-Manipulationen zusammen, um Reflows und Repaints zu reduzieren.

Fazit

Das Beherrschen des DOM-Traversierens ist entscheidend für die Erstellung dynamischer, interaktiver Webanwendungen. Wenn Sie die verschiedenen Methoden und Techniken zum Navigieren und Manipulieren des DOM verstehen und nutzen, können Sie Benutzererlebnisse verbessern und die Funktionalität Ihrer Webprojekte steigern.

Practice

Welche der folgenden Methoden können verwendet werden, um das DOM in JavaScript zu traversieren?

Finden Sie das nützlich?

Dual-run-Vorschau — vergleichen Sie mit den Symfony-Routen live.