Diese Seiten sind Teil von Bachsau’s Archiv.
Die hier beschriebenen Praktiken entsprechen nicht mehr dem Stand der Technik!
Bitte nutzen Sie für aktuelle Projekte das fortlaufend aktualisierte SELFHTML-Wiki.

SELFHTML

Das Document Object Model (DOM)

Informationsseite

nach unten Allgemeines zum DOM
nach unten Elementinhalte dynamisch ändern
nach unten HTML-Attribute dynamisch ändern
nach unten CSS-Eigenschaften dynamisch ändern
nach unten Neue Knoten erzeugen und in Baumstruktur einhängen
nach unten Event-Handling beim DOM

 nach unten 

Allgemeines zum DOM

Das Document Object Model (DOM) ist eine vom W3-Konsortium verabschiedete Norm, die zunächst einmal den Programmiersprachen-Zugriff auf beliebige Elemente eines Auszeichnungssprachen-Dokuments beschreibt. Das DOM ist also weder selber eine eigene Programmiersprache, noch ist es auf HTML beschränkt. Es definiert lediglich Objekte, Eigenschaften und Methoden, die eine Programmiersprache umsetzen sollte, wenn sie sich DOM-fähig bezeichnen will. Anwendbar sollen diese Objekte, Eigenschaften und Methoden auf alle Dokumente sein, die in einer Kapitel XML-gerechten Auszeichnungssprache geschrieben sind. Das W3-Konsortium betont ausdrücklich, dass das DOM nicht einfach nur eine Norm für "Dynamic HTML" sein soll. Das DOM ist auch nicht auf die Client-Seite, also etwa den Web-Browser beschränkt. Ebensogut lässt es sich in serverseitigen Programmen, z.B. in Kapitel CGI-Scripten einsetzen, um Dokumente dynamisch zu erzeugen.

Wie auch immer - das DOM ist die willkommene Lösung auch für das, was hier unter dynamischem HTML verstanden wird, also das nachträgliche dynamische Verändern von Inhalten einer im Browser-Fenster angezeigten Web-Seite. 1998 erstmals als offizielle W3C-Empfehlung herausgegeben, wurde es im Internet Explorer 5.0 und in dem von der Mozilla-Entwicklergemeinde völlig neu programmierten Netscape-Browser, den Netscape selber unter der Version 6.0 anbot, implementiert (JavaScript-Version 1.5). Die Implementierung ist in den heutigen Browsern noch nicht vollständig. Immer wieder wird man als Programmierer auf rätselhafte Verhaltensweisen im einen oder anderen Browser stoßen. Dennoch ist die Richtung damit vorgegeben, wie Dynamisches HTML in Zukunft programmiert werden wird.

Eine Auszeichnungssprache wie HTML oder auch jede andere, XML-basierte Sprache ist als hierarchische Seite Baumstruktur abbildbar. Die einzelnen Bestandteile einer solchen Baumstruktur werden als Knoten bezeichnet. Das zentrale Objekt des DOM ist deshalb das Objekt Seite node (node = Knoten). Es gibt verschiedene Knotentypen. Innerhalb eines gewöhnlichen HTML-Dokuments gibt es auf jeden Fall drei wichtige Knotentypen, die Sie unterscheiden müssen: Elementknoten, Attributknoten und Textknoten.

Betrachten Sie zum Verständnis das folgende einfache HTML-Konstrukt:
<h1 align="center">Hallo Welt</h1>
In diesem Konstrukt gibt es einen Elementknoten, nämlich den Elementknoten des h1-Elements. Ferner gibt es einen Attributknoten, nämlich den des align-Attributs. Und schließlich gibt es so genannte "Zeichendaten", die an zwei Stellen vorkommen: nämlich einmal als Inhalt des h1-Elements, und einmal bei der Wertzuweisung an das align-Attribut. Diese Zeichendaten stellen selbst Knoten dar, nämlich Textknoten.

Ein weiteres Beispiel-Konstrukt soll das Verständnis vertiefen:
<h1 align="center">Hallo <i>Welt</i></h1>
In diesem Beispiel ist die Kursiv-Auszeichnung um das Wort Welt hinzugekommen. Wichtig ist dabei nun zu verstehen, wie die Knotenhierarchie aussieht:
Das h1-Element ist in diesem kleinen Strukturbaum-Ausschnitt der Ausgangsknoten. Dieser Knoten hat nach den Regeln des DOM zwei Kindknoten und einen assoziierten Knoten: die Kindknoten sind zum einen der Textknoten mit dem Wort Hallo und dem Leerzeichen dahinter, sowie der Elementknoten des i-Elements. Das align-Attribut im einleitenden <h1>-Tag ist dagegen kein Kindknoten, sondern ein assoziierter Knoten. Der Attributknoten hat jedoch selbst wiederum einen Kindknoten, nämlich den zugewiesenen Wert (center). Auch der Elementknoten des i-Elements hat wieder einen Kindknoten, nämlich den Textknoten seines Zeicheninhalts, also das Wort Welt.

