Galileo Computing < openbook >
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.


Kompendium der Informationstechnik
 von Sascha Kersken
EDV-Grundlagen, Programmierung, Mediengestaltung
Buch: Kompendium der Informationstechnik
gp Kapitel 19 JavaScript
  gp 19.1 JavaScript-Einführung
  gp 19.2 JavaScript im HTML-Dokument
    gp 19.2.1 Erstes Beispiel: Ausgabe ins Dokument
  gp 19.3 Formulare und Event-Handler
    gp 19.3.1 Zugriff auf Formulare und ihre Elemente
    gp 19.3.2 Neufassung des Rechners mit einem Formular
    gp 19.3.3 Die Hintergrundfarbe dynamisch ändern
    gp 19.3.4 Formularauswertung
  gp 19.4 Datums- und Uhrzeit-Funktionen
    gp 19.4.1 Datums- und Uhrzeit-Methoden
    gp 19.4.2 Das Timeout – die JavaScript-»Stoppuhr«
    gp 19.4.3 Ein ausführliches Beispiel
  gp 19.5 Manipulation von Bildern
    gp 19.5.1 Erstes Beispiel: Austauschen eines Bildes auf Knopfdruck
    gp 19.5.2 Vorausladen von Bildern
    gp 19.5.3 Eine gut funktionierende Rollover-Lösung
    gp 19.5.4 Weitere Beispiele
  gp 19.6 Browser- und Fenster-Optionen
    gp 19.6.1 Browser-Eigenschaften
    gp 19.6.2 Automatische Hyperlinks – History und Location
  gp 19.7 DHTML und die Objektmodelle der Browser
    gp 19.7.1 W3C-DOM
    gp 19.7.2 Das klassische Internet-Explorer-Modell
    gp 19.7.3 Das klassische Netscape-Modell
    gp 19.7.4 Browserübergreifende Lösungen
  gp 19.8 Zusammenfassung

gp

Prüfungsfragen zu diesem Kapitel (extern)


Galileo Computing

19.7 DHTML und die Objektmodelle der Browser  downtop

Seit 1998 die 4er-Versionen der beiden wichtigsten Browser eingeführt wurden, ist das Schlagwort Dynamic HTML (kurz DHTML) eine der Lieblingsvokabeln aller Webdesigner. Für einen Begriff, der gar keine einheitliche Technologie beschreibt, ist das bemerkenswert: Die Bezeichnung DHTML ist in den Marketingabteilungen von Microsoft und Netscape entstanden. Es handelt sich um die Zusammenarbeit zwischen Stylesheets zur Formatierung von HTML-Inhalten und neueren JavaScript-Fähigkeiten.

Die verschiedenen Objektmodelle

Insbesondere wurden in den 4er-Browsern zum ersten Mal so genannte Objektmodelle eingeführt, die es ermöglichen, einen Großteil der Elemente in HTML-Dokumenten anzusprechen und auch nach dem Laden des Dokuments noch dynamisch zu verändern. Ärgerlicherweise müssen Sie in der Praxis drei verschiedene Objektmodelle berücksichtigen, die zueinander inkompatibel sind:

gp  Das W3C hat das Document Object Model (DOM) standardisiert. Es ermöglicht konsequent die nachträgliche Änderung jedes beliebigen Elements eines HTML-Dokuments, indem es das Dokument als hierarchisch verschachtelte Baumstruktur versteht. Das DOM ist nicht nur für JavaScript und HTML gedacht, sondern wurde in vielen verschiedenen Programmiersprachen für den Zugriff auf XML-Dokumente aller Art implementiert. In Kapitel 15, XML, wird beispielsweise die Verwendung des DOM in Java kurz eingeführt.
    DOM wird von folgenden Browsern interpretiert: Internet Explorer ab 5.0, Netscape ab 6.0, Mozilla und Opera ab 6.0.
       
gp  Der Internet Explorer ab der Version 4.0 unterstützt ein eigenes Objektmodell, dessen Möglichkeiten fast genau so weit gehen wie bei DOM. Allerdings funktioniert der Zugriff auf die Elemente völlig anders. Dieses Modell kann auch in neueren Explorer-Versionen verwendet werden, obwohl sie auch DOM unterstützen.
gp  Das eigene Objektmodell des Netscape Communicators 4.x bietet deutlich weniger Möglichkeiten als die beiden anderen. Es beschränkt sich im Grunde auf die Manipulation von Layer-Objekten, das heißt auf spezielle <div>-Tags, die frei positioniert werden können und die Netscape mit einem eigenständigen document-Objekt zur Inhaltsänderung ausgestattet hat.
    Das wirklich Ärgerliche an diesem Objektmodell ist allerdings, dass es von Netscape-Versionen ab 6.0 gar nicht mehr unterstützt wird; diese Browser verwenden nur noch DOM. Deshalb sind viele alte DHTML-Sites im Web, die lediglich zwischen dem alten Internet Explorer- und dem alten Netscape-Objektmodell unterscheiden, in neueren Netscape-Versionen und unter Mozilla nicht mehr lauffähig.
       

Galileo Computing

19.7.1 W3C-DOM  downtop

