Diese Webseite soll eine kurze Einführung in die JavaScript DOM Manipulation geben und zeigen wie man nativ - also ohne Frameworks wie jQuery - auf DOM Elemente zugreift, neue DOM Elemente erzeugt, diese verändern und löschen kann.
Das Document Object Model, im folgenden kurz DOM genannt, bildet alle Elemente einer Webseite in einer Baumstruktur ab und speichert diese im Arbeitsspeicher des verwendeten Gerätes. Dies ermöglicht später einen schnellen Zugriff.
Ist der DOM fertig aufgebaut wird in modernen Browsern durch den EventListener "domContentLoaded" ein Ereignis ausgelöst. Erst jetzt kann auf alle DOM Elemente zugegriffen werden.
In älteren IE Versionen muss dies über die unzuverlässige document.readyState Eigenschaft und einen do.Scroll Hack simuliert werden.
Die einzelnen Elemente des DOM Baums werden Knoten (node) genannt. Wie fast alles in JavaScript - mit Ausnahme von ein paar primitiven Datentypen - sind auch DOM-Knoten Objekte.
In der Hierarchie des DOM-Baums ist der HTML-Knoten das Wurzelelement (root), da ja auch in einem HTML-Dokument das HTML-Element - mit Ausnahme des DOCTYPE - alle anderen Elemente umschließt.
Man nennt ihn auch Dokumentknoten, da er die gesamte Baumstruktur darstellen kann.
Ein Dokumentfragmentknoten stellt dagegen nur einen Teil der Baumstruktur dar.
Ein Elementknoten entspricht genau einem HTML-Element (body, div, p, ...).
Ein Attributknoten entspricht genau einem Attribut (alt, title, href, ...) innerhalb eines HTML-Elements.
Außerdem gibt es noch Textknoten, welche den textuellen Inhalt eines Elements darstellen.
Es gibt auch noch weitere Knotentypen (nodeType) die hier keine Rolle spielen sollen.
Im Folgenden versuche ich zwischen allgemeinen Knoten (nodes) und Knoten mit einem Knotentyp (nodeType), z.B. Elementknoten (ELEMENT_NODE), zu unterschieden.
Der übergeordnete Knoten eines DOM-Elements ist das Elternelement (parent) und die untergeordneten Knoten nennt man Kinder (child).
Alle Knoten auf einer Ebene mit dem selben Elternelement werden als Geschwisterelemente (siblings) bezeichnet.
Man hat also eine Verwandschaftsbeziehung aus der biologischen Abstammung gewählt um die DOM Knoten abzubilden.
Bevor man auf einen oder mehrere DOM-Knoten zugreifen kann muss man sie erst einmal auswählen (selektieren). Dafür gibt es im nativen JavaScript mehrere Methoden.
Auswahl über das Attribut "ID" eines HTML Elements:
Der Wert des Attributes ID muss bekanntlich so gewählt werden, dass kein anderes HTML Element die gleiche ID besitzen kann. Somit kann man durch die Abfrage der Element ID sehr einfach den gewünschten Knoten selektieren.
Es wird immer nur ein Element zurückgegeben.
var elemSelectById = document.getElementById('wert-von-id');
Auswahl über das Attribut "NAME" eines HTML Elements:
Da mehrere HTML Elemente den gleichen Wert für dieses Attribut besitzen können wird kein einzelnes Element ausgewählt, sondern eine Sammlung von Knoten (nodelist oder live node list).
Die nodelist ist übrigens kein Array und hat nur eine beschränkte Anzahl an Eigenschaften und Methoden.
Eine Eigenschaft nodelist.length für die Anzahl an Knoten in der nodelist.
Und eine Methode nodelist.item(index) um auf einen Knoten in der nodelist zuzugreifen. Dies kann man aber auch Array-ähnlich über die eckigen Klammern nodelist[<index>] erledigen.
var elemSelectByName = document.getElementsByName('wert-von-name');
Auswahl über das HTML-Tag eines Elements:
Da auch hier keine eindeutige Identifizierung erfolgt, wird wieder eine nodelist zurückgegeben.
var elemSelectByTagName = document.getElementsByTagName('name-des-tags');
Auswahl über das Attribut "CLASS" eines HTML Elements:
Da mehrere Elemente zur gleichen Klasse gehören können wird auch in diesem Fall eine nodelist selektiert.
Aber Achtung: Diese Möglichkeit funktioniert erst ab Internet Explorer 9 und Firefox 3. In Chrome, Opera und Safari sollte es mit jeder Version funktionieren.
var elemSelectByClassName = document.getElementsByClassName('name-der-klasse');
Eine selektierte nodelist kann man übrigens durch eine Methodenverkettung ein weiteres Mal selektieren.
Dies kann allerdings schnell unübersichtlich werden, so dass man sich bereits vor der Programmierung Gedanken über die Kennzeichnung von HTML-Elementen machen sollte.
Auch eine inflationäre Verwendung von IDs ist kein guter Programmierstil.
var elemSelectByNameAndClass = document.getElementsByName('wert-von-name').getElementsByClassName('name-der-klasse';
Wenn man ein DOM Elemente ausgewählt hat kann man von diesem auf andere DOM Elemente zugreifen.
Diesen Vorgang nennt man DOM Navigation oder DOM Traversierung. Letzteres weil man sich wie auf einem Querbalken von einem Knoten zum anderen bewegt.
Das funktioniert nicht mit einer nodelist!
Es gibt folgende Möglichkeiten zu traversieren.
Wie ich bereits weiter oben erklärt habe hat jeder Knoten - außer dem Wurzelknoten - ein Elternelement (parent). Wenn man zu diesem traversieren will kann man dies über die Eigenschaft node.parentNode tun.
Jeder Knoten kann natürlich nur ein direktes Elternelement besitzen. Also nicht Vater und Mutter. :-). Man kann aber von dem Elternelement weiter zu deren Elternelement navigieren, indem man eine erneute parentNode Eigenschaft ankettet. Eine node.grandparent Eigenschaft gibt es nicht.
var elemSelectById = document.getElementById('wert-von-id');
elemSelectById.parentNode;
Alternativ gibt es noch eine Eigenschaft Node.parentElement. Der Unterschied zwischen diesen Eigenschaften ist, dass bei parentNode alle Knoten berücksichtigt werden und bei parentElement nur die Elementknoten. Also z.B. keine Textknoten.
var elemSelectById = document.getElementById('wert-von-id');
elemSelectById.parentElement;
Was nach oben geht, geht auch nach unten. Node.childNodes gibt eine nodeList mit allen Kindknoten zurück.
var elemSelectById = document.getElementById('wert-von-id');
elemSelectById.childNodes;
Will man nur den ersten Kindknoten kann man dies mit der Eigenschaft Node.firstChild erreichen.
var elemSelectById = document.getElementById('wert-von-id');
elemSelectById.firstChild;
Node.LastChild macht genau das genaue Gegenteil und navigiert zum letzten Kindknoten.
var elemSelectById = document.getElementById('wert-von-id');
elemSelectById.lastChild;
Nachdem wir jetzt vertikal traversiert haben kommen wir jetzt zum horizontalen Teil.
Node.previousSibling navigiert zum vorhergehenden Geschwisterelement, links von diesem.
var elemSelectById = document.getElementById('wert-von-id');
elemSelectById.previousSibling;
In die andere Richtung geht es mit Node.nextSibling. Hier wird zum nächsten Geschwisterelement, rechts von diesem, navigiert.
var elemSelectById = document.getElementById('wert-von-id');
elemSelectById.nextSibling;
Noch einmal zur Erinerung. Geschwisterelemente liegen auf einer Ebene und haben dasselbe Elternelement.
Einen neuen DOM-Knoten zu erzeugen und sofort über oder unter einen benachbarten Knoten einzuhängen ist nicht möglich. Dafür ist ein weiterer Schritt notwendig.
Zum erzeugen eines DOM-Knotens wird die Methode createElement() benötigt, die nur im document Objekt verfügbar ist.
Diese Methode erzeugt einen neuen Element-Knoten. Als Argument muss der Name eines HTML-Tags übergeben werden, da man sonst nicht weiß um was für ein HTML-Element es sich handelt.
var elementKnoten = document.createElement('h1');
Will man einen Textknoten erzeugen muss man dagegen die Methode createTextNode() verwenden.
var textKnoten = document.createElement('Das ist mein Text');
Wir haben jetzt zwar Knoten erzeugt, aber der DOM-Baum hat sich deshalb noch nicht verändert. Wir müssen den erzeugten DOM-Knoten jetzt an die gewünschte Position einhängen.
Dafür gibt es die Methode appendChild(), was so viel wie Kindknoten anhängen bedeuten soll. Der DOM-Knoten wird also als letztes Kindelement innerhalb eines anderes Elementknotens angehängt.
var elemSelectById = document.getElementById('id');
var elementKnoten = document.createElement('h1');
var = document.createElement('Das ist mein Text');
elementKnoten.appendChild(textKnoten);
elemSelectById.appendChild(elementKnoten);
Will man einen neuen DOM-Knoten nicht am Ende eines anderen Elementknotens platzieren, sondern an einer speziellen Position nutzt man die Methode insertBefore().
Diese Methode ist etwas komplizierter in der Anwendung.
Man muss zuerst das zukünftige Elternelement des neuen Knotens auswählen und über dieses die Methode aufrufen. Der erste Parameter ist der neue Knoten und der zweite Parameter ist der Knoten vor den das neue Element platziert werden soll.
var parentElement = document.getElementById('parent');
var childElement = document.getElementById('child');
var neuerKnoten = document.createElement('div');
parentElement.insertBefore(neuerKnoten, childElement);
Das Löschen eines DOM-Knotens funktioniert über die Methode removeChild().
Dazu wird zusätzlich der Elternknoten des zu löschenden DOM-Knotens benötigt, da die Methode über diesen Knoten aufgerufen wird.
var firstChildElement = document.getElementById('parent').firstChild;
document.getElementById('parent').removeChild(firstChildElement);
Das Ersetzen eines DOM-Knotens funktioniert ähnlich wie das Löschen eines Knotens. Doch zusätzlich wird noch ein Knoten benötigt der den anderen Knoten ersetzt und als erster Parameter für die Methode replaceChild() dient.
var firstChildElement = document.getElementById('parent').firstChild;
var neuerKnoten = document.createElement('h1');
document.getElementById('parent').replaceChild(neuerKnoten, firstChildElement);
Es gibt auch eine Methode clone(deep) um DOM-Knoten zu duplizieren. Diese besitzt ein Argument "deep" vom Datentyp boolean. Wird es auf true gesetzt, werden auch alle Kindknoten mit dupliziert. Dies betrifft auch Textknoten!
Es wird empfohlen das Argument zu setzen auch wenn es optional ist. Der Grund sind Inkompatibilitäten in den verschiedenen DOM-Spezifikationen.
var cloneElement = document.getElementById('original').cloneNode(true);