Die Baumstruktur einer komplexen Web-Seite kann, wie sich aus diesen einfachen Beispielen erschließt, sehr umfangreich und tief verschachtelt sein. In einer Script-Sprache muss es aber möglich sein, möglichst schnell und effizient auf einzelne Knoten zugreifen zu können. Im DOM gibt es daher drei wichtige Methoden des Seite document-Objekts, um zumindest auf jeden beliebigen Elementknoten direkt zugreifen zu können:
Seite getElementById() kann auf Elemente zugreifen, die ein dokumentweit eindeutiges id-Attribut enthalten, z.B.
<p id="derAbsatz">hier steht der Text</p>
Seite getElementsByName() kann auf Elemente zugreifen, die einen Namen besitzen (er muss nicht unbedingt eindeutig sein), z.B.
<input name="Eingabefeld" type="text" size="40">
Seite getElementsByTagName() kann auf alle Elemente zugreifen in der Form: "liefere mir das 27. td-Element im Dokument".

Ausgehend von einem ermittelten Elementknoten lässt sich dann schnell auf dessen Attribute und Inhalt zugreifen. Auch dafür stellt das DOM Eigenschaften und Methoden bereit. Dabei gibt es jedoch bei HTML-basierten Web-Seiten zwei Varianten. Einmal können Sie die Eigenschaften und Methoden des Seite node-Objekts dazu verwenden, um auf Kindknoten und assoziierte Knoten eines Elements zuzugreifen. Zum anderen können Sie aber auch die Seite HTML-Elementobjekte benutzen. Vor allem für den Zugriff auf einzelne Attribute eines Elements sind die HTML-Elementobjekte gut geeignet.

Dynamisches HTML kann aber auch darin bestehen, neue Elemente mit Inhalten und Formatierungen zur Anzeigezeit einer Web-Seite neu zu erzeugen. Für diesen Zweck hält das DOM ebenfalls Methoden bereit.

In der Version 1.0 des DOM wurde nur der Zugriff auf Knoten geregelt. Der Zugriff auf zugewiesene Style-Eigenschaften und von Event-Handling ist dort noch ausgespart. In der DOM-Version 2.0 vom November 2000 sind jedoch auch diese für dynamische Web-Seiten wichtigen Gebiete behandelt. Es ist deshalb auf jeden Fall empfehlenswert, bei neu zu erstellenden dynamischen Web-Seiten von den im DOM geregelten Techniken auszugehen. Die älteren Modelle von Seite Microsoft und Seite Netscape sollten derzeit noch aus Gründen der Rückwärtskompatibilität eingesetzt werden, auf die Dauer jedoch langsam aus der Welt verschwinden, damit endlich ein einheitlicher Sprachenstandard das Entwickeln dynamischer Web-Seiten erleichtert.

nach obennach unten

DOM 1.0JavaScript 1.5Netscape 6.0MS IE 5.5Opera 7Mozilla Firefox 1Konqueror 3.1Safari 1.0 Elementinhalte dynamisch ändern

Es gibt viele sinnvolle Anwendungsfälle zum dynamischen Ändern von zunächst angezeigten HTML-Elementen. Das folgende Beispiel zeigt einen davon. In dem Beispiel wird eine nummerierte Liste von Großstädten zunächst alphabetisch sortiert ausgegeben. Unterhalb der Liste kann der Anwender jedoch mit Hilfe zweier Formular-Buttons zwischen alphabetischer Sortierung oder geographischer Sortierung wechseln.

Beispiel:

Beispiel-Seite Anzeigebeispiel: So sieht's aus

<html><head><title>Test</title>
<script type="text/javascript">
var geoArray = new Array(6, 7, 0, 1, 4, 3, 8, 9, 2, 5, 11, 12, 10);
var Art = "ABC";

function ABC () {
  if (Art == "ABC")
    return;
  Art = "ABC";
  var Staedte = new Array();
  for (var i = 0; i < document.getElementsByTagName("li").length; i++)
    Staedte[Staedte.length] = document.getElementsByTagName("li")[i].firstChild.nodeValue;
  Staedte.sort();
  for (i = 0; i < document.getElementsByTagName("li").length; i++)
    document.getElementsByTagName("li")[i].firstChild.nodeValue = Staedte[i];
  document.getElementById("Art").firstChild.nodeValue = "alphabetisch von A bis Z";
}

function GEO () {
  if (Art == "GEO")
    return;
  Art = "GEO";
  var Staedte = new Array();
  for (var i = 0; i < document.getElementsByTagName("li").length; i++)
    Staedte[Staedte.length] = document.getElementsByTagName("li")[i].firstChild.nodeValue;
  for (i = 0; i < document.getElementsByTagName("li").length; i++)
    document.getElementsByTagName("li")[i].firstChild.nodeValue = Staedte[geoArray[i]];
  document.getElementById("Art").firstChild.nodeValue = "geographisch von Nord nach Süd";
}
</script>
</head><body>
<h1>Große Städte <span id="Art">alphabetisch von A bis Z</span></h1>
<ol>
<li>Berlin</li>
<li>Dortmund</li>
<li>Dresden</li>
<li>Düsseldorf</li>
<li>Essen</li>
<li>Frankfurt</li>
<li>Hamburg</li>
<li>Hannover</li>
<li>Köln</li>
<li>Leipzig</li>
<li>München</li>
<li>Nürnberg</li>
<li>Stuttgart</li>
</ol>
<form name="Formular" action="">
<input type="button" name="abc" value="alphabetisch" onclick="ABC()">
<input type="button" name="geo" value="geographisch" onclick="GEO()">
</form>
</body></html>