Mit Hilfe von DOM können Sie auf jedes einzelne Element einer Webseite zugreifen. Dazu wird das Objekt als Baum-Modell aus verschiedenen Arten von Knoten betrachtet. Jeder Knoten kann beliebig viele Kindknoten besitzen. Jeder Knoten besitzt einen der in Tabelle 19.1 gezeigten Knotentypen, der über seine Eigenschaft nodeType abgefragt werden kann:


Tabelle 19.1   DOM-Knotentypen für HTML-Dokumente

Knotentyp Bedeutung
1 Element (HTML-Tag)
2 Attribut (funktioniert so nicht!)
3 einfacher Text
8 HTML-Kommentar
9 das Dokument selbst

Es existieren zwei verschiedene Möglichkeiten, auf einen Knoten vom Typ HTML-Tag zuzugreifen:

gp  Die Methode
document.getElementById (ID-String) 
    liefert eine Referenz auf das Tag zurück, dem über das Attribut id eine spezielle ID zugewiesen wurde. Beispielsweise können Sie auf einen Absatz, der so definiert wurde,
       
<p id="test">Spezieller Absatz, Marke test</p>
    mit Hilfe dieser DOM-Methode zugreifen:
       
document.getElementById ("test")
gp  Mit Hilfe der Methode
document.getElementsByTagName (Tag-String) 
    erhalten Sie eine Referenz auf ein Array aller Elemente, die dem angegebenen HTML-Tag entsprechen. Beispielsweise entspricht der folgende Ausdruck dem dritten <p>-Tag einer Seite:
       
document.getElementsByTagName ("p")[2]

Auf Text- und Kommentarknoten können Sie nicht direkt zugreifen. Sie sind stets Kindknoten der umschließenden HTML-Tags. Auf die Kindknoten eines Elements sowie auf seinen Elternknoten und seine »Geschwister« können Sie mit Hilfe der in Tabelle 19.2 gezeigten Eigenschaften zugreifen:


Tabelle 19.2   Zugriff auf DOM-Kindknoten

Eigenschaft Bedeutung
Knoten.firstChild liefert das erste Kindelement von Knoten
Knoten.childNodes[] ein Array aller Kindknoten von Knoten
Knoten.lastChild liefert den letzten Kindknoten von Knoten
Knoten.parentNode liefert den übergeordneten Knoten
Knoten.nextSibling liefert den nächsten »Geschwisterknoten«, also den nachfolgenden Kindknoten desselben Elternknotens
Knoten.previousSibling liefert den vorigen »Geschwisterknoten«
Knoten.hasChildNodes() diese Methode liefert true, wenn Knoten Kindelemente besitzt, ansonsten false

Textknoten-Eigenschaften

HTML-Tag-Knoten besitzen die Eigenschaft nodeName, die den Namen des eigentlichen HTML-Tags enthält. Text- und Kommentarknoten weisen dagegen die Eigenschaft nodeValue auf, die den Textinhalt enthält. nodeValue liefert möglicherweise etwas anderes zurück als Sie erwarten. Betrachten Sie beispielsweise den folgenden Auszug aus dem Body eines HTML-Dokuments:

<p id="test">Dies ist der <i>alte</i> Text.</p>
<script language="JavaScript" type="text/javascript">
<!--
 
   alert (document.getElementById ("test")
          .firstChild.nodeValue);
 
//-->
</script>

Die alert()-Anweisung greift zunächst über die Methode getElementById() auf den Absatz mit der ID test zu. Anschließend liest sie per nodeValue den Textinhalt ihres ersten Kindknotens (firstChild). Vielleicht überrascht es Sie, zu hören, dass das Ergebnis nicht so lautet:

Dies ist der alte Text

Vielmehr bekommen Sie lediglich Folgendes zu sehen:

Dies ist der

Der Text »Dies ist der« bildet den ersten Kindknoten des Absatzes, das HTML-Tag <i>...</i> ist der zweite und der restliche »Text« der letzte.

Textknoten ändern

Das nächste Beispiel verwendet einige dieser Methoden und Eigenschaften zur Anzeige der aktuellen Uhrzeit im Fließtext eines Absatzes. Der Absatz selbst wird so definiert:

<p id="uhr">Uhrzeit</p>

Im Head steht folgende Funktion, die im <body>-Tag im Event-Handler onload aufgerufen werden sollte:

function zeit ()  {
   var jetzt = new Date();
   var std = jetzt.getHours();
   var min = jetzt.getMinutes();
   var sek = jetzt.getSeconds();
   var zeitangabe = std < 10 ? "0" : "";
   zeitangabe += std + ":";
   zeitangabe += min < 10 ? "0" : "";
   zeitangabe += min + ":";
   zeitangabe += sek < 10 ? "0" : "";
   zeitangabe += sek;
   document.getElementById ("uhr").firstChild.
      nodeValue = "Es ist " + zeitangabe + " Uhr";
   setTimeout ("zeit();", 1000);
}

Das Thema Datums- und Uhrzeitanzeige wurde bereits weiter oben in diesem Kapitel behandelt. Neu ist hier lediglich die Zeile

document.getElementById ("uhr").firstChild.
      nodeValue = "Es ist " + zeitangabe + " Uhr";

