CSS, HTML und Javascript mit {stil}

Javascript DOM (Document Object Model)

Javascript DOM Document Object Model

Das DOM (Document Object Model) beschreibt HTML-, XML- und SVG-Dokumente. Für Programmiersprachen wie Javascript ist das DOM der Standard für den Zugriff auf Tags, Attribute und Inhalte von HTML-Seiten, XML-Dokumenten und SVG-Grafiken.

Eine Baumstruktur setzt alle Elemente eines Dokuments in Beziehung zueinander: Ein Dokument besteht aus Nodes – Knoten – in einer hierarchischen Baumstruktur. Javascript kann von einem Element aus durch die Seite navigieren und Tags, Attribute oder Inhalt einfügen oder entfernen.

An der Spitze des DOM-Baums ist das document-Objekt, gefolgt vom root (der Wurzel des DOM-Baums), das bei Webseiten das html-Element der Seite ist. Unterhalb des html-Elements liegen das HEAD- und das BODY-Element.

Parent Node, Child Node, Siblings

Die Elemente des DOM werden als Nodes – Knoten – bezeichnet. Das html-Tag ist der Elternknoten – Parent – des head- und des body-Elements. In diesem Beispiel hat head zwei Kinder: titel und meta.

Nicht nur HTML-Tags bilden Knoten oder DOM-Nodes, sondern HTML-Attribute und Inhalte und selbst Kommentare sind ebenfalls Nodes.

DOM Tree Nodes, parentNode, childNode, siblings, nextSibling html head body titlemetanavdivformulsectionsectionh1pDas DOM verbindetNodes zu einer Baumstruktur Der DOM-Baum parentNode – childNode parentNode – childNodenextSiblingsiblings

title und meta sind Nachfahren desselben Eltern-Elements – Siblings in der Sprache des DOM –. nav ist das Child – ein Kind und direkter Nachkomme von body. body ist Parent – Elternknoten – des nav-Elements.

Über die Beziehungen wie parentNodechildNode, siblings, nextSibling, previousSibling erreicht Javascript jedes Element – jeden Knoten – und kann neue Elemente erzeugen, in den Baum einhängen oder Teile des DOM-Baums löschen.

DOM Traversal – Navigation durch das DOM

Ganz schön viele Zeiger für jedes Element im HTML-Dokument.

DOM Nodes: parentNode, childNode, siblings, nextSibling

Obendrein erzeugen Kommentare, Leerzeichen zwischen den HTML-Tags und Zeilenumbrüche Knoten, von denen wir lieber gar nichts wissen wollen. Darum wurde die Menge der Zeiger um echte Element-Nodes ergänzt: children, parentElement, firstElementChild, lastElementChild, previousElementSibling, nextElementSibling.

Damit reichen schon zwei Zeiger oder Referenzen, um alle Nodes im DOM zu erreichen.

function log (node) {
   console.log (node.nodeName)
}

function domWalker (node, func) {
   func(node);
   node = node.firstElementChild;
   while(node) {
      domWalker (node, func);
      node = node.nextElementSibling;
	}
}
domWalker (document.querySelector("BODY"), log);

// Quelle Douglas Crockford Vortragsnotizen

Viel einfacher als mit komplizierten while-Schleifen durchquert die rekursive Funktion domWalker alle Knoten des DOM. Das zweite Argument ist eine Funktion, die in diesem Beispiel einfach nur den NodeName ausgibt.

Zum Glück müssen wir uns nicht um die Verwaltung der Referenzen auf die ganze Sippe von Vorfahren, Nachkommen und Geschwister nicht kümmern: Die Browser bauen das Dokument als DOM-Baum aus HTML-Tags-, -Attributen und Inhalt auf und halten bei allen Änderungen immer die aktuellen Referenzen bereit.

Grundlage für funktionierende Skripte ist einfach nur valides HTML.

DOM Nodes

Dieses P-Element hat drei Kinder