Erläuterung:

Im Beispiel ist die nummerierte Liste zunächst mit den Städtenamen in alphabetischer Sortierfolge notiert. In dem Formular unterhalb der Liste sind zwei Klick-Buttons notiert. Der eine ruft die Funktion ABC() auf, der andere die Funktion GEO(). Ein Klick auf ABC() bringt natürlich nichts, da die Liste ohnehin alphabetisch sortiert ist. Also empfiehlt sich zunächst der Klick auf den Button mit der Aufschrift geographisch. Die Funktion GEO(), die er aufruft, prüft zunächst über die Variable Art, ob die Liste bereits geographisch sortiert ist. Wenn dies der Fall ist, wird die Funktion vorzeitig mit Seite return ohne Rückgabewert beendet. Andernfalls erfolgt die Sortierung. Dazu wird mit zuerst var Staedte = new Array(); ein neuer, leerer Seite Array definiert. Das Vorhaben ist, diesen Array mit den Städtenamen aus der Liste zu füllen. Dazu greift die Funktion der Reihe nach in einer for-Schleife alle Elemente vom Typ li ab, die in dem Dokument vorkommen.

Der Zugriff erfolgt mit document.getElementsByTagName("li").

Über document.getElementsByTagName("li").length kann die Anzahl der li-Elemente im Dokument ermittelt werden. Diese Information benutzt die Funktion als Abbruchbedingung für die for-Schleife. Innerhalb der Schleife wird dem Array der Inhalt des jeweils aktuellen li-Elements hinzugefügt.

Mit document.getElementsByTagName("li")[i].firstChild.nodeValue wird dabei auf den Inhalt des jeweiligen li-Elements zugegriffen. Aus DOM-Sicht ist document.getElementsByTagName("li")[i] ein Knoten, nämlich der i.te li-Elementknoten im Dokument. firstChild ist eine Eigenschaft des Seite node-Objekts. Über diese Eigenschaft können Sie auf den ersten Kindknoten eines Knotens zugreifen. Der erste Kindknoten aller li-Elemente im Dokument ist deren Textinhalt, also jeweils ein Städtenamen. Die Eigenschaft firstChild liefert aber noch nicht den Inhalt des Elements, sondern nur das Objekt des Inhalts. Um tatsächlich an den Inhalt heranzukommen, also an den konkreten Städtenamen, muss eine weitere Eigenschaft des node-Objekts bemüht werden, nämlich die Eigenschaft nodeValue. Die Kombination firstChild.nodeValue können Sie sich ruhig merken. Diese Kombination werden Sie häufig verwenden, um an den Inhalt eines Elements zu kommen.

Nachdem der Array mit den Städtenamen gefüllt ist, macht die Funktion GEO() einfach das Umgekehrte und schreibt den Array wieder zurück in die Liste - ebenfalls in einer for-Schleife.
Der Ausdruck document.getElementsByTagName("li")[i].firstChild.nodeValue steht diesmal links von der Zuweisung. Dadurch wird dem Inhalt des Listenelements dynamisch ein neuer Wert zugewiesen. Im Beispiel ist das der etwas vertrackst aussehende Wert Staedte[geoArray[i]]. Die Städte sollen ja geographisch ausgegeben werden. Nun gibt es keinen Algorithmus, der die Geographie kennt. Ganz oben im Script-Bereich ist daher ein Array namens geoArray notiert. Die Zahlen, mit denen er initialisiert wird, sind einfach die Indexnummern der alphabetisch sortierten Städte. So hat geoArray[0] beispielsweise den Wert 6. Dank dieser Information weiß die Funktion GEO(), dass die nördlichste der Städte diejenige ist, die in der alphabetischen Sortierung die Indexnummer 6 hat (Hamburg). Mit Staedte[geoArray[i]] benutzt die Funktion als aktuellen Index für die Stadt, die in die Liste geschrieben werden soll, also einfach den Zugriff auf geoArray.

Die Funktion ABC() geht ganz genauso vor wie die Funktion GEO(). Sie unterscheidet sich nur dadurch von letzterer, dass sie nach dem Einlesen des Staedte-Arrays die Objektmethode Seite sort() auf den Array anwendet, um die Einträge zu sortieren. Dann schreibt sie den sortierten Array einfach zurück in die nummerierte Liste.

Ein weiteres Element wird von beiden Funktionen ebenfalls noch geändert: nämlich das span-Element innerhalb der Überschrift. Da für dieses Element im HTML-Code mit id="Art" ein ID-Wert notiert ist, lässt sich mit document.getElementById("Art") bequem darauf zugreifen. Mit der üblichen Syntax firstChild.nodeValue wird der Text des Elements angesprochen und dynamisch geändert.

nach obennach unten

DOM 1.0JavaScript 1.5Netscape 6.0MS IE 5.5Opera 7Mozilla Firefox 1Konqueror 3.1Safari 1.0 HTML-Attribute dynamisch ändern

Durch das dynamische Hinzufügen, Ändern oder Löschen von HTML-Attributen lassen sich interessante Effekte, aber auch nützliche Zwecke erreichen. Das folgende Beispiel zeigt, wie Sie Verweise dynamisch ändern können.

Beispiel:

Beispiel-Seite Anzeigebeispiel: So sieht's aus

<html><head><title>Test</title>
<script type="text/javascript">
var TopLinks = new Array("http://www.spiegel.de/",
                         "http://www.heise.de/newsticker/",
                         "http://www.encarta.msn.de/",
                         "http://paperball.fireball.de/",
                         "http://kochbuch.unix-ag.uni-kl.de/");
var aktuellerLink = 0;

function TopLink () {
  document.getElementsByName("Ziel")[0].href = TopLinks[aktuellerLink];
  document.getElementsByName("Ziel")[0].firstChild.nodeValue = TopLinks[aktuellerLink];
  aktuellerLink += 1;
  if (aktuellerLink >= TopLinks.length)
    aktuellerLink = 0;
}

function TopLinksFenster (Fenster) {
  document.getElementsByName("Ziel")[0].target = Fenster;
}
</script>
</head><body>
<p><a name="Ziel" href="#Ziel">Top-Link?</a><br>
<a href="javascript:TopLink()">Nächster Top-Link!</a><br>
TopLinks: <a href="javascript:TopLinksFenster('_blank')">in neues Fenster laden!</a> oder
<a href="javascript:TopLinksFenster('_self')">ins aktuelle Fenster laden!</a></p>
</body></html>

Erläuterung:

Das Beispiel enthält im sichtbaren Bereich einen "Top-Link", der zunächst auf sich selbst verweist (name="Ziel" href="#Ziel"). Unterhalb davon sind drei weitere Verweise notiert. Der erste verspricht den jeweils nächsten Top-Link zu präsentieren, und die beiden darunter erlauben es dem Anwender festzulegen, wie er die Links öffnen will - ob im gleichen oder in einem neuen Fenster. Alle diese drei Verweise rufen JavaScript-Funktionen auf, die im Dateikopf notiert sind. Der Verweis, der den nächsten Top-Link verspricht, ruft die Funktion TopLink() auf.

Diese Funktion greift mit document.getElementsByName("Ziel")[0] auf das erste Element im Dokument zu, bei dem als Attribut name="Ziel" notiert ist. Das ist im Beispiel bei dem Verweis der Fall, der die TopLinks anzeigen soll und aber bislang auf sich selbst verweist. Geändert werden sollen bei diesem Verweis sowohl sein href-Attribut als auch sein sichtbarer Verweistext. Der Zugriff auf das href-Attribut ist ganz einfach, weil nach der DOM-Syntax der Seite HTML-Elementobjekte jedes denkbare Attribut eines HTML-Elements einfach eine Eigenschaft des entsprechenden HTML-Objekts darstellt. Um auf HTML-Attribute zuzugreifen, brauchen Sie also nur auf das gewünschte Element zuzugreifen und dahinter, durch Punkt getrennt, den Attributnamen als Eigenschaft notieren. Beachten Sie dabei aber die besondere Groß-/Kleinschreibung bei verschiedenen Attributen wie bgColor, vSpace oder cellPadding.
Mit document.getElementsByName("Ziel")[0].href wird im Beispiel also direkt auf den Wert des href-Attributs des gewünschten Verweises zugegriffen. Durch Zuweisung eines Wertes wird das Attribut dynamisch geändert. Im Beispiel wird jeweils ein neuer Wert aus dem weiter oben im Script notierten Seite Array namens TopLinks zugewiesen. Als Indexzähler wird die ebenfalls zuvor schon definierte Variable aktuellerLink verwendet. Diese wird anschließend um 1 erhöht, damit beim nächsten Aufruf der Funktion der nächste Top-Link aus dem Array gesetzt wird. Wenn der Wert von aktuellerLink zu hoch wird, um noch einen Eintrag in dem Array zu finden, wird die Variable wieder auf 0 gesetzt, und beim nächsten Klick wird wieder der erste Eintrag aus dem Array serviert.
Der Zugriff auf den Verweistext erfolgt wieder über firstChild.value.

Die Verweise, die regeln, in welchem Fenster die Top-Links geöffnet werden sollen, rufen jeweils die Funktion TopLinksFenster() auf und übergeben ihr als Parameter den gewünschten Zielfensternamen. Übergeben werden die reservierten Fensternamen _self (Öffnen im eigenen Fenster) bzw. _blank (Öffnen in neuem Fenster). Die Funktion TopLinksFenster() benutzt wieder den bequemen Weg über die HTML-Elementobjekte, um direkt auf die target-Eigenschaft des a-Elements zuzugreifen und das entsprechende Attribut zu setzen. Es ist also kein Problem, Attribute zu setzen, die im HTML-Quelltext eines Elements nicht notiert sind.

Falls Sie mal ein Attribut löschen wollen, haben Sie zwei Möglichkeiten: entweder Sie setzen seinen Wert auf "" (leere Zeichenkette), oder - und das ist sauberer - Sie arbeiten mit der Methode Seite removeAttribute() des node-Objekts.

nach obennach unten

DOM 2.0JavaScript 1.5Netscape 6.0MS IE 5.5Opera 7Mozilla Firefox 1Konqueror 3.1Safari 1.0 CSS-Eigenschaften dynamisch ändern

