DOM

Aus m-wiki
Zur Navigation springen Zur Suche springen

Einführung

HTML ist wie XML eine Auszeichnungssprache und kann daher in einem DOM (Document Object Model) abgebildet werden. Das geparste Dokument ist wie ein Baum aufgebaut und beginnt mit der Wurzel (root) und bildet sich über Äste (Elementknoten) aus, welche den Tags im Dokument entsprechen und geht zu den Blättern, welche dem Inhalt das Dokuments und seiner Formatierung entsprechen.

Mittels DOM ist es nicht nur möglich, das Dokument zu analysieren und gewisse Eigenschaften zu ändern, man kann auch Elemente hinzufügen oder entfernen.

Damit die Verarbeitung korrekt erfolgen kann, muss das Dokument wohlgeformt sein. Browser wurden vom Hersteller darauf programmiert, auch feherhafte Webseiten möglichst trotzdem irgendwie anzuzeigen. Wenn man nun ein solchermassen ergänztes Dokument verarbeitet, kann es sein, dass der eigentlich korrekte Code nur bei manchen Browsern funktionert, welche das Dokument genauso ergänzen. Damit dies nicht geschieht, sollte man sein Dokument immer beim W3C validieren.

Aufbau des DOM

Beispieldokument aus dem Wiki-Artikel zum DOM.

Das Element <table> ist in diesem Beispiel "root".<thead> oder <td> sind Elementknoten "Vorname" oder "Duck" sind Textknoten (Blätter). Die Eigenschaften von Elementen, die Attribute, werden im Baum nicht dargestellt und können entsprechend auch nicht direkt erreicht werden, sondern sind Eigenschaften der Elementknoten. Bei <td textalign = "center"> ist textalign eine Eigenschaft, welche nicht direkt errreicht werden kann, sondern über document.table.tbody.tr.td(textalign) ausgelesen wird.

Jedes Element "in der Mitte" enthält entsprechend ein Elternteil (parent) und Kinder (child), wobei es immer nur einen direkten Elternteil geben kann, doch dieser mehrere Kinder haben kann. tr.parent() ist entsprechend <tbody>, doch als Kinder gibt es hier 2 <td>-Elemente, welche entsprechend über ein Array angesprochen werden müssen und in der Reihenfolge ihrer Definition auftauchen: tr.child[0]() und tr.child[1](), da auch hier ein Array immer mit 0 beginnt.

Zugriff auf Knoten

Auf jeden Knoten egal welcher Art er ist, kann mittels des Node-Objekts zugegriffen werden. Dies wird im Artikel zu Javasript aufgezeigt.

Status des Dokuments

Mit Javascript kann man den Zustand abfragen. Es gibt je nach Browser verschiedene Zustände, doch folgende sind bei allen (neuen) Browsern implementiert. Eine komplette Liste wieder auf selfhtml.

  • loading -> Ladevorgang begonnen aber noch nicht abgeschlossen
  • interactive -> Die Bearbeitung ist noch nicht komplett, z. B. können noch Bilder fehlen, aber der Benutzer bekommt schon eine Seite angezeigt -> ab hier ist es sinnvoll, mit JS zu starten
  • complete -> Die Seite wird komplett im Browser gezeigt

Entsprechend des Status gibt es die Events DOMContentLoaded, welche den Status auf interactive setzen und Load, welcher complete auslöst. Daher kann man die Events mit folgendem Code auch als Alternative verwenden:

document.onreadystatechange = function () {
 if (document.readyState == "interactive") { initApplication(); }
} // end onreadystatechange 

document.onreadystatechange = function () {
 if (document.readyState == "complete") { initApplication(); }
} // end onreadystatechange

Methoden des Dokuments