Über getElementById() wird der Absatz mit der ID uhr angesprochen. Dessen erster Kindknoten firstChild ist der Absatztext, der mit Hilfe einer Wertzuweisung an seine Eigenschaft nodeValue geändert wird.


Abbildung 19.3   Die DOM-Baum-Anzeige in Aktion

Abbildung
Hier klicken, um das Bild zu Vergrößern


Eine DOM-Baum-Anzeige

Das folgende Beispiel durchwandert rekursiv den DOM-Baum des aktuellen Dokuments und gibt in einem separaten Fenster Informationen über alle Knoten aus, die es dabei findet. Abbildung 19.3 zeigt das Skript bei der Arbeit.

Listing 19.9 zeigt zuerst den Quellcode des gesamten HTML-Dokuments.

Listing 19.10   Den DOM-Baum des aktuellen Dokuments ausgeben

<html>
  <head>
    <title>DOM-Baumdiagramm</title>
    <script language="JavaScript">
    <!--
 
        var infofenster;
           function initDOMTree ()  {
           infofenster = 
              open ("", "", "width=400,height=400");
           showDOMTree (document, 0);
        }
           function showDOMTree (knoten, indentation)  {
           var typ = knoten.nodeType;
           var typtext, info;
           switch (typ) {
              case 1: 
                 typtext = "HTML-Tag";
                 info = knoten.nodeName;
                 break;
              case 3:
                 typtext = "Text";
                 info = knoten.nodeValue;
                 break;
              case 8:
                 typtext = "Kommentar";
                 info = knoten.nodeValue;
                 break;
              case 9:
                 typtext = "Dokument";
                 info = "Das ganze HTML-Dokument";
                 break;
              default:
                 typtext = "Anderer Typ";
                 info = "XML-Dokument?";
           }
           // Einrücken
           for (var i = 0; i < indentation; i++) {
              infofenster.document.write 
                   ("&nbsp;&nbsp;&nbsp;&nbsp;");
           }
           infofenster.document.write ("<b>" + typtext 
                 + "</b> (<i>" + info + "</i>)<br />");
           // Kinder rekursiv bearbeiten
           if (knoten.hasChildNodes ()) {
              for (var j = 0; 
                   j < knoten.childNodes.length; j++) {
                 showDOMTree (knoten.childNodes[j], 
                    indentation + 1);
              }
           }
        }
       //-->
    </script>
  </head>
  <body onload="initDOMTree();">
    <!-- Jetzt geht's los! -->
    <font size="4" color="#FF0000">Hier sehen Sie 
    <i>die DOM-Baumstruktur <b>des aktuellen 
    <u>Dokuments</u></b></i>.</font>
  </body>
</html>

Im Grunde verwendet das Skript nur Funktionen, die bereits besprochen wurden, und benötigt deshalb nicht viel an Erläuterungen.

Für die eigentliche Rekursion wird mit Hilfe der Methode knoten.hasChildNodes() überprüft, ob überhaupt Kindknoten vorhanden sind. Ist dies der Fall, dann werden sie in einer Schleife über alle Elemente des Arrays knoten.childNodes[] durchlaufen. Für jedes Kindelement wird wiederum die Funktion selbst aufgerufen; dabei wird der um 1 erhöhte Wert der Variablen indentation übergeben, um jeweils die korrekte Einrückung vorzunehmen.

Beachten Sie bitte zuletzt, dass die explizite Deklaration der Schleifenzähler i und j mittels var hier absolut notwendig ist, weil sie ansonsten als globale Variablen betrachtet würden und so bei der Rekursion die falschen Werte hätten.

DOM-Anwendung in der Praxis

Das wichtigste Anwendungsgebiet von DOM ist es, nachträglich Veränderungen an Struktur und Inhalt des Dokuments vorzunehmen. Am häufigsten wird es verwendet, um die Positionierung und andere per Stylesheet definierte Eigenschaften von Layers zu ändern. Die bereits in Kapitel 16, HTML, vorgestellten Layers sind frei schwebende <div>-Elemente, die über das CSS-Attribut position an eine bestimmte Stelle gesetzt werden. Die festgelegte Position kann nachträglich geändert werden, um Animationen zu erzeugen. Abgesehen davon können Sie auch jede andere CSS-Eigenschaft ändern, beispielsweise Farben, Schriftformatierungen, die generelle Sichtbarkeit oder die Stapelreihenfolge.

CSS-Formatierungen dynamisch ändern

Über die DOM-Eigenschaft style können Sie auf die Stylesheet-Formatierungen von Layers (und beliebigen anderen HTML-Elementen) zugreifen und diese dynamisch ändern. Dabei besitzt style jeweils Untereigenschaften, deren Namen mit den Original-CSS-Attributen übereinstimmen. So können Sie etwa über top und left die Position eines absolut positionierten Layers ändern oder mittels color die Schriftfarbe modifizieren. Die einzige Besonderheit gilt für diejenigen Attribute, deren CSS-Name einen Bindestrich enthält: Statt dieses Sonderzeichens wird in üblicher JavaScript-Bezeichner-Konvention der darauf folgende Buchstabe großgeschrieben – aus background-color wird beispielsweise backgroundColor; text-align wird zu textAlign.