Seit der DOM-Version 2.0 wird auch geregelt, wie auf Stylesheet-Angaben zugegriffen wird. Dabei hat man sich weitgehend an das seinerzeit von Microsoft eingeführte Seite style-Objekt angelehnt.
Das folgende Beispiel zeigt, wie Sie mit Hilfe der DOM-Technik typisches, klassisches dynamisches HTML mit Bewegung positionierter Elemente schreiben. Dazu dient die Möglichkeit, Elemente mit Hilfe von CSS-Eigenschaften absolut zu positionieren.

Beispiel:

Beispiel-Seite Anzeigebeispiel: So sieht's aus

<html><head><title>Test</title>
<script type="text/javascript">
var rp, bp, ich;
var rpGeschw = 10, bpGeschw = 20;
var rpGrad = 0, bpGrad = 0;
var rpX = 170, rpY = 170, bpX = 170, bpY = 170;
var rpRadius = 150, bpRadius = 150;

function Init () {
  rp = document.getElementById("roterPunkt");
  bp = document.getElementById("blauerPunkt");
  ich = document.getElementById("ich");
  rp.style.position = "absolute";
  rp.style.top = 20 + "px";
  rp.style.left = 320 + "px";
  bp.style.position = "absolute";
  bp.style.top = 320 + "px";
  bp.style.left = 320 + "px";
  ich.style.position = "absolute";
  ich.style.top = 110 + "px";
  ich.style.left = 90 + "px";
  ich.style.fontFamily = "Courier New,Courier";
  ich.style.fontSize = "96px";
  ich.style.fontWeight = "bold";
  ich.style.color = "#009900";
  rpKreis();
  bpKreis();
}

function rpKreis () {
  rpGrad += rpGeschw / 1000;
  if (rpGrad > 360)
    rpGrad = 0;
  rp.style.top = Math.round(rpY + (rpRadius * Math.cos(rpGrad))) + "px";
  rp.style.left = Math.round(rpX + (rpRadius * Math.sin(rpGrad))) + "px";
  window.setTimeout("rpKreis()", 100 / rpGeschw);
}

function bpKreis () {
  bpGrad += bpGeschw / 1000;
  if (bpGrad > 360)
    bpGrad = 0;
  bp.style.top = Math.round(bpY + (bpRadius * Math.cos(bpGrad))) + "px";
  bp.style.left = Math.round(bpX + (bpRadius * Math.sin(bpGrad))) + "px";
  window.setTimeout("bpKreis()", 100 / bpGeschw);
}
</script>
</head><body onload="Init()">

<div id="roterPunkt"><img src="ichkreis1.gif" width="20" height="20" border="0" alt="roter Punkt"></div>
<div id="blauerPunkt"><img src="ichkreis2.gif" width="20" height="20" border="0" alt="blauer Punkt"></div>
<div id="ich">ICH</div>

</body></html>

Erläuterung:

Innerhalb des body-Bereichs werden im Beispiel einfach nur drei div-Bereiche ohne weitere Formatierungen notiert. Die ersten beiden enthalten jeweils eine kleine Grafik - ichkreis1.gif ist ein roter Punkt, ichkreis2.gif ein blauer Punkt. Beide Grafiken haben einen transparenten Hintergrund, was wichtig ist, da sich die Punkte im späteren Verlauf des Geschehens öfter überlagern werden.

Im einleitenden <body>-Tag ist der Seite Event-Handler onload notiert. Dieser tritt in Aktion, sobald die Datei vollständig im Browser geladen ist. Dann wird die Funktion Init() aufgerufen, die im Dateikopf notiert ist. Diese Funktion speichert zunächst einmal Referenzen auf die drei div-Elemente in den drei Variablen rp, bp und ich, um die darauffolgenden Zugriffe auf diese Elemente zu verkürzen. Da alle drei div-Bereiche ein id-Attribut haben, ist der Zugriff auf den entsprechenden Elementknoten mit getElementById("roterPunkt") usw. möglich. Anschließend lässt sich mit rp usw. genauso arbeiten, als wenn man jedesmal wieder document.getElementById("roterPunkt") notieren würde.

Über die Variablen rp, bp und ich ist dann auch das style-Objekt ansprechbar. Die Funktion Init() stattet die drei div-Bereiche erst einmal mit anfänglichen CSS-Eigenschaften aus. Alle drei Bereiche werden mit style.position = "absolute" absolut positioniert. Die linke obere Ecke jedes Bereichs wird mit style.left und style.top bestimmt. Der Inhalt des ich-Bereichs, also das Wort ICH, wird groß und auffällig formatiert.

Am Ende ruft die Funktion Init() die beiden anderen Funktionen rpKreis() und bpKreis() auf. Jede dieser beiden Funktionen kontrolliert die Kreisbewegung jeweils eines der beiden Punkte, indem sie letztlich die linke obere Ecke des div-Bereichs, der die jeweilige Grafik enthält, neu berechnet. Dabei kommen die Kreisfunktionen für Sinus (Seite Math.sin()) und Cosinus (Seite Math.cos()) zum Einsatz. Am Ende ruft jede der beiden Funktionen sich selber rekursiv mit Seite window.setTimeout() wieder auf, um die nächste Position des div-Bereichs mit der Grafik zu setzen. Die Variablen wie bpGrad, bpGeschw usw., mit denen diese Funktionen arbeiten, wurden zuvor im globalen Bereich des Scripts initialisiert.