<p>Jedes HTML-Dokument <em>ist ein Knotenbaum</em> aus allen Elementen.</p>
DOM Element Nodes and Text Nodes pJedes XML-Elementist einaus allen ElementenKnotenbaumem
Das erste Kind ist der Text-Node "Jedes XML-Dokument ", das zweite Kind ist der Element-Node EM und das dritte Kind ist der Text-Node "aus allen Elementen.". Das EM-Element hat ein Kind: den Text-Node "ist ein Knotenbaum". Text-Nodes haben keine Kinder.

DOM: Formular

Das Formular hat drei childNodes: einen commentNode und zwei DIV-Nodes. Der erste DIV hat zwei Kinder: LABEL und INPUT. LABEL hat ein Kind: den Text-Node "Name". Das zweite DIV hat ein Kind: den Node LABEL, der wiederum auch nur ein Kind, nämlich den Node INPUT hat.

<form id="formdemo" …>
<!-- Name eingeben und speichern -->
<div>
   <label for="name">Name</label> 
   <input type="text" name="name" /> 
</div>
<div>
   <label>
      <input type="submit" value="Speichern" />
   </label>
</div>
</form>
Name Speichern
DOM Tree Structure Form form<!-- -->divdivlabellabelinputinput

Das sind »nur« die Element- und Text-Nodes eines Fragments des gesamten DOM Tree. Jedes Attribut ist ein Attribute-Node und selbst Weißraum stellt einen DOM Node dar. Ein Attribute Node ist allerdings kein childNode seines Element-Knotens.

CSS mit Javascript ändern

Die Methoden und Eigenschaften des DOM erzeugen neue Tags, manipulieren die Attribute, hängen Elemente mitsamt allen verschachtelten Elementen an eine andere Stelle des Dokuments und steuern den Fluss der Ereignisse, wenn das Dokument bereits im Fenster des Benutzers geladen ist und ersparen das aufwändige Neuladen des Dokuments.

CSS mit Javascript ändern

Schrift ändern
document.getElementById('change').onclick = function () {
   elem.setAttribute('style','font-family: Georgia,Times, serif');
}

Das Script identifiziert den Button anhand des id-Attributs change und fängt ein onclick-Event auf dem Element ab. Beim Klick auf den Button fügt das Script ein style-Attribut in das Element elem ein.

Nodes einfügen: appendChild

<div class="row">
   <button id="insert">Element mit Javascript einfügen</button>
</div>

<script>
document.getElementById('insert').onclick = function () {
   var img = document.createElement('IMG');
   img.setAttribute('src','luftschloss.png');
   img.setAttribute('alt','Bild mit Javascript einfügen');
   document.getElementById('insert').parentNode.appendChild(img);
}
</script>

document.createElement('IMG') erzeugt einen neuen Elementknoten »IMG«, mit img.setAttribute('src','luftschloss.png') setzt das Script ein scr-Attribut in das neue Element.

Das neu erzeugte IMG-Element erscheint allerdings noch nicht im Dokument, sondern schwebt sozusagen frei im Raum – bis das IMG-Element mit parentNode.appendChild(img) hinter das Element mit der ID 'insert' gehangen wird.

Eine Methode, die das neue IMG-Element hinter das Element mit id="insert" hängt, gibt es nicht, sondern eine Methode, die ein Element an den übergeordneten Vaterknoten vor einem vorhandenen Element einklinkt: parentNode.appendChild(img).

Ein Element kann nicht nur mit appendChild oder insertBefore eingefügt werden, sondern auch mit innerHTML.

Javascript Nodes: Leerraum und Weißraum

Leerraum durch Leerzeichen, Tabulatoren und Zeilenumbrüche erzeugen ebenfalls DOM Nodes. Da man sich auf den HTML-Quelltext nicht verlassen darf, müssen die Rückgaben auf den Node Type geprüft werden.

FORM<!-- -->Name eingeben und speichernDIVDIVLABELINPUTLABELINPUTName

Eine Alternative zu den aufwändigen Abfragen sind Javascript firstElementChild, lastElementChild, nextElementSibling und previousElementSibling. Diese Funktionen sind präziser und liefern nur Element-Nodes (nodeType 1), aber keine Text- und Comment-Nodes.