Geschrieben von

JavaScript: DOM

WebDev

Definition

In meinem Artikel “Wie Webseiten geladen werden” bin ich neben der Client-Server-Kommunikation auch auf die Darstellung der HTML-Seite im Browser eingegangen. Sobald das HTML-Dokument beim Browser angekommen ist, muss es analysiert bzw. verarbeitet werden. Dieser Vorgang wird “Parsing” genannt und wird vom “Parser” übernommen. “Parsing” und “Parser” kommen aus dem Englischen “parse” und bedeuten, dass etwas in seine Einzelteile zerlegt wird. Hauptaufgabe des Parsers ist es, den HTML-Code in eine Objektstruktur umzuwandeln. Die Objektstruktur besteht aus verschiedenen Knoten, die miteinander verschachtelt sind. Durch diese Verschachtelung entsteht die sogenannte Baumstruktur, was letztendlich auch das Document Object Model (DOM) darstellt.

Das DOM wird im Arbeitsspeicher abgelegt und es kann nun darauf zugegriffen werden. Für alle CSS- und JavaScript-Operationen nutzt nun der Browser das DOM und arbeitet sich durch die Baumstruktur. Dies ist viel einfacher als auf Elemente eines unstrukturierten HTML-Dokuments zuzugreifen. Um dies zu verdeutlichen, kann man sich HTML-Code und DOM wie folgt selbst anschauen:

  • HTML-Code: Mit Strg+U oder mit rechter Maustaste und dann auf “Seitenquelltext anzeigen” (am Beispiel von Chrome; Wording kann bei anderen Browsern anders sein) klicken
  • DOM: F12 oder mit rechter Maustaste und dann auf “Untersuchen” klicken (Reiter “Elements”)

Während das HTML aus einer Code-Wüste besteht, hat man im DOM die Möglichkeit mittels der kleinen Pfeile, immer links der HTML-Tags (Knoten genannt), diese auf- und zuzuklappen. So kann man sich durch die Baumstruktur durchklicken. Würde man diese Struktur grafisch darstellen, hätte man folgendes Bild:

Aufbau

Wie man oben am Screenshot sehen kann ähnelt der Aufbau einen Baum, weshalb man beim DOM auch von einer Baumstruktur oder einem Verzeichnisbaum spricht. Dieser besteht aus einzelnen Knoten (Nodes). Die Knoten sind im Screenshot oben die einzelnen Kästen. Dabei ist jeder Knoten ein Objekt (node-Objekt), der einen Teil des Dokuments repräsentiert.

Grundsätzlich lässt sich der DOM-Aufbau über die Beziehungsarten der Knoten und der Knotentypen charakterisieren.

Beziehungsarten

  • Wurzelknoten (root): Bei einer Tabelle wäre table der Wurzelknoten.
  • Elternknoten (parent): table wäre zudem der Elternknoten von thead und tbody.
  • Kindknoten (children): Die 2 Elemente thead und tbody wären wiederum Kindknoten von table.

Knotentypen

  • Dokumentknoten: Dieser (document) stellt die komplette Baumstruktur dar.
  • Elementknoten: Dieser entspricht einem HTML-Elemente (z.B. body oder head).
  • Attributknoten: Dieser entspricht einem HTML-Attribut (z.B. das Attribut src innerhalb des img-Tags)
  • Textknoten: Dieser entspricht einem Textinhalt (z.B. die Text-Überschrift von H1)
  • Kommentare: Kommentare sind keine Textknoten, sondern stellen einen eigenen Knotentyp dar.

Zugriff auf das DOM

Es gibt nun verschiedene Methoden, um auf das DOM zuzugreifen und folgende Aufgaben durchzuführen:

  • Lesen bzw. Auswählen
  • Hinzufügen bzw. Erstellen
  • Löschen

Lesen bzw. Auswählen

Hierzu zählen folgende Methoden:

  • Über die Anweisung document
  • Über getElement-Methoden
  • Über querySelector-Methoden

Dies werden wir nun nachfolgend etwas genauer anschauen. Für die Praxisbeispiele dient uns dabei folgender Ausgangscode:

<html>
<head>
<title>Seitentitel</title>
</head>
<body>
<div id="div1">
<h1>Überschrift 1</h1>
<p class="absatz">Hallo und Willkommen auf der Webseite!</p>
</div>
</body>
</html>

document

