Galileo Computing <openbook>
Galileo Computing - Programming the Net
Galileo Computing - Programming the Net


JavaScript von Christian Wenz
Browserübergreifende Lösungen
JavaScript - Zum Katalog
gp Kapitel 22 DOM
  gp 22.1 DOM-Baum
  gp 22.2 Navigation im Baum
  gp 22.3 Den Baum modifizieren
  gp 22.4 Fragen & Aufgaben

Kapitel 22 DOM

Die Zukunft hat viele Namen. Für die Schwachen ist sie das Unerreichbare. Für die Furchtsamen ist sie das Unbekannte. Für die Tapferen ist sie die Chance.
– Victor Hugo

JavaScript entwickelt sich natürlich weiter. Inzwischen gibt es JavaScript-Version 1.5, welche jedoch von keinem Browser unterstützt wird. JavaScript 1.5 schließt die Lücke der bisherigen JavaScript-Versionen hin zum Standard ECMAScript, 3. Revision. Dieser Sprachstandard (offizielle Spezifikation unter http://www.ecma.ch oder auf der Buch-CD) entspricht in etwa dem Sprachumfang von JavaScript 1.1, wurde aber bisher noch von keinem Browser komplett unterstützt. Der Internet Explorer 4 war sehr nahe dran, und der Internet Explorer 5 unterstützt (bis auf die üblichen Bugs) vollständig ECMAScript (oder kurz: ECMA-262). Auch Netscape 6, der im Vor-Beta-Stadium befindliche neue Browser (unter http://home.netscape.com, Entwicklerversion unter http://www.mozilla.org) ist ECMA-compliant.

Wenn jedoch im Zusammenhang mit JavaScript von Standards gesprochen wird, dann ist die Rede von DOM, dem Document Object Model. Vereinfacht gesagt, soll ein HTML-Dokument so modelliert werden, dass mit JavaScript darauf zugegriffen werden kann. Wie in den drei DHTML-Kapiteln schon angedeutet wurde, geht der Internet Explorer (ab Version 4) hier viel weiter als der Netscape Navigator 4. Die zueinander inkompatiblen DOM-Umsetzungen der beiden Browserhersteller sind für den Programmierer ein stetes Ärgernis. Da zudem noch sowohl Netscape als auch Microsoft ihre Umsetzung für die jeweils besser hielten, war zunächst keine Einigung in Sicht. Für solche Fälle gibt es glücklicherweise (mehr oder weniger) unabhängige Gremien wie das W3C, welche mittlerweile einen DOM-Standard abgesegnet haben. Die Konsequenz daraus: Der Internet Explorer 5 hält sich daran, der Netscape Navigator 6 ebenfalls (in der momentanen Version ist die Unterstützung aber vor allem von der JavaScript-Seite aus noch überhaupt nicht vollständig). Da es bis zur endgültigen Fertigstellung des Netscape noch eine Weile dauert, und die Verbreitung des Internet Explorer 5 vor allem in Firmennetzwerken noch nicht so groß ist, ist die Zielgruppe für DOM-Effekte nicht allzu groß. Aus diesem Grund finden Sie in diesem Kapitel lediglich eine kurze Einführung in das Konzept. In einer weiteren Auflage kann das schon ganz anders aussehen.

Eine Vorbemerkung noch: Wir beschränken uns hier ausschließlich auf den DOM-Mechanismus des Internet Explorer 5.x. Der Grund hierfür ist ganz einfach der, dass der Netscape 6 – trotz offiziellem Release-Status – noch weit von der Serienreife entfernt ist und deshalb die Entwicklung damit keine Freude ist. In Kapitel 18 haben Sie gesehen, wie Sie alte DHTML-Anwendungen für den neuen Netscape fit machen.


Galileo Computing

22.1 DOM-Baum  downtop

Das HTML-Dokument wird in einen Baum umgewandelt. Jedes HTML-Element, und auch jeder Text, der nicht von Tags umgeben ist, wird zu einem Knoten (engl. nodes) in dem Baum. Elemente zwischen einem öffnenden und dem dazugehörigen schließenden Tag sind Kindknoten (engl. child nodes), sodass auch eine Hierarchie gegeben ist. In diesem Kapitel wird folgendes Beispieldokument betrachtet:

<HTML>
<HEAD>
<TITLE>DOM-Demo</TITLE>
</HEAD>
<BODY ID="alles">
<H3 ID="Ueberschrift">DOM-Demo</H3>
<IMG SRC="ball.gif" ID="Ball1">
<IMG SRC="ball.gif" ID="Ball2">
<IMG SRC="ball.gif" ID="Ball3">
<IMG SRC="ball.gif" ID="Ball4">
</BODY>
</HTML>

In Abbildung 22.1 sehen Sie, wie der DOM-Baum für das vorherige Dokument aussieht.

Beachten Sie, dass jeder Tag ein ID-Attribut trägt. Hiermit kann der Tag dann von JavaScript aus angesprochen werden. Sie ahnen bereits, es geht wohl auch über irgendein Array mit irgendeinem Index, wie bisher immer, aber der Übersichtlichkeit halber ist es auch hier besser, sprechende Namen zu verwenden.

Abbildung 22.1  Der DOM-Baum des HTML-Dokuments
Abbildung


Galileo Computing

22.2 Navigation im Baum  downtop

Ähnlich wie bei Framehierarchien kann man auch in dem DOM-Baum von Ebene zu Ebene springen. Die entsprechenden Methoden und Eigenschaften heißen hier nur anders, aber ansonsten bleibt alles beim Alten. Die Kindknoten eines Elements im DOM-Baum befinden sich im Array childNodes[]. Von einem Knoten (bzw. HTML-Element) aus kann man mit den folgenden Eigenschaften auf andere Knoten zugreifen:

Tabelle 22.1  Eigenschaften eines Knotens im DOM-Baum
Eigenschaft Beschreibung
firstChild Der erste Kindknoten (erstes Element im child Nodes-Array)
lastChild Der letzte Kindknoten (letztes Element im child Nodes-Array)
nextSibling Das nächste Kind des Elternknotens
parentNode Der Elternknoten
previousSibling Das vorherige Kind des Elternknotens

Die Eigenschaften aus Tabelle 22.2 liefern nähere Informationen über einen Knoten zurück:

Tabelle 22.2  Eigenschaften, die nähere Informationen über einen Knoten liefern
 Eigenschaft Beschreibung
nodeName HTML-Tag des Knotens als Zeichenkette (z. B. "H3")
nodeType 1 = Tag, 2 = Attribut, 3 = Text

In Abbildung 22.2 sehen Sie den DOM-Baum noch einmal, und diesmal mit den Beziehungen zwischen den einzelnen Knoten.

Abbildung 22.2  Navigationsmöglichkeiten innerhalb des DOM-Baums
Abbildung


Galileo Computing

22.3 Den Baum modifizieren  downtop

Der große Vorteil von DOM gegenüber DHTML und den früheren DOM-Implementierungen besteht darin, dass man Elemente nicht nur ändern, sondern auch entfernen und sogar neue Elemente einfügen kann. Die Baumstruktur ist hier von großem Vorteil, da das Löschen eines Knotens nicht die Baumintegrität gefährdet. In Tabelle 22.3 sehen Sie eine grobe Übersicht über die verschiedenen Methoden. Für das Beispiel in diesem Kapitel reicht sogar eine Methode.

Tabelle 22.3  Methoden zur Veränderung des DOM-Baums
Methode Syntax Beschreibung
appendChild Vater.appendChild(Kind) Hängt Kind als Kindknoten an Vater an.
cloneNode Original.cloneNode
(alles)
Erzeugt einen Knoten, der identisch zu Original ist. Ist alles gleich true, so werden auch alle Kindknoten von
Original mit dupliziert, bei false lediglich der Knoten selbst.
createElement document.createElement
(HTMLTag)
Erzeugt einen Knoten, der aus dem in Klammern angegebenen HTML-Element (z. B. H3) besteht.
hasChildNodes Knoten.hasChildNodes() Boolescher Wert, der angibt, ob Knoten Kinder hat oder nicht.
insertBefore Vater.insertBefore(Kind, Schwester) Kind wird als Kindknoten von Vater eingefügt, und zwar direkt vor Schwester.
removeNode Knoten.removeNode(alles) Knoten wird aus dem DOM-Baum entfernt. Ist alles gleich true, dann werden auch alle Kindknoten von Knoten entfernt.
replaceNode Alt.replaceNode(Neu) Der Knoten Alt wird durch den Knoten Neu ersetzt.
setAttribute Knoten.setAttribute(Name, Wert) Der Knoten enthält ein neues
Attribut
.

In einem kleinen Beispiel soll dies einmal ausprobiert werden. Ausgehend von obigem Beispiel-HTML-Dokument sollen die folgenden Effekte eingebaut werden:

gp  Wenn der Benutzer mit der Maus auf eine der Grafiken klickt, soll diese durch eine andere Grafik ausgetauscht werden.
gp  Wenn der Benutzer noch einmal auf die Grafik klickt, soll sie komplett verschwinden (eine Art armseliges Ballerspiel mit JavaScript also).

Der Einfachheit halber werden die Event-Handler der Grafiken schon im ursprünglichen HTML-Dokument gesetzt. Es muss also nur noch eine Funktion geschrieben werden, die überprüft, ob die Grafik schon einmal angeklickt worden ist, und dann entweder die Grafik austauscht oder den Knoten aus dem DOM-Baum entfernt.

Der folgende Code ist kurz und einleuchtend und wird daher ohne längere Vorrede abgedruckt. Leider ist noch ein kleiner Fehler drin, dazu später mehr.

<HTML>
<HEAD>
<TITLE>DOM-Demo</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function mausklick(Nummer){
   var obj = document.all.alles.childNodes[1+Nummer]
   var gfx = obj.src
   if (gfx.indexOf("ball.gif")>-1)
      obj.src="kreuz.gif"
   else
      obj.removeNode(false)
}
//--></SCRIPT>
</HEAD>
<BODY ID="alles">
<H3 ID="Ueberschrift">DOM-Demo</H3>
<IMG SRC="ball.gif" ID="Ball1" onClick="mausklick(1)">
<IMG SRC="ball.gif" ID="Ball2" onClick="mausklick(2)">
<IMG SRC="ball.gif" ID="Ball3" onClick="mausklick(3)">
<IMG SRC="ball.gif" ID="Ball4" onClick="mausklick(4)">
</BODY>
</HTML>
Abbildung 22.3  Die DOM-Demo im Internet Explorer 5
Abbildung

Wie Ihnen sicherlich nicht entgangen ist, spuckt der Browser hin und wieder Fehlermeldungen bei der Ausführung dieses Skripts aus, beispielsweise, wenn Sie auf die dritte Grafik von links klicken. Sehr merkwürdig! Zum Testen sollten Sie in die Funktion mausklick() den folgenden Debug-Code einfügen (am besten gleich am Anfang):

function mausklick(Nummer){
   var meldung=""
   for (var i=0; i<document.all.alles.childNodes.length; i++)
     meldung += document.all.alles.childNodes[i].nodeName + "|" +
       document.all.alles.childNodes[i].nodeType + "\n"
   alert(str)
   var obj = document.all.alles.childNodes[1+Nummer]
   var gfx = obj.src
   if (gfx.indexOf("ball.gif")>-1)
      obj.src="kreuz.gif"
   else
      obj.removeNode(false)
}
Abbildung 22.4  Die Debug-Ausgabe
Abbildung

In Abbildung 22.4 sehen Sie die Ursache des Übels: Anscheinend befinden sich zwischen den einzelnen Grafiken noch Textstücke. Auch das ist nicht weiter verwunderlich – auch wenn ein Zeilensprung im HTML-Code in der Anzeige quasi nie Auswirkungen hat, beim DOM-Baum ist das ein Textelement. Sie sollten also die Zeilensprünge entfernen, und dann gibt es beim ersten Anklicken einer Grafik auch keine Fehlermeldungen mehr.

Um dies zu vermeiden, sollten Sie die HTML-Elemente, die Sie in Ihrem Skript verwenden wollen, mit den oben gezeigten Methoden (create Element() und appendChild() bzw. insertBefore()) erzeugen. Das obige HTML-Dokument kann auch folgendermaßen erzeugt werden (von der Klick-Funktionalität mal abgesehen) – jedoch nur ab Internet Explorer 5 und Netscape Navigator 6!

<HTML>
<HEAD>
<TITLE>DOM-Demo</TITLE>
<SCRIPT LANGUAGE="JavaScript"><!--
function init(){
   var basis = document.all.alles
   var h3 = document.createElement("H3")
   h3.setAttribute("id", "Ueberschrift")
   h3.innerText = "Überschrift"
   basis.appendChild(h3)
   for (var i=1; i<=4; i++){
      img = document.createElement("IMG")
      img.setAttribute("id", "Ball"+i)
      img.src = "ball.gif"
      basis.appendChild(img)
   }
}
//--></SCRIPT>
</HEAD>
<BODY ID="alles" onLoad="init()">
</BODY>
</HTML>

Wie Sie in einer Aufgabe am Ende des Kapitels jedoch noch sehen werden, ist das vorherige Skript nicht ganz fehlerfrei. Es ist einfach gefährlich, über Index auf ein Element zuzugreifen, wenn zwischendurch Elemente entfernt werden sollen. Aber Sie haben ja bereits an anderer Stelle schon gesehen, dass es fast immer besser ist, per Identifikator auf ein Element zuzugreifen. Hier ist das auch der Fall. Es gibt eine weitere Methode des document-Objekts, und zwar getElementById(). Sie kennen sie bereits aus Kapitel 18, dort wird Sie für DHTML-Effekte des Netscape 6 eingesetzt. Als Parameter übergeben Sie den Wert des ID-Attributs des entsprechenden HTML-Tags, und die Methode gibt Ihnen eine Referenz auf das Objekt zurück. Im folgenden Code finden Sie das für unser kleines Beispiel einmal umgesetzt. Anhand der Nummer, die an mausklick() übergeben wird, kann der Identifikator der angeklickten Grafik ermittelt werden, und dieser Wert wird dann an getElementById() übergeben.

function mausklick(Nummer){
   var obj = document.getElementById("Ball"+Nummer)
   var gfx = obj.src
   if (gfx.indexOf("ball.gif")>-1)
      obj.src="kreuz.gif"
   else
      obj.removeNode(false)
}

Ihnen ist sicherlich aufgefallen, dass alle Screenshots in diesem Kapitel mit dem Internet Explorer erstellt worden sind, während im restlichen Buch stets der Netscape Navigator zum Einsatz kam. Das hat einen recht einfachen Grund. Der Netscape Navigator 6, der als einziger Netscape-Browser das neue DOM-Konzept unterstützt, ist noch sehr fehleranfällig, und für den Entwickler ziemlich grausam. Auch die Beispiele in diesem Kapitel funktionieren in diesem Browser nicht, im Internet Explorer 5 und 5.5 jedoch schon. Die Unterstützung des Browsers an der Basis, den Surfern nämlich, ist auch noch relativ gering. Zwar wird anerkannt, dass der Browser für viele Plattformen zur Verfügung steht, und dass er Webstandards ziemlich genau unterstützt; die meisten Anwender wollen jedoch noch auf eine stabile Version warten. Und somit bleibt eine saubere DOM-Programmierung noch Zukunftsmusik. Die JavaScript-Programmierung wird sich in diese Richtung bewegen – das steht außer Frage. So lange jedoch der Internet Explorer 4 und (vor allem) der Netscape Navigator 4 noch eine große Verbreitung haben, müssen Sie die Entwicklung auf diese Browser abstimmen, und sich dort mit den Inkompatibilitäten herumschlagen. Dieses Kapitel sollte Ihnen einen ersten Eindruck geben, was in Zukunft alles möglich sein wird, und wie dynamische Webseiten der Zukunft aussehen (können). Sie können sich einen Wissensvorsprung verschaffen, wenn Sie sich schon heute mit dieser Thematik beschäftigen, aber es wird noch eine lange Zeit dauern, bis Sie dieses zusätzliche Wissen auch einsetzen können. Wenn Sie diese Materie interessiert, dann lassen Sie es uns bitte über MyGalileo wissen – in einer möglichen Neuauflage werden wir bei entsprechendem Zuspruch diesen Teil erweitern.


Galileo Computing

22.4 Fragen & Aufgaben  toptop

1. Das Listing ohne getElementById() hat einen Bug; klicken Sie beispielsweise stets auf die am weitesten rechts stehende Grafik. Was verursacht diesen Bug?
2. Beheben Sie den Bug aus der vorherigen Aufgabe.
3. Versuchen Sie, das Skript so umzuschreiben, dass auf die src-Eigenschaft der Grafik nicht zugegriffen wird.
  

Perl – Der Einstieg




Copyright © Galileo Press GmbH 2001 - 2002
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken und speichern. Ansonsten unterliegt das <openbook> denselben Bestimmungen wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.
Die Veröffentlichung der Inhalte oder Teilen davon bedarf der ausdrücklichen schriftlichen Genehmigung von Galileo Press. Falls Sie Interesse daran haben sollten, die Inhalte auf Ihrer Website oder einer CD anzubieten, melden Sie sich bitte bei: stefan.krumbiegel@galileo-press.de


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, fon: 0228.42150.0, fax 0228.42150.77, info@galileo-press.de