Die Werte für die jeweiligen Stil-Eigenschaften sind Strings, deren Inhalt auf dieselbe Weise festgelegt wird wie bei Stylesheet-Angaben. Betrachten Sie zum Beispiel den folgenden Absatz:

<p id="info">Der Hintergrund dieses Absatzes 
kann gelb werden!</p>

Mit Hilfe der folgenden JavaScript-Anweisung können Sie seinen Hintergrund wie versprochen gelb einfärben:

document.getElementById ("info").style
     .backgroundColor = "#FFFF00";

Interessant ist in diesem Zusammenhang, dass neuere Browser Event-Handler wie onmouseover oder onmouseout für beinahe jedes Element unterstützen. So ist es zum Beispiel inzwischen weit verbreitet, in umfangreichen Tabellen die Zeile oder Zelle, in der sich der Cursor gerade befindet, durch Änderung der Hintergrundfarbe hervorzuheben. Die folgende Funktion kann durch einen solchen Handler aufgerufen werden, um die Farbänderung durchzuführen:

function betonen (id, farbe)
{
   document.getElementById (id).
      style.backgroundColor = farbe;
}

Hier sehen Sie eine Tabellenzeile, die bei Mausberührung mit Hilfe dieser Funktion ihre eigene Hintergrundfarbe ändert:

<tr id="zeile" style="background-color: #FFFF00" 
onmouseover="betonen ('zeile', '#FFFF99');" 
onmouseout="betonen ('zeile', '#FFFF99');">
  <td>DOM</td>
  <td>IE 4.0-Objektmodell</td>
  <td>Netscape-Objektmodell</td>
</tr>

Layers manipulieren

Die Manipulation der Eigenschaften von Layer-Objekten funktioniert im Prinzip genauso. Denken Sie daran, dass ein <div>-Element nur dann zum echten Layer wird, wenn es mit Hilfe des CSS-Attributs position auf eine feste Position gesetzt wird. Da sich HTML-Tag-Knoten am leichtesten über ihre ID ansprechen lassen, liegt es nahe, die CSS-Formatierung für den Layer in einer unabhängigen Stilangabe vorzunehmen, die dem Layer dann gleichzeitig mit seiner ID zugewiesen wird.

Das Beispiel in Listing 19.10 lässt nach einer Wartezeit von drei Sekunden nach dem Laden einen Layer mit einem Bild von links in den sichtbaren Bereich des Fensters fahren; anschließend bleibt er fünf Sekunden stehen und wird schließlich ausgeblendet. Auf immer mehr Sites ist heute Werbung nach diesem Schema zu sehen.

Listing 19.11   Ein aufdringliches Werbe-Popup in einem Layer

<html>
  <head>
    <title>Aufdringliche Werbung</title>
    <style type="text/css">
    <!--
 
       #werbung {
          position: absolute;
          top: 100px;
          left: -200px
       }
 
    -->
    </style>
 
    <script language="JavaScript" 
    type="text/javascript">
    <!--
 
        // Aktuelle Position
        var x = -200;
           function werbungZeigen()
        {
           x += 5;
           document.getElementById ("werbung").style.
                left = x + "px";
           if (x >= 100)
              setTimeout ("werbungSchliessen ();",
                   5000);
           else
              setTimeout ("werbungZeigen ();", 50);
        }
           function werbungSchliessen()
        {
           document.getElementById ("werbung")
                .style.visibility = "hidden";
        }
           setTimeout ("werbungZeigen();", 3000);
 
    //-->
    </script>
  </head>
  <body>
    <div id="werbung"><img src="werbung.gif" 
    width="198" height="198"></div>
    ... beliebiger Inhalt ...
  </body>
</html>

Eine überzeugendere Anwendung als dieses Beispiel, das Anwender verärgern könnte, finden Sie im letzten Unterabschnitt dieses Kapitels, in dem browserübergreifende Lösungen präsentiert werden.

Dokumentinhalte verändern und austauschen

Die Struktur des DOM-Baums, den ein HTML-Dokument bildet, kann beliebig manipuliert werden, um Inhalte vollständig gegen andere auszutauschen. Zu diesem Zweck sind Knoten-Objekte mit einer Reihe von Methoden ausgestattet, die entsprechende Manipulationen ermöglichen. Tabelle 19.3 zeigt hierzu eine Übersicht.


Tabelle 19.3   Die wichtigsten Methoden zur Manipulation von Knoten

Methode Knotentyp(en) Bedeutung
createElement(Tagname) document erzeugt einen neuen HTML-Tag-Knoten vom angegebenen Typ
createTextNode (Text) document erzeugt einen neuen Textknoten mit dem angegebenen Inhalt
hasAttribute (Name) element (HTML-Tag) true, wenn das Tag das genannte Attribut besitzt
getAttribute (Name) element gibt das Attribut mit dem angegebenen Namen zurück
setAttribute
(Name, Wert)
element setzt das mit Name bezeichnete Attribut auf Wert
removeAttribute
(Name)
element entfernt das genannte Attribut
appendChild (Knoten) alle hängt Knoten als letztes neues Kind an
removeChild (Knoten) alle entfernt den angegebenen Kindknoten
replaceChild
(neuKnoten, altKnoten)
alle ersetzt altKnoten durch neuKnoten