Im selfhtml werden alle möglichen Elemente mit ihren Methoden aufgezeigt. Hier werden entsprechend nur die direkten Methoden des Dokuments aufgeführt. Fürs Dokument gibt es noch Eigenschaften, die auch abgefragt werden könnten:

  • close() -> wird nur gebraucht, wenn man manuell Dokumente öffnet und diese dann schliessen will.
  • createAttribute() -> damit können Elemente mit zusätzlichen Attributen (class, id usw.) versehen werden. Es braucht aber noch setAttributeNode(), um das erzeugte Attribut einem Element zuzuweisen. Wird normalerweise nicht beim Dokument selber, sondern bei einem Unterelement verwendet.
  • createDocumentFragment() -> Damit können dynamisch Elemente zum Dokument hinzugefügt gefügt werden. Es braucht aber weitere Methoden (siehe Beispiel im Link), damit die Elemente dem Dokument hinzugefügt werden.
  • createElement() -> Erzeugt ein neues Element im Dokument. Dieses muss anschliessend mit weiteren Methoden an der richtigen Stelle dem Dokumentbaum hinzugefügt werden.
  • createTextNode() -> Wie bei einem Element, doch dies erzeugt die Beschriftung oder allgemeine Texte.
  • getElementById() -> Stellt ein Element an Hand seiner einmaligen ID zur Verfügung. Gross- und Kleinschreibung wird beachtet. Kann die ID nicht gefunden werden, so wird null zurückgegeben.
  • getElementsByName() -> Gibt alle Elemente mit diesem Namen zurück. Dadurch dass mehrere Elemente zurückgegeben werden können, muss man auf die Elemente immer wie auf ein Array zurückgreifen (element[0]), auch wenn es nur ein Element mit diesem Namen gibt. Da es sich aber um eine "live node list" handelt, kann man die Elemente nicht wie ein Array und dessen Methoden anwenden.
  • getElementsByClassName() -> Auch hier erhält man eine "live node list" zurück. Die Funktion kann aber auch Elemente von mehreren Klassen zurückliefern. Dazu muss man die Funktion einfach mit allen gewünschten Klassen mittels Komma separiert aufrufen x = document.getElementsByClassName('class1', 'class2').
  • getElementsByTagName() -> Im Gegensatz zur Klasse gibt man hier als Argument das HTML-Element an, das man bearbeiten möchte (p, h2, usw.). Man kann sogar mit * alle Elemente übernehmen. Auch hier wird entsprechend eine "live node list" zurückgeliefert.
  • getSelection() -> Diese Funktion liefert den Text zurück, welchen der Benutzer markiert hat. Ohne Auswahl kommt ein leerer Text zurück.
  • importNode() -> Diese Funktion wird nur verwendet, wenn man zusätzliche Dokumente oder Teile davon ins aktuelle Dokument übernehmen möchte.
  • open() -> wird nur gebraucht, wenn man manuell weitere Dokumente öffnen möchte.
  • querySelector() -> Diese Methode sucht den ersten Treffer im Dokument(fragment) oder Element auf den der zutreffende CSS-Ausdruck passt. Damit kann etwa geziehlt ein Abschnitt angepasst werden. document.querySelector('.beispiel').innerHTML = "Ersten Abschnitt anpassen."; Im Beispiel wird nach der Klasse beispiel gesucht und der Text in dessen Element ersetzt. Diese Methode ist Teil der Node-Klasse. Die Methode übernimmt auch mehrere Ausdrücke, welche einfach kommagetrennt sein müssen.
  • querySelectorAll() -> Im Gegensatz zur Methode ohne "All" werden hier alle Elemente des CSS-Ausdrucks gefunden und als "live node list" zurückgeliefert. Sonst ist das Verhalten gleich.
  • write() -> Wird nur verwendet, wenn man ein zusätzliches Dokument erstellt. Um fertige Dokumente zu bearbeiten sollte stattdessen mit createTextNode gearbeitet werden, in den man dann mit appendChild Text, aber keinen HTML-Code anhängen kann.
  • writeln() -> Wie write() wird es nicht für fertige Dokumente verwendet. Im Gegensatz dazu wird noch ein Zeilenumbruch eingefügt.

Methoden eines Knotens (Node)

Ein Knoten stellt eine bestimmte "Verzweigung" im Baum dar und ist daher das zentrale Element, wenn es darum geht, ein Dokument zu bearbeiten. Neben den Eigenschaften gibt es auch hier mehrere Methoden. Da im Gegensatz zum DOkument alle für die Bearbeitung wichtig sind, werden diese nicht speziell fett gekennzeichnet.

  • Node.appendChild() -> fügt ein neues Kindelement hinzu und zwar als letztes Element. Das neue Element muss vorher mit createElement() oder createTextNode() erzeugt worden sein.
  • Node.cloneNode() -> Mit dieser Methode wird der übergebene Knoten dupliziert. Man kann auch sagen, ob er mitsamt seinen Kindelementen kopiert werden soll. Man muss beachten, dass hier auch eine ID geklont werden kann. Diese muss entsprechend angepasst werden, damit man nicht plötzlich doppelte IDs hat.
  • [Node.compareDocumentPosition()
  • [Node.contains()
  • [Node.hasChildNodes()
  • [Node.insertBefore()
  • [Node.isDefaultNamespace()
  • [Node.isEqualNode()
  • [Node.normalize()
  • [Node.removeChild()
  • [Node.replaceChild()

Zugriff auf den DOM mit Javascript

selfhtml zeigt im Artikel zum DOM, wie man mit JavaScript (JS) auf den DOM zugreift. Wie in der Einführng gezeigt, kann dies über den Gesamtbaum geschehen oder man kennzeichnet die Elemente mit einer einmaligen ID oder einem spezifischen Namen (welcher auch mehrmals vorkommen darf). Beim Zugriff über die ID hat man die Gewissheit, dass nur das gewünschte Objekt betroffen ist. Beim Zugriff über den Namen muss man schauen, dass man nicht ungewollt das falsche Objekt verwendet oder mehrere Objekte anpasst. Dies kann vor allem bei generierten Inhalten geschehen, wenn man etwa einen Teil doppelt oder aus unterschiedlichen Quellen einbindet.

Damit JS ein Element verwenden kann, muss es schon vom Browser geparst worden sein. Dies ist wichtig, da ein Skript theoretisch überall im HTML-Code eingebunden werden kann.