Mit document können wir initial auf die gesamte Baum-Struktur zugreifen. In der Console bekommen wir dann:

Auf die jeweiligen Kinderelemente können wir dann mittels document.children zugreifen:

Wollen wir nun tiefer eintauchen, so müssen wir auf das Array mittels document.children[0] zugreifen und würden folgendes in der Console bekommen:

Um mittels dieser Methode auf den Absatz aus dem HTML-Dokument zuzugreifen müsste man dies mit document.children[0].children[1].children[0].children[1].innerText weitermachen:

Sieht kompliziert und aufwendig aus? Das ist es eigentlich auch. Gibt es alternative, effizientere Methoden? Ja, die gibt es. Hier kommen wir zu den getElement-Methoden.

getElement-Methoden

Mit den getElement-Methoden können wir auf Ids, Klassennamen und auch Tags direkt zugreifen.

getElementById
Mit getElementById kann man direkt auf Ids zugreifen, die mit dem übergebenen String übereinstimmen. Da im HTML Ids einzigartig sind, ist die getElementById-Methode ein schneller Weg um auf ein Element zuzugreifen. Beispiel:

getElementsByClassName
Mit getElementsByClassName kann man direkt auf Klassennamen zugreifen. Diese Methode gibt eine HTMLCollection zurück, also alle Elemente, die mit dem übergebenen Klassennamen übereinstimmen. Mit getElementsByClassName kann man auch mehrere Klassen gleichzeitig auswählen, indem man die Klassennamen mit Leerzeichen getrennt angibt. Wichtig zu wissen ist, dass diese Methode “Live” arbeitet. Sprich: Wenn wir einmal Elemente mit diesen Klassennamen ausgeählt haben und später weitere Elemente mit denselben Klassennamen hinzukommen, dann wird unsere HTMLCollection auch automatisch aktualisiert.

Beispiel für die getElementsByClassName-Methode:

getElementsByTagName
Mit getElementsByTagName kann man direkt auf Tags zugreifen. Auch hier wird eine “Live”-HTMLCollection zurückgegeben. Beispiel:

querySelector-Methoden

Mit den querySelector-Methoden können wir auf CSS-Selektoren zugreifen.

  • querySelector(): Hier wird das erste Element zurückgegeben, welcher dem angegebenen CSS-Selektor entspricht.
  • querySelectorAll(): Hier wird eine Liste von Elementen zurückgegeben, welcher den angegebenen CSS-Selektor entspricht.

Mit document.querySelector() können wir auch Klassennamen, Ids oder Tagnamen zurgreifen:

const id = document.querySelector("#idname");
const classname = document.querySelector(".klassenname");
const tag = document.querySelector("h2");

Die querySelectorAll() gibt eine Nodelist-Collection zurück, die im Gegensatz zu getElementsByClassName und getElementsByTagName nicht “Live” ist.

Hinzufügen bzw. Erstellen

Um Elemente zu erstellen, kann man sich der Methode document.createElement() bedienen. Dabei wird zunächst das HTML-Element, welches man erstellen möchte, als Parameter mitgegeben. Später können noch weitere Attribute angepasst bzw. hinzugefügt werden:

const myLink = document.createElement("a");
myLink.innerText = "Hier klicken";
myLink.classList.add("etwas");
myLink.setAttribute("href", "www.demirjasarevic.com");

Damit wird folgendes Element erstellt:

<a href="www.google.com">Click Me</a>

Als nächstes muss an der gewünschte Stelle im DOM hinzugefügt werden. Dabei wählt man zunächst ein bestehendes Element aus und kann dann verschiedene Methoden zum Hinzufügen anwenden:

document.querySelector(".sidebar-links").prepend(myLink);
document.querySelector(".sidebar-links").append(myLink);
document.querySelector(".sidebar-links").befor(myLink);
document.querySelector(".sidebar-links").after(myLink);

Zu Erklärung:

  • prepend() fügt das Element am Anfang des ersten untergeordneten Elements ein.
  • append() fügt das Element am letzten Index ein.
  • before() fügt das Element vor dem ausgewählten Element ein.
  • after() fügt das Element nach dem ausgewählten Element ein.

Löschen

Bestehende Element im DOM können mittels der Methode remove() gelöscht werden. Dabei wird zunächst das zu löschende Element gewählt:

const h1 = document.querySelector("h1");

Und dann kann es gelöscht werden:

h1.remove();