Das Beispiel in Listing 19.11 tauscht den Inhalt eines vollständigen Absatzes aus, der aus mehreren Text- und Elementknoten besteht.

Listing 19.12   Austauschen von DOM-Knoten

<html>
  <head>
    <title>Eine Geschichte in zwei Teilen</title>
      <script language="JavaScript" 
      type="text/javascript">
      <!--
 
        function weiter()
        {
           var k1 = document.createTextNode 
                ("Hier folgt der zweite Teil des ");
           var k2 = document.createElement ("b");
           var k2a = document.createTextNode 
                ("kurzen");
           k2.appendChild (k2a);
           var k3 = document.createTextNode 
                (" Textes.");
           document.getElementById ("story")
                .replaceChild (k1, document.
                getElementById ("story").firstChild);
           document.getElementById ("story")
                .appendChild (k2);
           document.getElementById ("story")
                 .appendChild (k3);
        }
       //-->
    </script>
  </head>
  <body>
    <div id="story"><p>Dies ist ein <i>kurzer</i> 
    Text. Er besteht aus zwei Teilen. Den zweiten Teil 
    k&ouml;nnen Sie durch Klick auf den Link 
    &quot;Weiter&quot; lesen.</p></div>
    <p><a href="javascript:weiter();">Weiter</a></p>
  </body>
</html>

Da von Anfang an bekannt ist, dass der komplette Inhalt des <div>-Elements mit der ID story ausgetauscht werden soll, wurde dieser insgesamt zwischen die Tags <p> und </p> gepackt. Eine mögliche Alternative bestünde darin, sämtliche Kindknoten von story mit Hilfe einer Schleife zu entfernen:

while (document.getElementById ("story")
     .hasChildNodes()) {
   document.getElementById ("story").removeChild
       (document.getElementById ("story").firstChild);
}

In der vorliegenden Lösung werden zunächst die Knoten für den Ersatztext von Grund auf neu erzeugt: die beiden Textknoten k1 und k3 sowie der dazwischen liegende Elementknoten k2 vom Typ "b" (das HTML-Tag <b>) und sein Text. Anschließend wird der bisher einzige Kindknoten von story, das <p>-Element, mittels replaceChild() durch k1 ersetzt; die beiden folgenden Knoten k2 und k3 werden durch appendChild() angefügt.

Praktisch gesehen wird in diesem Beispiel der Text »Dies ist ein kurzer Text. Er besteht aus zwei Teilen.« gegen den neuen Inhalt »Hier folgt der zweite Teil des kurzen Textes.« ausgetauscht.


Galileo Computing

19.7.2 Das klassische Internet-Explorer-Modell  downtop

Ähnlich wie beim W3C-DOM können Sie in Microsofts eigenem Objektmodell, das mit dem Internet Explorer 4.0 eingeführt wurde, im Prinzip auf jedes einzelne Element einer Webseite zugreifen. Auch hier bietet sich als einfachste Möglichkeit der Zugriff auf diejenigen HTML-Tags an, denen über ein id-Attribut eine eindeutige ID zugewiesen wurde. Aktuelle Internet Explorer-Versionen seit 5.0 unterstützen gleichzeitig das DOM und auch das Microsoft-Objektmodell.

document.all

Jedes Element, das eine ID besitzt, ist ein Element des großen Objekt-Arrays document.all, in dem die jeweilige ID den Index oder ein entsprechendes benanntes Unterobjekt bildet. Beispielsweise können Sie auf die Tabellenzeile

<td id="wichtig">wichtiger Inhalt</td>

mit Hilfe der folgenden Formulierung zugreifen:

document.all.wichtig

Die Alternative ist:

document.all ["wichtig"]

Auch bei diesem Objektmodell ist die wichtigste Eigenschaft eines solchen Objekts, auf die Sie zugreifen können, die CSS-Formatierung style.

Betrachten Sie etwa den folgenden Absatz:

<p id="demo">Dies ist ein Absatz.</p>

Über die folgende Anweisung können Sie den Text dieses Absatzes nachträglich fett setzen:

document.all.demo.style.fontWeight = "bold";

Auch die Manipulation von Layers funktioniert entsprechend. Sehen Sie sich beispielsweise diese Layer-Definition an:

<div id="ebene" style="position: absolute; left: 100px; 
top: 100px">Test</div>

Unter Verwendung der folgenden Anweisungen können Sie den Layer ebene auf eine neue Position (200 Pixel vom linken Rand und 200 vom oberen entfernt) setzen:

document.all.ebene.style.left = "200px";
document.all.ebene.style.top = "200px";

Selbstverständlich muss die CSS-Formatangabe zur Positionierung des Layers auch hier nicht unbedingt in einem style-Attribut innerhalb des Tags vorgenommen werden, sondern kann auch als unabhängiger Stil für die ID des Layers oder auf andere Art erfolgen.

Inhalte austauschen

Eine weitere interessante Eigenschaft der Objekte in document.all ist innerHTML: Indem Sie ihr einen anderen Wert zuweisen, können Sie beliebige Inhalte des Dokuments ändern.