nach obennach unten

DOM 1.0JavaScript 1.5Netscape 6.0MS IE 5.5Opera 7Mozilla Firefox 1Konqueror 3.1Safari 1.0 Neue Knoten erzeugen und in Baumstruktur einhängen

Dynamisches HTML nach DOM bedeutet nicht nur, auf bereits in HTML vorhandene Elemente zuzugreifen, sondern auch neue zu erzeugen und in den Strukturbaum einzuhängen. Wie das funktioniert, zeigt das folgende Beispiel. Es stellt einen primitiven HTML-Editor dar.

Beispiel:

Beispiel-Seite Anzeigebeispiel: So sieht's aus

<html><head><title>Test</title>
<style type="text/css">
body { color:#000000; background-color:#FFFFFF; }
#User { background-color:#FFFFC0; padding:10px; }
form { background-color:#EEEEEE; padding:10px; }
h1 { font-family:Arial,sans-serif; font-size:2.2em; font-weight:normal; border-bottom:2px solid red; }
h2 { font-family:Arial,sans-serif; font-size:1.8em; font-weight:normal; border-bottom:1px solid red; }
h3 { font-family:Arial,sans-serif; font-size:1.1em; font-weight:bold; }
p { font-family:Arial,sans-serif; font-size:1em; }
</style>
<script type="text/javascript">
function Hinzufuegen () {
  var Typ = document.Formular.Elementtyp.options[document.Formular.Elementtyp.selectedIndex].value;
  var Elementknoten = document.createElement(Typ);
  if (Typ != "hr") {
    var Textknoten = document.createTextNode(document.Formular.Elementinhalt.value);
    Elementknoten.appendChild(Textknoten);
  }
  document.getElementById("User").appendChild(Elementknoten);
}
</script>
</head><body>

<form name="Formular" action="">
<select name="Elementtyp" size="1">
<option value="h1">Überschrift 1</option>
<option value="h2">Überschrift 2</option>
<option value="h3">Überschrift 3</option>
<option value="p">Textabsatz</option>
<option value="hr">Trennlinie</option>
</select>
<input type="text" name="Elementinhalt" size="50">
<input type="button" value="Hinzufügen" onclick="Hinzufuegen()">
</form>

<div id="User">
</div>

</body></html>

Erläuterung:

Das Beispiel enthält im sichtbaren HTML-Bereich ein Formular mit einer Auswahlliste, einem Eingabefeld und einem Klick-Button. Unterhalb ist noch ein div-Bereich notiert, der jedoch noch keinen konkreten Inhalt hat. In der Auswahlliste des Formulars kann der Anwender einen HTML-Elementtyp auswählen - in den value-Attributen der option-Elemente sind die tatsächlichen HTML-Elementnamen der jeweiligen Auswahl gespeichert. Im Eingabefeld des Formulars kann der Anwender den Textinhalt für das ausgewählte Element eingeben. Wenn er dann auf den Button klickt, wird die Funktion Hinzufuegen() aufgerufen, die im Dateikopf in einem JavaScript-Bereich notiert ist.

Dort wird erst einmal der lange, umständliche Ausdruck document.Formular.Elementtyp.options[document.Formular.Elementtyp.selectedIndex].value in der Variablen Typ gespeichert. Der lange Ausdruck bzw. die Variable speichert den vom Anwender im Formular ausgewählten HTML-Elementtyp, also z.B. "h1" oder "p".

Mit document.createElement(Typ) wird dann ein leeres, neues Element vom Typ Typ erzeugt, also je nach Wert der Variablen Typ z.B. ein h1-Element oder ein p-Element. Damit wird das Element aber noch nicht angezeigt. document.createElement() erzeugt lediglich den Elementknoten, hängt ihn aber noch nicht in den Strukturbaum des Dokuments ein. Im Folgenden muss das Script zwischen Elementen unterscheiden, die einen Textinhalt haben, und solchen, die keinen haben. Das hr-Element für Trennlinien, das der Anwender ebenfalls auswählen kann, kann keinen Textinhalt haben. Alle anderen auswählbaren Elemente dagegen können Textinhalt haben. Durch eine if-Anweisung wird daher abgefragt, ob die Variable Typ den Wert "hr" besitzt. Nur wenn dies nicht der Fall ist, wird der Textknoten mit der Methode document.createTextNode() erzeugt. Als Parameter erhält diese Methode den Text, den der Anwender ins Eingabefeld des Formulars eingegeben hat. Danach wird der Textknoten an den erzeugten Elementknoten gehängt, sodass der Text letztendlich auch sichtbar ist. In allen Fällen wird schließlich das neu erzeugte und in der Variablen Elementknoten gespeicherte Element in den Dokumentbaum eingehängt.

Für alle "Einhäng"-Vorgänge wird die Methode appendChild() des Seite node-Objekts verwendet. Anwendbar ist die Methode auf ein Knotenobjekt, das Kindknoten haben darf. Also beispielsweise Elementknoten. Als Parameter erwartet die Methode einen Knoten, der als Kindknoten eingehängt werden soll.
Wenn im Beispiel also steht: Elementknoten.appendChild(Textknoten);
Dann ist Elementknoten eine Variable, in der zuvor durch createElement() ein Elementobjekt erzeugt wurde, und Textknoten ist eine Variable, die zuvor durch Aufruf von createTextNode() einen Textknoten gespeichert hat.
Mit der Anweisung document.getElementById("User").appendChild(Elementknoten) wird auf den zunächst leeren div-Bereich im Dokument zugegriffen. Diesem Element wird der neu erzeugte Elementknoten hinzugefügt.

nach obennach unten

DOM 2.0JavaScript 1.5Netscape 6.0Opera 7Mozilla Firefox 1Konqueror 3.1Safari 1.0 Event-Handling beim DOM

Die Normierung des Event-Handling im DOM war zum Redaktionszeitpunkt dieses Dokuments noch nicht abgeschlossen - so fehlte beispielsweise noch die Implementierung von Tastaturereignissen. Der Internet Explorer interpretiert auch noch keine Events nach DOM-Syntax, Netscape 6 dagegen schon. Das folgende Beispiel zeigt das Prinzip, nach dem Event-Handling nach DOM-Syntax funktioniert.

Beispiel:

Beispiel-Seite Anzeigebeispiel: So sieht's aus

<html><head><title>Test</title>
<script type="text/javascript">
function Ausgeben(Text) {
  var LogEintrag = document.createElement("li");
  var neuerText = document.createTextNode(Text);
  LogEintrag.appendChild(neuerText);
  document.getElementById("Log").appendChild(LogEintrag);
}

function handleEingabefeldClick (Event) {
  var Text = "Sie haben in das Eingabefeld geklickt. " +
    "Event-Typ = " + Event.type + ", " +
    "Event-Target-Elementname = " + Event.target.nodeName + ".";
  Ausgeben(Text);
}

function handleBereichMove (Event) {
  var Text = "Sie haben die Maus im Bereich bewegt. " +
    "X-Position = " + Event.clientX + ", " +
    "Y-Position = " + Event.clientY + ".";
  Ausgeben(Text);
}

function handleBereichClick (Event) {
  var Text = "Sie haben in den Bereich geklickt. " +
    "X-Position = " + Event.clientX + ", " +
    "Y-Position = " + Event.clientY + ".";
  Ausgeben(Text);
}

function Init () {
  document.getElementById("Eingabe").addEventListener("click", handleEingabefeldClick, false);
  document.getElementById("Bereich").addEventListener("mousemove", handleBereichMove, false);
  document.getElementById("Bereich").addEventListener("click", handleBereichClick, false);
}
</script>
<style type="text/css">
#Formular { background-color:#EEEEEE; padding:10px }
#Bereich { background-color:#FF0000; color:#FFFFFF; font-weight:bold; width:100px; }
#Log { font-family:Arial,sans-serif; font-size:80%; }
</style>
</head><body onload="Init()">

<form name="Formular" id="Formular" action="">
<input type="text" name="Eingabe" id="Eingabe" size="50">
</form>

<div id="Bereich">Ein Bereich</div>

<ol id="Log">
<li>Ereignisliste</li>
</ol>

</body></html>

Erläuterung:

Im sichtbaren Bereich der HTML-Datei ist ein Formular mit einem Eingabefeld notiert, ferner ein div-Bereich, und schließlich eine leere, nummerierte Liste. Im einleitenden <body>-Tag ist der Event-Handler onload notiert, der jedoch noch nichts mit Event-Handling nach DOM-Syntax zu tun hat. Dort wird einfach erst mal die Funktion Init() aufgerufen, die im Dateikopf notiert ist.

Innerhalb der Funktion Init() geht es jedoch in Sachen DOM-Event-Handling zur Sache. Event-Handling besteht beim DOM zunächst einmal darin, für einen beliebigen Knoten im Dokument eine Ereignisüberwachung zu registrieren. Dazu gibt es die Methode addEventListener(). Mit dem Teil davor, im Beispiel etwa document.getElementById("Eingabe"), wird derjenige Knoten im Dokument angesprochen, für den eine Ereignisüberwachung registriert werden soll. Im Beispiel der Funktion Init() werden insgesamt drei Ereignisüberwachungen angestoßen: eine für das Eingabefeld des Formulars, und zwei für den div-Bereich.

Die Methode addEventListener() erwartet drei Parameter. Der erste Parameter gibt an, welcher Ereignistyp überwacht werden soll. Bei Mausereignissen sind das weitgehend die aus dem JavaScript-Objekt Seite event bekannten Ereignistypen wie click, mouseover, mousedown, mouseup, mousemove. Dazu kommen im DOM Event-Typen wie DOMFocusIn (Knoten erhält den Fokus), DOMFocusOut (Knoten verliert den Fokus), DOMActivate (Knoten wird durch Mausklick oder Tastendruck aktiviert), sowie anwenderunabhängige Ereignisse wie DOMSubtreeModified (Strukturbaum geändert), DOMNodeInserted (Knoten in Strukturbaum eingefügt) oder DOMNodeRemoved (Knoten aus Strukturbaum entfernt). Der Name des gewünschten Ereignistyps muss bei der Parameterangabe in Anführungszeichen stehen.

Der zweite Parameter, den addEventListener() erwartet, ist der Name einer Funktion, die beim Eintreten des Events aufgerufen werden soll. Der Name der Funktion wird ohne Anführungszeichen angegeben. Die angegebene Funktion bekommt automatisch ein Ereignisobjekt übergeben und kann dann damit anfangen was sie will. Dazu weiter unten mehr.

Die Ereignisse werden beim DOM-Event-Handling in drei Phasen verarbeitet: 1. die Capture-Phase (engl. einfangen), 2. die Target-Phase (engl. Ziel) und 3. die Bubbling-Phase (engl. aufsteigen). In der Capture-Phase läuft das Ereignis von dem äußersten Element des DOM-Baums (dem html-Element) zu dem Ziel-Element, für das das Ereignis bestimmt ist. Auf diesem Weg werden alle Event-Handler ausgelöst, die für die passierten Elemente für die Capture-Phase registriert sind. In der Target-Phase werden alle Event-Handler ausgelöst, die für das Ziel-Element registriert sind. In der Bubbling-Phase schließlich wandert das Ereignis schließlich vom Ziel-Element über dessen Eltern-Elemente zurück zum äußersten Element. In dieser Phase werden alle Event-Handler ausgelöst, die für die passierten Elemente für die Bubbling-Phase registriert sind. Nicht bei allen Ereignistypen steigen die Ereignisse auf (Bubbling).

Mit dem dritten Parameter von addEventListener() können Sie bestimmen, in welcher Phase ein Event-Handler aktiv wird. Mit true wird die Handler-Funktion in der Capture-Phase aufgerufen, mit false in der Target- oder Bubbling-Phase. In der Regel sollten Sie false wählen. Dieses Verhalten stellt einen Kompromiss zwischen der Seite Vererbung bei Events (Event-Bubbling) bei dem Seite älteren DHTML-Modell von Microsoft und der Funktion Seite captureEvents() bei dem Seite älteren DHTML-Modell von Netscape dar.

Für jedes Ereignis, das Sie überwachen wollen, benötigen Sie eine Funktion, die auf das Ereignis reagiert - die sogenannte Handler-Funktion. Es ist die Funktion mit dem Namen, der bei addEventListener() als zweiter Parameter angegeben wird. Im obigen Beispiel sollen drei Ereignisse überwacht werden. Deshalb gibt es drei ähnliche Funktionen - mit den Namen handleEingabefeldClick(), handleBereichMove() und handleBereichClick(). Alle drei Funktionen bekommen beim automatischen Aufruf, der beim Eintritt des Ereignisses passiert, das Ereignis als Objekt übergeben. Die Funktionen im Beispiel erwarten deshalb einen Parameter Event. Dieses Ereignisobjekt besitzt Eigenschaften, die Informationen zum Ereignis bereitstellen, und Methoden, mit denen sich die Ereignisverarbeitung steuern lässt. Bei Mausereignissen gibt es beispielsweise Eigenschaften wie clientX (Anzahl Pixel vom linken Rand des sichtbaren Knotenbereichs), clientY (Anzahl Pixel vom oberen Rand des sichtbaren Knotenbereichs), screenX (Anzahl Pixel vom linken Bildschirmrand) oder screenY (Anzahl Pixel vom oberen Bildschirmrand).

Im Beispiel stellen die Funktionen, die ein Ereignis überwachen, einfach nur einen Text zusammen und rufen dann die Funktion Ausgeben() mit dem zusammengestellten Text auf. Die Funktion Ausgeben() erzeugt zuerst mit document.createElement("li") ein neues HTML-Element vom Typ li. Dann erzeugt sie mit document.createTextNode(Text) einen neuen Textknoten mit dem übergebenen Text. Schließlich hängt sie den Textknoten mit appendChild() als Kindknoten in den erzeugten li-Elementknoten ein, und diesen in die im Dokument notierte nummerierte Liste. Auf diese Weise füllt sich die nummerierte Liste dynamisch mit jedem Ereignis, das erkannt wurde.

Beachten Sie:

Noch nicht alle Browser, die prinzipiell Ereignisüberwachung nach DOM-Syntax unterstützen, führen Handler-Funktionen, die für die Capture-Phase registriert sind, korrekt aus. Solche Handler-Funktionen werden nur aktiviert, wenn sich das Ziel-Element des Ereignisses unterhalb des Elements befindet, bei dem die Handler-Funktion für die Capture-Phase registriert wurde. Mozilla Firefox und Safari rufen die Funktion irrtümlicherweise trotzdem auf.

Im Beispiel wurde die herkömmliche Methode onload="Init()" verwendet, um die Funktion Init() beim abgeschlossenen Laden der HTML-Datei aufzurufen, um darin die restliche Ereignisüberwachung zu starten. Diese ist theoretisch durch folgende Konstruktion ersetzbar:

document.addEventListener("load", Init, false);

Allerdings passiert im Mozilla Firefox 1.5 kein load-Ereignis am document-Objekt, obwohl dies im DOM-Standard so vorgeschrieben ist. Eine Alternative wäre die Verwendung von window.addEventListener("load", Init, false). Dies wird zwar breiter unterstützt, allerdings liegt das window-Objekt außerhalb des DOM-Standards.

 nach oben
weiter Seite Das ältere DHTML-Modell von Microsoft
zurück Seite Allgemeines zu Dynamischem HTML
 

© 2007 Seite Impressum

Originaladresse dieses Dokuments: http://de.selfhtml.org/dhtml/modelle/dom.htm