Zum Beispiel soll der Inhalt des kursiven Textbereichs im folgenden Absatz geändert werden:

<p>Dies ist der <i id="kursiv">alte</i> Text.</p>

Dies gelingt mit Hilfe der Anweisung:

document.all.kursiv.innerHTML = "neue";

Galileo Computing

19.7.3 Das klassische Netscape-Modell  downtop

Netscape hat mit dem Communicator 4.0 ein eigenes DHTML-Objektmodell eingeführt. Gegenüber DOM und dem Microsoft-Modell besitzt es nur sehr beschränkte Möglichkeiten. Genau aus diesem Grund wurde es mit dem Nachfolger der 4.x-Versionen von Netscape, der Version 6.0, vollständig abgeschafft: Neuere Netscape-Versionen und die Open-Source-Variante Mozilla unterstützen nur noch das W3C-DOM.

Grenzen dieses Modells

Über das alte Netscape-Modell können Sie keine beliebigen Inhalte des HTML-Dokuments modifizieren. Geändert werden können lediglich die CSS-Eigenschaften von Layer-Objekten.

Die Layers selbst werden genauso erzeugt wie beim Internet Explorer und wie in Kapitel 16, HTML und XHTML, gezeigt: Es wird ein <div>-Tag mit einer eindeutigen ID und mit festgelegter Formatierung eingerichtet.

In JavaScript wird ein Layer über das Array document.layers angesprochen. Die zugewiesene ID des jeweiligen <div>-Elements wird wiederum als Index beziehungsweise Unterobjekt dieses Objekts verwendet:

Ein Layer, den Sie über

<div id="test" style="position: absolute; left: 10px; 
top: 10px">Textinhalt</div>

erzeugt haben, kann per JavaScript folgendermaßen referenziert werden:

document.layers.test

Die zulässige Alternative ist

document.layers ["test"]

CSS-Manipulation

Die einzelnen CSS-Eigenschaften des Layers sind unmittelbare Eigenschaften des Objekts; ein übergeordnetes style-Objekt gibt es nicht. Die CSS-Attribute selbst sind dieselben wie bei den anderen Objektmodellen, allerdings werden numerische Werte als Integer zugewiesen statt als Strings mit integrierter Maßeinheit. Die Maßeinheit muss demzufolge bei der ursprünglichen Stylesheet-Definition verbindlich festgelegt werden und kann sich im Nachhinein nicht mehr ändern.

Zum Beispiel können Sie den Layer test auf diese Weise weiter nach rechts verschieben:

document.layers.test.left = 50;

Die eigentliche Besonderheit der Netscape-Layer offenbart sich, wenn Sie auf ihre Inhalte zugreifen möchten: Layer-Elemente besitzen in diesem Objektmodell ein eigenes inneres document-Objekt, ihre Inhalte sind nicht unmittelbar Teil des HTML-Dokuments. Dies wird besonders beim Zugriff auf Bilder oder Formulare deutlich.

Angenommen, Sie möchten das folgende in einem Layer befindliche Bild gegen ein anderes austauschen:

<div id="rahmen" style="position: absolute; left: 200px; 
top: 100px"><img src="test.gif" name="bild" width="300" 
height="200" /></div>

Dieses Bild wird nicht etwa – wie möglicherweise erwartet – als document.bild angesprochen, sondern so:

document.rahmen.document.bild

Ärgerlicherweise erfolgt der Zugriff auf das Bild in allen anderen Browsern – etwa im Internet Explorer, aber auch in neuen Netscape-Versionen – über document.bild.

Andererseits bietet das innere document-Objekt eines Layers die Möglichkeit, den kompletten Inhalt des Layers nachträglich auszutauschen. In dem Layer rahmen aus dem obigen Beispiel soll statt des Bildes der Text »Kein Bild mehr« erscheinen. Das gelingt mit Hilfe der Technik, die weiter oben für angepasste Browserfenster vorgestellt wurde:

document.rahmen.document.open();
document.rahmen.document.write ("Kein Bild mehr");
document.rahmen.close();

Die Inhalte, die Sie mittels write() in das document-Objekt des Layers hineinschreiben, können übrigens beliebigen HTML-Code enthalten.


Galileo Computing

19.7.4 Browserübergreifende Lösungen  toptop

Natürlich wäre es ideal, wenn es von heute auf morgen nur noch DOM-fähige Browser gäbe. Leider werden jedoch die verschiedensten Varianten parallel genutzt. Insofern nützt das ganze DHTML eigentlich nur, wenn Sie Skripts schreiben, die automatisch den aktuellen Browser ermitteln und mit allen drei Objektmodellen umgehen können.

An dieser Stelle ist die praktische Anwendung von Browserweichen gefragt, die bereits weiter oben im Abschnitt über die Browser- und Fenstereigenschaften besprochen wurden. Der gute alte Hinweis, dass Seiten nur für bestimmte Browser optimiert seien, wirkt nun einmal eher unprofessionell. Sie sollten zumindest den Internet Explorer und Netscape ab Version 4.0 unterstützen.

Die Auswahl der DHTML-Features, die Sie mit Hilfe browserübergreifender Lösungen anwenden können, ist nicht allzu groß. Besonders das alte Netscape-Modell bietet aufgrund seiner Beschränkung auf die Manipulation von Layers nur relativ wenige Möglichkeiten. In diesem Unterabschnitt werden die beiden wichtigsten Verfahren so vorgestellt, dass sie in allen Versionen der beiden Browser ab den 4er-Versionen laufen: die Layer-Animation sowie der Austausch von Text innerhalb eines Layers.

Verallgemeinerte Layer-Animation

Als praxisnahes Beispiel für die Animation von Layers sehen Sie hier eine funktionierende Analoguhr: Drei farbige, als Zeiger dienende Punkte werden entsprechend der Systemzeit auf kreisförmigen Bahnen um das Zifferblatt herumbewegt (siehe Abbildung 19.4).


Abbildung 19.4   Momentaufnahme der DHTML-Analoguhr um 13:34

Abbildung
Hier klicken, um das Bild zu Vergrößern


In Listing 19.12 sehen Sie zunächst den vollständigen Code.

Listing 19.13   Eine browserunabhängige DHTML-Analoguhr

<html>
<head>
<title>DHTML-Analoguhr</title>
<script language="JavaScript" type="text/javascript">
<!--
 
   // DHTML-Version ermitteln
   var dom = document.getElementById ? true : false;
   var ie = document.all ? true : false;
   var n4 = document.layers ? true : false;
 
   // Globale Variablen
   var std_radius = 80;
   var min_radius = 100;
   var sek_radius = 90;
   var x = 110;
   var y = 110;
      function zeit ()
   {
      var jetzt = new Date();
      var std = jetzt.getHours();
      var min = jetzt.getMinutes();
      var sek = jetzt.getSeconds();
      if (std > 11)
         std -= 12;  // 12-Stunden-Anzeige!
            // Winkel ermitteln
      var std_winkel = std * 30 - 90 + min * 0.1 - 90;
      var min_winkel = min * 6 - 90 + sek * 0.1 - 90;
      var sek_winkel = sek * 6 - 90;
            // Zeigerpositionen berechnen
      var std_y = Math.round (y + std_radius * 
         Math.sin (std_winkel * Math.PI / 180)) - 10;
      var std_x = Math.round (x + std_radius * 
         Math.cos (std_winkel * Math.PI / 180)) - 10;
      var min_y = Math.round (y + min_radius * 
         Math.sin (min_winkel * Math.PI / 180)) - 8;
      var min_x = Math.round (x + min_radius * 
         Math.cos (min_winkel * Math.PI / 180)) - 8;
      var sek_y = Math.round (y + sek_radius * 
         Math.sin (sek_winkel * Math.PI / 180)) - 5;
      var sek_x = Math.round (x + sek_radius * 
         Math.cos (sek_winkel * Math.PI / 180)) - 5;
            // Zeiger setzen
      if (dom) {
         document.getElementById ("std").style.top 
              = std_y + "px";
         document.getElementById ("std").style.left 
             = std_x + "px";
         document.getElementById ("min").style.top 
              = min_y + "px";
         document.getElementById ("min").style.left 
             = min_x + "px";
         document.getElementById ("sek").style.top 
              = sek_y + "px";
         document.getElementById ("sek").style.left 
             = sek_x + "px";
      } else if (ie) {
         document.all.std.style.top  = std_y + "px";
         document.all.std.style.left = std_x + "px";
         document.all.min.style.top  = min_y + "px";
         document.all.min.style.left = min_x + "px";
         document.all.sek.style.top  = sek_y + "px";
         document.all.sek.style.left = sek_x + "px";
      } else if (n4) {
         document.layers.std.top  = std_y;
         document.layers.std.left = std_x;
         document.layers.min.top  = min_y;
         document.layers.min.left = min_x;
         document.layers.sek.top  = sek_y;
         document.layers.sek.left = sek_x;
      }
      setTimeout ("zeit();", 1000);
   }
 
//-->
</script>   </head>
<body onload="zeit();">
<div id="zifferblatt" style="position: absolute; top: 0px; left: 0px">
<img src="zifferblatt.gif" width="220" height="220" /></div>
<div id="std" style="position: absolute; top: 90px; left: 10px">
<img src="std_zeiger.gif" width="20" height="20" /></div>
<div id="min" style="position: absolute; top: 92px; left: 20px">
<img src="min_zeiger.gif" width="15" height="15" /></div>
<div id="sek" style="position: absolute; top: 95px; left: 30px">
<img src="sek_zeiger.gif" width="10" height="10" /></div>
</body>
</html>

DHTML-Browserweiche

Zunächst fällt auf, dass hier eine völlig andere Art der Browserweiche zum Einsatz kommt als die weiter oben besprochenen: Den Variablen dom, ie und n4 werden versuchsweise die DHTML-Objekte von DOM, dem klassischen Internet Explorer-Modell beziehungsweise dem alten Netscape-Modell als Werte zugewiesen. Das Ergebnis dieser Wertzuweisung ist jeweils eine Objektreferenz, wenn die Zugriffsart funktioniert, oder null, wenn sie fehlschlägt. Auf diese Weise können die DHTML-Modelle weiter unten einfach über Formulierungen wie if (dom) oder if (ie) abgefragt werden.

Die herkömmliche Browserweiche hat für DHTML-Zwecke einen großen Nachteil: Da auch neuere Internet Explorer-Versionen als Hauptversionsnummer 4.0 melden, würden alle Varianten dieses Browsers eben als Internet Explorer 4.0 behandelt. Neuere Versionen könnten dann nicht von den DOM-Vorteilen profitieren.

Berechnung
der Zeigerpositionen

Das Interessanteste an dem vorliegenden Skript ist wahrscheinlich das mathematische Verfahren, nach dem die Positionen der Zeiger auf dem Zifferblatt berechnet werden.

Der erste Schritt besteht darin, aus der jeweiligen Stunden-, Minuten- oder Sekundenangabe den korrekten Winkel zu berechnen. Dazu werden einfach die 12 möglichen Stunden- beziehungsweise 60 möglichen Minuten- und Sekundenangaben durch Multiplikation auf 360° verteilt: Zum Beispiel können Sie aus Gründen der Klarheit statt der bereits vereinfachten Angabe sek * 6 auch sek / 60 * 360 schreiben.

Für den Stundenzeiger wird noch der anteilige Minutenwert und für den Minutenzeiger der entsprechende Sekundenwert hinzuaddiert, damit diese beiden Zeiger kontinuierlich mitlaufen. Zu guter Letzt müssen noch 90° abgezogen werden, da der Startpunkt 12 Uhr nicht links liegt, sondern oben.

Im zweiten Schritt muss nun der Winkel in x- und y-Werte auf einem Kreis mit einem bestimmten Radius umgerechnet werden. Wenn die Sinus-Werte der Winkel als x–Koordinaten und die Cosinus-Werte als y-Koordinaten betrachtet werden, lassen sich daraus die korrekten auf 1 bezogenen Grundwerte ermittelt, die nur noch mit dem Radius multipliziert und zum jeweiligen Achsenwert des Mittelpunkts addiert werden müssen. Dies ergibt etwa für den Stundenzeiger (Radius 80 Pixel) die Werte sin(x) * 80 + 110 und cos(y) * 80+110.

Das einzige kleine Problem besteht darin, dass die trigonometrischen Funktionen in JavaScript das Bogenmaß verwenden; für die Umrechnung aus dem Winkelmaß gilt 360° = 2Pi.

Als Letztes wird noch der Radius des jeweiligen Zeigerbildes abgezogen, um die Zeiger wirklich korrekt zu positionieren.

Nach abgeschlossener Berechnung können die drei Zeiger-Layers auf die berechneten x- und y-Werte gesetzt werden. Zu diesem Zweck wird abgefragt, welches zu Beginn der Funktion ermittelte Objektmodell unterstützt wird, damit jeder Browser mit der für ihn passenden Syntax angesprochen wird.

Austausch von Layer-Inhalten

Als Beispiel für den Austausch von Textinhalten wird im folgenden Listing im Layer dauer angezeigt, wie lange der Besucher bereits die Seite betrachtet.

Den Code sehen Sie in Listing 19.13.

Listing 19.14   Browserübergreifender Austausch von Layer-Texten

<html>
<head>
<title>Ihre Verweildauer</title>
<script language="JavaScript" type="text/javascript">
<!--
 
   // DHTML-Version ermitteln
   var dom = document.getElementById ? true : false;
   var ie = document.all ? true : false;
   var n4 = document.layers ? true : false;
 
   // Bisherige Verweildauer
   var zeit = 0;
      function zeigeDauer()
   {
      var infostr = "Sie sind bereits " + zeit 
          + " Sekunden hier.";
      if (dom)
         document.getElementById ("dauer").
             firstChild.nodeValue = infostr;
      else if (ie)
         document.all.dauer.innerHTML = infostr;
      else if (n4) {
         with (document.layers.dauer.document) {
            open();
            write (infostr);
            close();
         }
      }
      zeit++;
      setTimeout ("zeigeDauer();", 1000);
   }
   //-->
</script>   </head>
<body onload="zeigeDauer();">
<div id="dauer" style="position: absolute; top: 10px; left: 
10px">So lange sind Sie schon hier!</div>
</body>
</html>

Als Erstes wird wieder ermittelt, welche DHTML-Version unterstützt wird. Anschließend wird der anzuzeigende String gebastelt, der dann je nach Browser auf die passende Art und Weise dargestellt wird.

Beachten Sie bitte, dass Sie in einen solchen Ausgabestring kein HTML hineinschreiben dürfen, wenn das Skript auch in DOM-Browsern funktionieren soll: Während die traditionelle Netscape-Methode sowie die alte Internet Explorer-Eigenschaft innerHTML damit kein Problem haben, stellen HTML-Tags unter DOM separate Knoten dar, die nicht einfach als String in die nodeValue eines Textknotens eingetragen werden dürfen.

  

Einstieg in PHP 5

Einstieg in Java

C von A bis Z

Einstieg in C++

Einstieg in Linux

Einstieg in XML

Apache 2




Copyright © Galileo Press GmbH 2004
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. 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.


[Galileo Computing]

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