Erhältlich u.a. bei Amazon.de
9
Von Wolfgang Schwarz
Lange Zeit waren Webseiten eher starre Gebilde. Ein Dokument konnte, nachdem es einmal fertig geladen war, praktisch nicht mehr verändert werden. Das höchste der Gefühle waren Image-Rollover und Scrolltexte (wahlweise in Formularfeldern oder der Statuszeile), die deshalb geradezu epidemische Verbreitung fanden. Als im Sommer 1997 der Netscape Navigator 4 und etwas später Internet Explorer 4 erschienen, wurde alles anders.
Seither kann man Seitenelemente auch nach dem Laden noch herumschieben, sie verstecken und verändern, Animationen erzeugen, Menüpunkte ein- und ausfahren, Texte überschreiben, usw. - und das ganz ohne Plugins, nur mit Hilfe von JavaScript. Die neuen Möglichkeiten gehen so weit über alles Bisherige hinaus, dass man ihnen, mehr oder weniger inoffiziell, einen eigenen Namen gab: "Dynamic HTML", oder kurz: DHTML.
Bevor Sie jetzt in Euphorie verfallen: Die Geschichte hat eine Kehrseite. Das Objektmodell, über das uns HTML-Elemente als JavaScript-Objekte zugänglich sind, ist in Sachen DHTML bei Netscape und Internet Explorer leider nicht identisch - nicht einmal ähnlich. Es ist deshalb im Allgemeinen nicht möglich, denselben Effekt auf beiden Browsern mit denselben Anweisungen zu erreichen. Diese Tatsache legt schwere Steine auf den Weg des DHTML-Programmierers: Nicht nur muss man beide Objektmodelle im Kopf haben, auch werden die Skripte durch Browserabfragen und Verzweigungen oft überdimensional aufgebläht.
Um diese viel beklagte Situation zu verbessern, hat das World Wide Web Consortium (W3C), Wächter über einheitliche Standards im Internet, mit seiner DOM-Spezifikation das einheitliche Objektmodell zukünftiger Browser vorgestellt. Da man aber weder das Modell von Netscape noch das von Microsoft einfach übernehmen wollte, gibt es nun drei Modelle, die beachtet werden müssen: Das von Netscape 4, das von Internet Explorer und das des W3C, welches zum Beispiel im neuen Netscape 6 (und teilweise auch im Internet Explorer 5) umgesetzt wurde.
In diesem Kapitel werden wir die drei Objektmodelle der Reihe nach durchgehen. Spätestens jetzt sollten Sie sich eine kleine Testumgebung einrichten. Sie brauchen für die Übungen auf jeden Fall eine Version von Netscape 4, einen Internet Explorer ab 4 und einen Browser, der das W3C-DOM unterstützt. Am besten nehmen Sie dazu Netscape 6, es reicht aber auch Internet Explorer 5.
Bevor wir mit den einzelnen Objektmodellen anfangen, machen wir einen kurzen Abstecher, um uns eine HTML-Erweiterung anzusehen, ohne die DHTML nicht möglich wäre: Cascading Style Sheets.
Cascading Style Sheets (CSS) sind eine Technik, mit sich genau festlegen lässt, wie die Elemente einer HTML- oder XML-Seite im Browser dargestellt werden sollen. HTML allein bietet darauf nur wenig Einflussmöglichkeit, etwa über den so allgegenwärtigen wie veralteten <font>-Tag.
Mit Style Sheets sind sehr detaillierte Angaben möglich, zum Beispiel können Sie bestimmen, dass alle Links auf Ihrer Seite in 15 Pixel hoher, grüner Arial-Schrift auf gelbem Hintergrund mit rotem Rahmen und 2 Pixel Innenabstand zwischen Schrift und Rahmen dargestellt werden sollen. In HTML müssten Sie dafür ein barockes Konstrukt aus Hilfstabellen und Grafiken um jeden Link platzieren, in CSS dagegen benötigen Sie nur eine Zeile, die im head stehen kann und damit sauber vom Seiteninhalt getrennt bleibt.
Style Sheets wurden von Internet Explorer ziemlich bruchstückhaft bereits in Version 3 unterstützt, seither ist die Umsetzung immer weiter verbessert worden. Der Netscape Navigator 4 versteht ebenfalls die wichtigsten CSS-Angaben, erst mit Version 6 hat Netscape aber in dieser Beziehung den Microsoft-Konkurrenten eingeholt.
CSS-Syntax
Die Syntax von CSS ist sehr einfach. Um alle Überschriften erster Ordnung auf einer Seite in blauer Schrift erscheinen zu lassen, brauchen Sie lediglich folgende Zeilen ins head-Element einzufügen:
<style type="text/css"> <!-- h1 { color:blue } --> </style>
Die Kommentare dienen wie bei script-Elementen dazu, den Inhalt vor alten Browsern zu verstecken. Ich werde sie, um nicht unnötig Bäume zu verschwenden, in den hier abgedruckten Beispielen jedoch weglassen.
Schauen Sie sich jetzt die CSS-Angabe an: Sie beginnt mit dem Tag-Namen des Ziel-Elements (h1), dann folgt in geschweiften Klammern die Eigenschaft, die wir für das Element festlegen wollen. Mehrere Angaben werden einfach durch Semikolons getrennt:
h1 { color:blue; font-size:16pt; background-color:#ffff33 }
Diese Definition wirkt sich auf alle h1-Elemente des Dokuments aus. Für den Einsatz in DHTML werden wir aber häufig ein HTML-Element einzeln mit CSS formatieren wollen. Auch das ist möglich. Dazu geben wir dem Element im Start-Tag eine ID:
<div id="irgendEinName">irgend ein Inhalt</div>
Über diese ID können wir uns dann im style-Bereich auf das Element beziehen:
#irgendEinName { font-weight:bold }
Der ID wird also ein # vorangestellt. IDs dürfen bekanntlich nicht mehrfach vergeben werden. Soll eine Angabe für zwei oder mehr Elemente gelten, verwenden Sie stattdessen den class-Selektor. Dieser beginnt mit einem Punkt:
.sehrSchoen { color:green; background-color:red }
Zwei Elemente dieser Klasse könnten etwa so aussehen:
<h3 class="sehrSchoen">sehr schöne Überschrift</h3> <p class="sehrSchoen">sehr schöner Absatz</p>
externe und interne Styles
Es gibt verschiedene Möglichkeiten, Style Sheets in eine HTML-Seite einzubinden. Eine davon haben Sie schon kennen gelernt: das Element style im Kopf der Seite. Diese Technik ist besonders geeignet für Angaben, die sich lediglich auf ein einzelnes Dokument beziehen.
Soll eine CSS-Definition dagegen nicht nur für eine Seite, sondern vielleicht für einen ganzen Webauftritt gelten, dann können Sie sie in einer externen Datei ablegen. Speichern Sie dazu die CSS-Angaben als Text-Datei mit der Endung css. Auf Ihren Seiten binden Sie diese dann mit dem link-Tag ein:
<link rel="stylesheet" type="text/css" href="meinStil.css">
Style Sheets, die sich nur auf ein einziges Element beziehen, können noch auf eine andere Weise definiert werden, indem man nämlich direkt in den Start-Tag des Elements ein style-Attribut einfügt:
<p style="color:green; background-color:red">sehr schön</p>
CSS-Eigenschaften
Die aktuelle CSS-Spezifikation des W3C, im Internet unter http://www.w3.org/TR/REC-CSS2/ zu finden, enthält 122 CSS-Eigenschaften. Tabelle 9.1 fasst diejenigen zusammen, die es sich lohnt auswendig zu lernen.
CSS-Eigenschaft | Beispiel | Erklärung |
---|---|---|
color | color: #990000 | die Schriftfarbe des Elements |
background-color | background-color: red | die Hintergrundfarbe des Elements |
font-family | font-family: Arial | die zu verwendende Schriftart |
font-size | font-size: 12pt | die Schriftgröße |
text-align | text-align: center | die horizontale Ausrichtung des Element-Inhalts |
width | width: 10cm | die Breite des Elements |
height | height: 200px | die Höhe des Elements |
margin | margin: 2mm | der Abstand des Elements zu seinen Nachbar-Elementen |
padding | padding: 10px | der Innenabstand zwischen Element-Grenzen und -Inhalt |
Tabelle 9.1: ein paar mit Style Sheets definierbare Eigenschaften
Bei vielen CSS-Attributen muss eine Maßeinheit gewählt werden. Größenangaben z.B. für Abstände oder Schriften können in den Einheiten pt, pc, in, cm, mm, em, ex, px und % festgelegt werden.
Nicht ganz so groß ist die Format-Auswahl bei Farbangaben: Hier steht Ihnen wie in HTML neben einer langen Liste vordefinierter Farbnamen wie blue, silver oder tomato die RGB-Schreibweise zur Verfügung. Diese kann nicht nur hexadezimal erfolgen - wo Rot zum Beispiel #ff0000 ist -, sondern auch dezimal und in Prozentwerten. Rot wäre also auch rgb(255, 0, 0) und rgb(100%, 0%, 0%).
Das folgende Beispiel definiert einen 300 Pixel breiten Absatz mit dunkelroter Schrift auf beigefarbenem Hintergrund und 5 Millimeter Abstand zwischen Schrift und Element-Aussenkante. Die Schriftart ist Verdana. Wenn Verdana nicht verfügbar ist, soll Helvetica gesucht werden; gibt es auch diese nicht, wird eine Standard-Schrift ohne Serifen gewählt.
<p style="background-color:beige; color:#660000; font-family: Verdana, Helvetica, sans-serif; padding:5mm; width:300px"> Den Stil verbessern, das heisst den Gedanken verbessern. </p>
(Netscape 4 zeigt den Hintergrund nicht korrekt an. Wie man diesen Fehler umgeht, erfahren Sie in Übung 12.)
Die für DHTML wichtigsten CSS-Eigenschaften habe ich bislang verschwiegen: Mit Style Sheets können Sie nämlich nicht nur bestimmen, wie ein Element aussehen (und klingen) soll, sondern auch, wo es im Browserfenster steht, wie viel von ihm zu sehen ist, und welche andern Elemente es verdecken darf.
Um ein Element pixelgenau im Browserfenster zu positionieren, sind drei Angaben nötig. Zuerst muss mit position festgelegt werden, relativ zu welchem Punkt positioniert werden soll: entweder relativ zur normalen Position des Elements im Dokumentfluss oder relativ zur linken oberen Dokumentecke. Die entsprechenden Werte sind relative und absolute. (Steht das Element in einem anderen positionierten Element, dann ist eine "absolute" Angabe immer relativ zur Position des umgebenden Elements.) Mit Hilfe der Eigenschaften left und top wird dann der Abstand von diesem Punkt festgelegt. Diese Werte können auch negativ sein.
Ein Beispiel:
<body> Das ist<br> nicht besonders <div style="position:absolute; left:20px; top:10px;"> gut zu lesen. </div> </body>
Durch die Angabe von position:absolute wird der div-Bereich aus dem normalen Dokumentfluss herausgenommen und mit einem Abstand von 10 Pixeln zur oberen und 20 Pixeln zur linken Seitenkante positioniert. Dadurch überlappt er den im Quelltext zuvor angegebenen Text und ist deshalb nicht besonders gut zu lesen.
Es gibt Elemente, bei denen macht eine Positionierung nur wenig Sinn, <td> zum Beispiel. Sie können unangenehme Überraschungen vermeiden, wenn Sie sich vor allem auf div- und span-Elemente beschränken, da diese von sich aus keine besonderen Formateigenschaften mit sich bringen.
Standardmäßig sind alle auf einer Seite definierten Elemente sichtbar. Mit der CSS-Eigenschaft visibility können aber auch unsichtbare Elemente erzeugt werden:
<div style="visibility:hidden"> Das ist überhaupt nicht gut zu lesen. </div>
Wozu das gut sein soll, werden Sie demnächst erfahren.
Es ist sogar möglich festzulegen, dass nur ein Stück eines Elements zu sehen ist. Dazu dient die Eigenschaft clip, der ein Rechteck mit vier Kanten-Werten zugewiesen wird:
" Das ist nur teilweilse gut zu lesen. </div>
Der erste Wert bestimmt den Abstand der Oberkante des sichtbaren Bereichs zur oberen Elementgrenze, der zweite die Entfernung zwischen der rechten Kante des sichtbaren Ausschnitts und der linken Elementgrenze, der dritte die zwischen der Unterkante des Ausschnitts und der oberen Elementgrenze, der vierte die zwischen linker Elementgrenze und linkem Rand des angezeigten Ausschnitts. Alle Angaben sind also relativ zur linken oberen Element-Ecke.
Schließlich können Sie mit der Eigenschaft z-index noch die Reihenfolge festlegen, in der sich positionierte Elemente überlappen, das heißt: welches Element über welchem liegt. Der Wert von z-index ist einfach eine Zahl: Je höher die Zahl, desto höher liegt das Element über den anderen Elementen im Dokument.
Tabelle 9.2 fasst die in diesem Abschnitt vorgestellten CSS-Eigenschaften zusammen und beendet damit unseren kleinen Ausflug in die Welt der Style Sheets.
CSS- Eigenschaft | Beispiel | Erklärung |
---|---|---|
position | position: absolute | die Art der Positionierung (relativ oder absolut) |
left | left: 100px | der horizontale Abstand zum normalen Ort des Elements bei relativer Positionierung, sonst der Abstand zum übergeordneten Element |
top | top: -50px | der entsprechende vertikale Abstand |
visibility | visibility: hidden | die Sichtbarkeit des Elements |
clip | clip: rect(20px 50px 30px 0px) | der sichtbare Ausschnitt des Elements |
z-index | z-index: 60 | die "Höhe" des Elements in der Stapelreihenfolge |
Tabelle 9.2: noch ein paar CSS-Eigenschaften
Anders als die neueren Objektmodelle von Microsoft und W3C bietet Netscape 4 nur sehr eingeschränkten Zugriff auf die Elemente einer Webseite. Es gibt lediglich einen einzigen wirklich flexiblen Element-Typ: Layer. "Layer" bedeutet "Ebene", und genau so sollten Sie sich Layer auch vorstellen:
Eine Webseite kann aus verschiedenen Ebenen bestehen, von denen jede ein eigenes kleines Dokument enthält. Diese Dokument-Ebenen können nicht nur wie in Framesets nebeneinander, sondern nach Herzenslust übereinander und ineinander liegen und noch dazu jederzeit verschoben, versteckt, verdeckt und neu beschrieben werden.
<layer>
Um eine Seite bequem in mehrere Dokument-Ebenen einzuteilen, gibt es bei Netscape 4 den neuen HTML-Tag <layer>. Sehen wir uns ein Beispiel an:
<body> Die Sprengung erfolgt mit <layer id="dynamitLayer" left="20" top="100"> <b>Dynamit</b> </layer> </body>
Was zwischen <layer> und </layer> steht, also der Inhalt des Layer-Elements, bildet ein eigenständiges Dokument, welches an der im Start-Tag angegebenen Stelle pixelgenau positioniert wird. In unserem Fall besteht es nur aus dem einen, fett formatierten Wort "Dynamit". Im Prinzip können Sie aber ein vollständiges Dokument von <html> bis </html> in den Layer schreiben. Es ist sogar möglich, externe Seiten einzubinden:
Sie sehen, Layer sind anders als gewöhnliche HTML-Elemente. So anders, dass kein Browser außer Netscape 4 sie versteht - nicht einmal die Nachfolgeversion Netscape 6. Deshalb sollten Sie in der Praxis besser auf <layer> verzichten.
<layer>-Ersatz
Das geht, weil Netscape einen Ersatz zur Verfügung stellt. Gewöhnliche HTML-Elemente werden nämlich intern in Layer verwandelt, wenn man ihnen mit CSS-Angaben eine absolute oder relative Positionierung verleiht. Das folgende Dokument entspricht deshalb intern genau dem Beispiel vom Anfang dieses Abschnitts:
<body> Die Sprengung erfolgt mit "</body>
Diese Schreibweise wird im Gegensatz zu <layer> auch von Internet Explorer und Netscape 6 verstanden. Wenn ich im Weiteren von Layern spreche, dann meine ich Objekte vom Typ Layer, egal ob sie mit dem <layer>-Tag oder mit <div>, <span> oder <p> erzeugt wurden.
Das Objekt Layer
In JavaScript gibt es bei Netscape 4 den speziellen Objekt-Typ Layer, durch den Layer-Elemente repräsentiert werden. Layer-Objekte ähneln window-Objekten (vgl. Kapitel 7), insofern jeder Layer eine eigene document-Eigenschaft besitzt. Andererseits sind Layer selbst wiederum Eigenschaften eines document-Objekts, nämlich der Repräsentation des Dokuments, in dem sie definiert wurden. Schauen wir uns noch einmal ein Beispiel an:
<html> <head> <title>zwei Dokumente</title> <style> #dynamo { position:absolute; left:20px; top:100px } </style> </head> <body> mein Fahrrad: <img src="fahrrad.jpg" name="fahrradBild"> <div id="dynamo"> mein Dynamo: <img src="dynamo.jpg" name="dynamoBild"> </div> </body> </html>
In der Objekt-Hierarchie ist das gesamte Dokument als window.document vertreten. Es enthält einen Layer, in Form eines absolut positionierten div-Elements. Genau wie Bilder und Formulare werden die zu einem Dokument gehörenden Layer in einem Array (genauer: einer Collection) aufgelistet. Wie Sie in Kapitel 3 gelernt haben, erhalten Sie mit document.images[0]eine Referenz auf das erste Bild einer Seite. Entsprechend verweist
document.layers[0]
auf den ersten Layer. Und weil Collection-Elemente im Gegensatz zu den Elementen eines gewöhnlichen Arrays auch über ihren Namen (bzw. ihre ID) herausgegriffen werden können, erreichen Sie den Layer mit der ID dynamo auch über diese Ausdrücke:
document.layers["dynamo"]
document.dynamo
Layer sind also, genau wie Image- oder Formular-Objekte, Eigenschaften von document.
Die document-Hierarchie
Nun besitzt aber wie gesagt jeder Layer sein eigenes document-Objekt. Unsere Beispielseite besteht deshalb aus zwei, ineinander verschachtelten Dokumenten:
window.document
und
window.document.dynamo.document
Das im Layer liegende Image-Objekt "dynamoBild" finden wir folglich unter
window.document.dynamo.document.dynamoBild
Elemente, die in einem Layer stehen, gehören zum document-Objekt des Layers, nicht zum übergeordneten Gesamtdokument window.document.
Sollten Sie versuchen, in unserem Beispiel mit document.images[1] oder document.dynamoBild auf das Dynamo-Bild zuzugreifen, erhalten Sie deshalb von Netscape 4 nur den Wert undefined.
Layer-Objekte besitzen eine Reihe von Eigenschaften, die Sie jederzeit lesen und ändern können. In Tabelle 9.3 sind die wichtigsten aufgelistet.
Layer-Eigenschaften
Eigenschaft | Typ | Beschreibung |
---|---|---|
left | Number | die horizontale Position (in Pixeln) des Layers |
top | Number | die vertikale Position des Layers |
clip.top | Number | die Oberkante des sichtbaren Layer-Bereichs relativ zur Layer-Oberkante (in Pixeln). Ein Wert größer 0 schneidet also den Layer-Inhalt von oben ab. |
clip.bottom | Number | die Unterkante des sichtbaren Layer-Bereichs relativ zur Layer-Oberkante |
clip.left | Number | die linke Kante des sichtbaren Layer-Bereichs relativ zur linken Layer-Kante (in Pixeln). Ein Wert größer 0 schneidet also den Layer-Inhalt von links ab. |
clip.right | Number | die rechte Kante des sichtbaren Layer-Bereichs relativ zur linken Layer-Kante. |
zIndex | Number | die "Höhe" der Layer-Ebene in der Stapelreihenfolge. Layer mit hohem zIndex-Wert verdecken Layer mit niedrigerem Wert. |
visibility | String | die Sichtbarkeit des Layers. show steht für sichtbar, hide für unsichtbar, bei inherit erbt der Layer seine Sichtbarkeit vom übergeordneten Layer. Anstatt show und hide können Sie auch visible und hidden verwenden. |
src | String | URL-Angabe für externe Layer-Inhalte |
Tabelle 9.3: einige Eigenschaften des Layer-Objekts
DHTML besteht beim Netscape Navigator im Wesentlichen darin, diese Werte so zu ändern, dass dadurch interessante Effekte entstehen. Zum Beispiel können wir eine Animation erzeugen, indem wir regelmäßig die left- und top-Koordinaten eines Layers ändern:
<html> <head> <title>eine einfache Animation</title> <style> #fahrrad { position:absolute; left:-100px; top:100px } </style> <script> function bewegung(){ document.fahrrad.left+=5; setTimeout("bewegung()",50); } </script> </head> <body onload="bewegung()"> mein Fahrrad: <div id="fahrrad"> <img src="fahrrad.jpg" name="fahrradBild"> </div> </body> </html>
CSS-Attribute entsprechen Layer-Eigenschaften
Wie Sie vermutlich bemerkt haben, entsprechen viele der Layer-Eigenschaften bestimmten CSS-Attributen. Tatsächlich werden diese Attribute von Netscape 4 nur in Verbindung mit Layern unterstützt. Das heißt, wenn Sie einen Bereich Ihrer Seite unsichtbar machen wollen, müssen Sie ihn in einen Layer stecken, zum Beispiel in ein positioniertes div-Element. Diesem Element verpassen Sie dann die Style-Angabe "visibility:hide" (oder "visibility:hidden"). Mit
document.layerID.visibility = "show"
können Sie den Bereich später auf sichtbar schalten.
Noch mehr dynamische Möglichkeiten ergeben sich aus der Tatsache, dass die document-Objekte von Layern alle Eigenschaften und Methoden von window.document besitzen. Sie können deshalb einen Layer mit
document.layerID.document.write("einString"); document.layerID.document.close();
neu beschreiben. Damit können Sie den Inhalt eines Seitenbereichs nach dem Laden noch verändern, etwa in Reaktion auf eine Benutzer-Eingabe.
CSS-Eigenschaften aller HTML-Elemente sind über JavaScript zugänglich
Bei Microsoft entschloss man sich, dem DHTML-Modell von Netscape nicht zu folgen. Der Internet Explorer kennt weder den <layer>-Tag noch das Layer-Objekt und bietet auch keinen vergleichbaren Ersatz. Stattdessen sind die CSS-Eigenschaften aller HTML-Elemente über JavaScript zugänglich und veränderbar. Das verschafft dem Internet Explorer Fähigkeiten, die weit über die von Netscape 4 hinaus gehen.
Ein Beispiel:
<body> "</body>
Dieser Absatz wechselt beim Überfahren mit der Maus Farbe und Schriftart. (Und dabei ist kein Link im Spiel!) Die Anweisung zur Änderung der Farbe ist:
this.style.color = 'red';
Der Ausdruck this bezieht sich, wenn er in einem Event-Handler steht, auf das Element, für das der Handler definiert ist, also hier das p-Element. Wie Sie sehen, erreicht man die CSS-Eigenschaften eines Elements in JavaScript als Eigenschaften des jedem Element zugeordneten Objekts style.
Wenn Sie genau hinsehen, wird Ihnen auffallen, dass die Style-Eigenschaften in JavaScript manchmal etwas anders geschrieben werden als in CSS. So wird aus font-family fontFamily. Ebenso fanden wir bei Netscape die Eigenschaft zIndex, die dem CSS-Attribut z-index entspricht. Die Regel ist einfach: Überall, wo ein Minus-Zeichen ist, wird dieses weggelassen und der nachfolgende Buchstabe groß geschrieben. Der Grund dafür ist, dass das Minus-Zeichen in JavaScript eben für Minus steht. Würden Sie also einElement.style.font-family schreiben, dann würde der JavaScript-Interpreter versuchen, den Wert des Ausdrucks family von dem des Ausdrucks einElement.style.font zu subtrahieren, wobei vermutlich nichts Sinnvolles herauskäme.
document.all
In der Praxis wollen wir oft die CSS-Eigenschaften eines Elements von außerhalb des Elements verändern, so dass wir nicht mit this darauf verweisen können. Wie dann? Die document.layers-Collection, in der bei Netscape 4 Layer-Elemente aufgelistet sind, existiert natürlich beim Internet Explorer nicht. Aber es gibt eine andere Collection, die uns weiterhilft. Erinnern Sie sich: Im IE sind nicht nur einige besondere HTML-Elemente dynamisch veränderbar, sondern wirklich alle. Die entsprechende Collection heißt folgerichtig document.all. Über
document.all[27]
erhalten Sie zum Beispiel das 28. HTML-Element auf der Seite (das erste, mit dem Index 0, ist das html-Element, das zweite in der Regel das head-Element, und so weiter). Die Referenzierung über Index-Nummern ist allerdings eher unhandlich: Immer wenn Sie ein neues Element in Ihre Seite einfügen, müssen alle Nummern angepasst werden. Geben Sie deshalb besser den Elementen, die Sie ansprechen wollen, ein ID-Attribut, dann können Sie mit
document.all["elementID"]
darauf zugreifen.
Wenn Sie vermuten, dass das wie bei Image- und (bei Netscape) Layer-Objekten auch mit document.elementID geht, dann haben Sie sich getäuscht. Die HTML-Elemente sind nicht als direkte Eigenschaften von document verfügbar. Es geht aber trotzdem kürzer, nämlich über
window.elementID
oder einfach elementID.
Hier noch einmal ein Rollover-Effekt, diesmal ohne "this":
<p id="par" onmouseover="par.style.fontSize='50pt'" onmouseout="document.all['par'].style.fontSize='3pt'"> ich bin sehr dynamisch</p>
Man kann, wie dieses Beispiel zeigt, auch Style-Eigenschaften ändern, die zuvor gar nicht explizit definiert wurden. Beim Lesen ist das allerdings anders:
Nur diejenigen style-Eigenschaften lassen sich auslesen, die inline im HTML-Tag angegeben oder dem Element nachträglich mit JavaScript zugewiesen wurden.
Das sollten Sie vor allem beachten, wenn Sie Style Sheets in eigenen <style>-Abschnitten definieren. Netscape 4 reflektiert die dort definierten Werte in den Layer-Eigenschaften, beim Internet Explorer aber werden Sie sie in den style-Eigenschaften der betroffenen Elemente nicht finden. (Seit Version 5 des Explorers gibt es als Ersatz die Eigenschaft currentStyle, die stets den aktuellen Wert enthält. Das funktioniert allerdings nur in der Windows-Version.)
Es gibt noch andere Wege, Teile einer Seite mit Internet Explorer dynamisch zu verändern. Wenn Sie zum Beispiel eine Überschrift definiert haben:
<h1 id="wau">Wau</h1>
dann können Sie diese nicht nur wann immer Sie wollen verstecken, vergrößern, verkleinern und verfärben, Sie können sogar ihren Inhalt austauschen. Dazu gibt es die Eigenschaften innerText und innerHTML, die sowohl gelesen als auch geschrieben werden dürfen:
document.all["wau"].innerText = "Miau"
verwandelt die Überschrift "Wau" in "Miau". Die Änderung ist sofort im Dokument sichtbar.
Der Unterschied zwischen innerText und innerHTML kommt zum Tragen, wenn sich innerhalb eines Elements HTML-Tags befinden. Beim body-Element ist das zum Beispiel meistens so. Wenn Sie document.body.innerText auslesen, erhalten Sie den gesamten Inhalt des body, aber nicht die darin vorkommenden HTML-Tags. document.body.innerHTML dagegen liefert Ihnen den Inhalt mitsamt den Tags.
Das folgende Beispiel erzeugt ein Dokument, dessen Inhalt Buchstabe für Buchstabe aufgebaut wird, ein bisschen so als würde man es gerade mit der Schreibmaschine schreiben.
<html> <head> <title></title> <script> var text = "Immerhin besitzt doch ein Mensch die Freiheit, " + "seine Hand auf den Kopf zu legen. (G.W. Leibniz, " + "Neue Abhandlung über den menschlichen Verstand, " + "Leipzig: Meiner 1915, S. 108)"; var zaehler = 0; function schreib(){ document.body.innerHTML+= text.charAt(zaehler); zaehler++; if (zaehler<text.length) setTimeout("schreib()",100); } </script> </head> <body onload="schreib()"> </body> </html>
Dieses Beispiel gibt es wieder auf CD (beispiel0902.html).
body ist übrigens eine vordefinierte Eigenschaft von document und steht, wie der Name schon sagt, für das body-Element der Seite. Wie Sie bereits in Kapitel 7 erfuhren, erhält man darüber einige nützliche Werte. Beispielsweise liefert document.body.clientWidth die Breite des Dokuments - also ungefähr die innere horizontale Ausdehnung des Browserfensters (vgl. Anhang 2 zu Kapitel 10).
Das DOM
Die sehr unterschiedlichen Ansätze von Microsoft und Netscape machen es schwer, Seiten zu erstellen, die auf beiden Browsern gleichermaßen funktionieren. Die DOM-Spezifikation des World Wide Web Consortiums (W3C) soll dafür sorgen, dass das in Zukunft besser wird. "DOM" bedeutet "Document Object Model". Sie erinnern sich: Das Objektmodell bestimmt, wie die Elemente eines Dokuments (Links, Bilder, Überschriften usw.) in JavaScript als Objekte repräsentiert werden (vgl. Kapitel 3). So gesehen haben Netscape und Microsoft schon lange ihr eigenes DOM entwickelt. Wenn aber von dem DOM die Rede ist, dann ist das W3C-DOM gemeint: Es ist die offizielle, einheitliche Richtlinie für das Objektmodell zukünftiger Browser. Microsofts Internet Explorer unterstützt wesentliche DOM-Konzepte seit Version 5, und die aus dem Mozilla-Projekt hervorgegangene Version 6 von Netscape (eine Version 5 gab es nie) erfüllt die Richtlinien der ersten DOM-Spezifikation (Level 1) sogar schon so gut wie vollständig.
Betrachten Sie Netscape 6 nicht als Nachfolger von Version 4, sondern als eigenständige Neuentwicklung. Netscape 6 ist nicht kompatibel zum Objektmodell früherer Netscape-Versionen, insbesondere kennt er kein Layer-Objekt!
Alle in diesem Buch besprochenen W3C-Techniken sollten sowohl mit Internet Explorer 5 als auch mit Netscape 6 funktionieren.
Netscape 6 befindet sich derzeit (Sommer 2000) noch in einer frühen Beta-Phase. Es ist deshalb nicht völlig ausgeschlossen, dass Informationen, die Sie hier finden, für die Endversion gar nicht zutreffen. Mit großen Änderungen ist allerdings kaum zu rechnen.
getElementById()
Das Objektmodell des W3C stellt, noch konsequenter als das von Microsoft, alle Elemente einer Webseite - bis hin zu Kommentaren - als JavaScript-Objekte zur Verfügung. Es gibt aber nicht, wie beim Internet Explorer, eine all-Collection, in der alle diese Objekte aufgelistet sind. Stattdessen besitzt das document-Objekt die Methode getElementById(), der Sie die ID eines Elements übergeben und dafür eine Referenz auf das entsprechende Objekt zurück bekommen.
Befindet sich beispielsweise irgendwo im HTML-Code die Zeile
<b id="Grundgedanke">Grundgedanke</b>
dann verweist nach der Ausführung der JavaScript-Anweisung
var grund = document.getElementById("Grundgedanke")
die Variable grund auf dieses HTML-Element.
W3C-Sprech
Beim W3C wird auf den Unterschied zwischen Elementen, Attributen und so genannten TextNodes großen Wert gelegt. Ein Element umfasst gewöhnlich einen Start-Tag (zum Beispiel <b>), einen End-Tag (</b>) und alles, was dazwischen steht. Zu den Ausnahmen gehören img- und br-Elemente: Sie besitzen keinen End-Tag und keinen Inhalt. Im Start-Tag sind häufig Attribute definiert, z.B. id="Grundgedanke" oder src="bild.jpg". TextNodes schließlich sind zwischen den HTML-Tags stehende Text-Bereiche. Das Wort "Grundgedanke" im vorigen Beispiel ist ein TextNode.
Bemühen Sie sich um korrektes HTML, wenn Sie mit DOM-Methoden arbeiten. Ein mit <p> begonnener Absatz muss zum Beispiel stets mit </p> wieder geschlossen werden.
Intern werden HTML-Dokumente im DOM als Baum abgebildet. Sehen wir uns zur Veranschaulichung ein vollständiges Dokument an:
<html> <head> <title> </title> </head> <body> Hier steht was. <p> Und hier kommt der <b id="Grundgedanke"> Grundgedanke </b> </p> </body> </html>
Stellen Sie sich das Objekt document am besten als das Stück Papier vor, auf dem der Quelltext geschrieben ist. Dieses Papier kann in ein Fenster (ein window-Objekt) gehängt (geladen) werden, woraufhin man im Fenster sehen kann, was auf dem Papier definiert ist.
Der DOM-Baum
Abbildung 9.1: der DOM-Baum des Beispieldokuments
Das document-Objekt ist die Wurzel des Objektbaums, auf ihm ruht die ganze HTML-Struktur. Direkt über document liegt in unserem Beispiel das html-Element (es beginnt mit <html>, endet mit </html> und umfasst den gesamten Quelltext). Von da an verzweigt sich der Baum in zwei Stämme: einer fußt auf dem head-Element, der andere auf body. Man bezeichnet solche Unterglieder eines Elements auch als dessen "Kinder" (ChildNodes). body und head sind also im Beispieldokument die ChildNodes von html. head besitzt selbst wiederum ein Kind, nämlich title. Das body-Element hat bei uns zwei Kinder: das b-Element mit der ID "Grundgedanke" und den TextNode "Hier steht was". Auch TextNodes sind im DOM als JavaScript-Objekte vertreten. Der Oberbegriff für Elemente, Attribute, TextNodes und alle anderen Objekttypen im DOM ist Node ("Knoten"). Abbildung 9.1 zeigt die Nodes des Beispiel-Dokuments so wie sie im DOM repräsentiert sind.<>
Mit Hilfe von JavaScript können wir uns im DOM-Baum einer Webseite von unten nach oben, von oben nach unten und seitwärts in alle Richtungen fortbewegen. Dazu besitzt jeder Node die in Tabelle 9.4 angegebenen Eigenschaften.
Node-Eigenschaften
Eigenschaft | Beschreibung |
---|---|
firstChild | der erste ChildNode in der Reihenfolge, in der sie im Quelltext definiert sind |
lastChild | der letzte ChildNode vor dem Schluss-Tag des Elements |
childNodes | ein Array mit allen ChildNodes des aktuellen Elements |
parentNode | das Parent-Element des Nodes |
previousSibling | der vorhergehende Node auf derselben DOM-Ebene ("sibling" heißt "Geschwister".) |
nextSibling | der nächste Node auf derselben DOM-Ebene |
Tabelle 9.4: einige Eigenschaften von DOM-Nodes
Mit
document.body.firstChild
erhalten wir also im obigen Beispieldokument den TextNode "Hier steht was.".
document.body.firstChild.nextSibling
liefert uns das p-Element, über
document.body.firstChild.nextSibling.childNodes[1]
erreichen wir dessen zweites Kind, also das Element mit der ID "Grundgedanke". Wir hätten auch mit
document.getElementById("Grundgedanke")
direkt darauf zugreifen können. Der Ausdruck
document.getElementById("Grundgedanke").parentNode
bringt uns wieder zurück zum p-Element.
Die ganze Kletterei wäre nutzlos, wenn wir mit den Nodes, die wir so erreichen, nichts anfangen könnten. Das DOM erlaubt uns, Node-Inhalte zu lesen, zu überschreiben, Nodes zu löschen, ihre Attribute zu ändern und neue Nodes ins Dokument einzufügen.
Die Eigenschaft nodeValue liefert den Inhalt eines TextNodes. Hinter
document.body.firstChild.nodeValue
verbirgt sich also in unserem Beispiel der String "Hier steht was.". Sie können den Wert einfach überschreiben und dadurch den Text ändern:
document.body.firstChild.nodeValue = "Jetzt steht hier was anderes."
Beachten Sie, dass der nodeValue von Elementen stets null ist. Eine Eigenschaft wie innerText oder innerHTML, die den Inhalt eines Elements wiederspiegelt, stellt das DOM derzeit nicht zur Verfügung.
Sie können jederzeit einen neuen Node erzeugen. Dazu gibt es die Methoden
document.createElement("TagName")
und
document.createTextNode("Inhalt des Nodes")
Die Anweisung
var neuerAbsatz = document.createElement("P")
erzeugt zum Beispiel ein neues p-Element, einen Absatz also. Das Element ist anfangs noch leer und besitzt keine Attribute. Es hat auch noch keinen Platz im DOM-Baum. Um es ins Dokument einzubauen, müssen wir auf den Baum klettern und es dort befestigen. Das machen wir mit der Methode
Element.appendChild(einNode)
die den Node einNode als letztes Kind an das Element Element anhängt.
document.body.appendChild(neuerAbsatz)
würde also den vorhin erzeugten Absatz am Ende des body-Elements einfügen.
Wenn Sie einen Node nicht als letztes Kind seines ParentNodes, sondern an einer anderen Stelle einfügen wollen, benutzen Sie statt appendChild() die Methode
Element.insertBefore(einNode, nächsterNode)
wobei nächsterNode auf den Node verweist, vor dem der neue Node in den Baum eingehängt werden soll.
Jetzt ist unser Absatz also Bestandteil des Dokuments, aber immer noch leer. Um ihn zu füllen, müssen wir einen TextNode erzeugen und am neuen Absatz befestigen:
var inhalt = document.createTextNode("ein neuer Absatz"); neuerAbsatz.appendChild(inhalt);
Wir können dem neuen Element auch Attribute verpassen:
neuerAbsatz.id = "derNeueAbsatz"; neuerAbsatz.align = "right"; neuerAbsatz.style.fontWeight = "bold";
Die Auswirkung ist dieselbe, als hätten wir den Absatz in HTML so definiert:
<p id="derNeueAbsatz" align="right" style="font-weight:bold">
CSS-Eigenschaften im DOM
Diese Attribute kann man natürlich nicht nur schreiben, sondern auch lesen. Sie werden vor allem das style-Attribut gebrauchen, denn darüber stehen im DOM genau wie beim Internet Explorer die ganzen CSS-Eigenschaften des Elements zur Verfügung.
Dabei gelten dieselben Regeln wie beim Internet Explorer: Lesen kann man über die style-Eigenschaft nur die CSS-Angaben, die im Start-Tag des Elements definiert oder mit JavaScript gesetzt wurden. Wenn die Werte Maßeinheiten besitzen, dann werden diese beim Lesen mit geliefert. Es ist deshalb weder beim Internet Explorer noch im DOM möglich, ein Element mit der folgenden Anweisung um 5 Pixel nach unten zu versetzen:
document.getElementById("etwas").style.top+= 5;
Der Wert von style.top ist ein String, beispielsweise "200px". Das Ergebnis der obigen Zuweisung wäre also so etwas wie "200px5", und das ist keine erlaubte Positionsangabe. Auch die weit verbreitete Angabe von Zahlenwerten für Positions- oder Schriftgrößen ist streng genommen laut DOM nicht korrekt: Die Maßeinheit sollte nicht weggelassen werden.
Nodes können übrigens auch jederzeit aus dem DOM-Baum entfernt werden. Um unseren vorhin eingehängten Absatz wieder zu löschen, brauchen Sie nur diese Anweisung auszuführen:
document.body.removeChild(neuerAbsatz)
Machen Sie sich keine Sorgen, wenn Sie im Grundlagen-Teil das eine oder andere nicht gleich verstanden haben. Sie werden bei den folgenden Übungen sicher noch einige Male zurückblättern müssen. Wenn Sie eine ausführliche Referenz zur Hand haben, kann es auch nicht schaden, hin und wieder einen Blick in diese zu werfen.
Die Übungen sind wie der Grundlagenteil in verschiedene Abschnitte unterteilt. Wir fangen an mit ein paar Aufgaben zu Style Sheets, die Sie überspringen können, wenn Sie damit schon Erfahrung haben. Es folgen Übungen zum DHTML-Modell von Netscape 4, dann zu dem des Internet Explorers und schließlich zum DOM des W3C. Natürlich werden Sie in der Praxis Seiten entwerfen wollen, die auf möglichst allen Browsern funktionieren. Dem Cross-Browser-DHTML ist deshalb das gesamte nächste Kapitel gewidmet. Vorher sollten Sie sich aber ein gewisses Verständnis der unterschiedlichen Ansätze von Netscape, Microsoft und dem W3C angeeignet haben.
leicht
Nennen Sie drei Möglichkeiten, Style Sheets in eine HTML-Seite einzubinden.
leicht
Mit welcher Style-Angabe werden alle p-Elemente einer Seite in Schriftgröße 15pt formatiert?
Und was tun Sie, wenn Sie einen einzelnen Absatz von dieser Regel ausnehmen wollen?
mittel
Welche CSS-Angabe müsste eigentlich der gesamten Webseite eine Breite von 500 Pixel, die Schriftart Arial und einen Abstand von 20 Pixel zum linken Fensterrand geben?
mittel
Erstellen Sie eine Schrift mit einem Schatten.
leicht
Hier ist eine HTML-Seite:
<html> <head> <title>Nichts</title> </head> <body> <layer id="nichts" left="-100" top="0" width="100"> Auf dieser Seite gibt es nichts zu sehen. <img src="etwas.jpg" name="etwas" width="50" height="50"> </layer> </body> </html>
Warum ist tatsächlich nichts zu sehen, wenn man diese Seite mit Netscape 4 lädt?
leicht
Mit welcher JavaScript-Anweisung könnte man den Layer von Übung 5 in den sichtbaren Fensterbereich verschieben?
leicht
Geben Sie neun verschiedene Ausdrücke an, die alle auf das Bild mit dem Namen etwas im Dokument von Übung 5 verweisen.
mittel
Auf dieser Seite befindet sich ein Link, durch den man einen Textabsatz ein- und ausblenden kann:
<script> var zustand="sichtbar"; function einaus(){ if (zustand == "sichtbar"){ document.vielText.visibility = "hidden"; zustand = "unsichtbar"; } else { document.vielText.visibility = "visible"; zustand = "sichtbar"; } } </script> <layer id="vielText" left="200" top="20"> Hier steht ganz viel Text </layer> <a href="#" onClick="einaus()"> Text ein-/ausblenden </a>
Schreiben Sie die Seite so um, dass darin kein Layer-Tag mehr vorkommt.
mittel
Hier ein Ausschnitt aus einem anderen Dokument:
<body> <div id="RecyclingHof" style="position:absolute; left:300px; top:300px;"> <div id="AltglasContainer" style="position:absolute; left:100px; top:-20px;"> <div id="BraunglasContainer" style="position:absolute; left:0px; top:30px;"> <img name="Bierflasche" src="bier.jpg"> </div> </div> </div> </body>
An welcher Position, relativ zum gesamten Dokument, liegt die linke obere Ecke des Layers BraunglasContainer?
mittel
Mit welcher JavaScript-Anweisung kann das Bild "bier.jpg" in Übung 9 durch "milch.jpg" ersetzt werden?
mittel
Als Nächstes ein Aquarium. Erstellen Sie mit einem Grafikprogramm ein paar Bilder von Blättern und Algen und positionieren Sie sie mit Style Sheets so im Fenster, dass ein hübsches Aquarium entsteht. Wählen Sie auch eine passende Hintergrundfarbe für den body.
Es fehlen noch die Fische. Auch hier brauchen Sie geeignete Bilder, und zwar sollten Sie von jedem Fisch zwei haben: eins auf dem der Fisch nach rechts und eins auf dem er nach links schwimmt. Besonders elegant wird es, wenn Sie animierte Grafiken verwenden, dann können Sie sogar die Flossen schlagen lassen.
Lassen Sie nun Ihre Fische langsam hin und her durchs Wasser ziehen.
schwer
Layer sind durchsichtig: Überall dort, wo das Dokument eines Layers keine (oder durchsichtige) Elemente enthält, ist das unter dem Layer liegende Dokument zu sehen. Um den Layer undurchsichtig zu machen, müssen Sie ihm eine Hintergrundfarbe oder ein Hintergrundbild geben. Die CSS-Angaben dafür sind:
background-image:url(dasHintergrundbild.jpg)
layer-background-image:url(dasHintergrundbild.jpg)
background-color:#6666ff;
layer-background-color:#6666ff;
Sei sollten zusätzlich zum W3C-konformen background-color-Attribut stets auch layer-background-color angeben, denn mit background-color alleine werden nur die Layer-Bereiche farbig hinterlegt, auf denen Text oder HTML-Elemente stehen. Dasselbe gilt für background-image und layer-background-image. (Der Effekt ist nicht ganz einfach zu beschreiben - wenn Sie es ausprobieren, werden Sie sofort verstehen, was gemeint ist.)
Schreiben Sie nun eine Seite mit fünf farbigen, leicht versetzt übereinander gestapelten Quadraten.
Mit Hilfe von Formular-Buttons soll man die Stapelreihenfolge der Quadrate verändern können: Ein Button stellt die dunklen nach oben, einer die hellen, ein dritter sortiert sie nach dem Zufallsprinzip.
Um einen Layer auf quadratische Form zu strecken, benutzen Sie das CSS-Attribut clip:
"ig;e 200x200 Pixel </div>
Eine Zufallszahl zwischen 0 und 1 liefert die Anweisung Math.random().
mittel
Schicke Effekte lassen sich mit halbtransparenten Hintergrundbildern erzielen. Gemeint sind kleine Bilder im gif-Format, die gleichmäßig verteilte transparente Anteile haben (vgl. Abbildung 9.2).
Abbildung 9.2: ein "halbtransparentes" Pixelmuster (vergrößert)
Für die nächste Aufgabe geben Sie einer Seite im body-Tag ein Hintergrundbild. Dann erstellen Sie einen Layer mit halbtransparentem Hintergrund, der einige Links enthält (der Layer natürlich, nicht der Hintergrund). Dieses Navigationsmenü soll anfangs aber nicht zu sehen sein. Erst wenn man auf einen Button klickt, erscheint es - und zwar indem es sich von oben nach unten ausfährt. Dazu ändern Sie einfach nach und nach den clip.bottom -Wert des Layers.
Benutzen Sie folgende Style-Definition:
<style type="text/css"> #menu { position:absolute; left:10; top:30; clip:rect(0px 200px 0px 0px); width:200px; background-image:url(semitrans.gif); padding:10px } a { font-weight:bold; color:black; text-decoration:none } </style>
Das Bild "semitrans.gif" müssen Sie natürlich erst einmal erstellen (oder von der beiliegenden CD kopieren). Der nicht-transparente Anteil sollte dabei weiß sein.
mittel
Eine der Stärken des Objektmodells von Netscape liegt in der einfachen Einbeziehung externer Inhalte in ein Dokument: Im Grunde kann jeder Layer auf einer Seite von einem anderen URL stammen. Wäre dieses Konzept weiterentwickelt worden, würden wir Frames kaum noch benötigen.
Erweitern Sie die Lösung von Übung 13 so, dass bei der Auswahl eines Menüpunkts die dazugehörige Datei auf derselben Seite angezeigt wird. Auch hier soll der Hintergrund halb durchsichtig sein.
leicht
Wie kann man im Internet Explorer mit JavaScript auf dieses Element verweisen?
<p id="Satie"> Das Meer ist voll Wasser - das soll einer verstehen. </p>
Und wie jetzt?
<div id="Erik" style="position:absolute"> <p id="Satie"> Das Meer ist voll Wasser - das soll einer verstehen. </p> </div>
leicht
Sehen Sie sich dieses Stück Quelltext an:
<p id="Satie"> Das Meer ist voll Wasser - das soll einer verstehen. </p> <script> document.all["Satie"].visibility = "hidden"; </script>
Was passiert hier?
Wie könnte man erreichen, was eigentlich beabsichtigt war?
leicht
Schreiben Sie eine Seite mit drei Absätzen. Die Schriftfarbe dieser Absätze soll grau sein. Bewegt man sich aber mit der Maus darüber, wechselt sie auf schwarz.
mittel
Erstellen Sie eine Schrift, die ganz klein auf der Seite auftaucht und dann immer größer wird.
mittel
Noch ein zoom-Effekt. Diesmal soll die Schrift nicht nur größer werden, sondern auch dunkler. Außerdem sollen mehrere Texte nacheinander eingezoomt werden, die dann untereinander stehen bleiben.
Zur Angabe der Schriftfarbe verwenden Sie am besten die Dezimal-Schreibweise:
rotesElement.style.color = "rgb(255,0,0)"
Der color-Wert ist hier ein String, bestehend aus "rgb(", dem Farbwert für Rot (0-255), gefolgt von einem Komma, gefolgt vom Grünanteil, gefolgt von noch einem Komma, dem Blauwert und einer schließenden Klammer.
mittel
Auf einer Webseite steht ein Formular mit einem textarea-Feld und einem Button. Darunter befindet sich ein leeres graues Rechteck. Wenn man etwas in das Formular eingibt und den Button drückt, wird der Inhalt der textarea in das graue Rechteck kopiert. Der Witz dabei ist: Gibt man HTML-Formatierungen ein, dann werden diese im grauen Rechteck nicht angezeigt, sondern ausgewertet. Schreibt man zum Beispiel
<b>Kohl</b>
dann erscheint im Rechteck das Wort "Kohl" fett formatiert.
Schreiben Sie diese Anwendung.
mittel
Sollten Sie bereits versucht haben, auch im Internet Explorer mit halbtransparenten Hintergrundbildern zu arbeiten, dann wird Ihnen nicht entgangen sein, dass IE zum Rendern hierfür wesentlich länger braucht als Netscape - zu lange selbst für einfache Animationen.
CSS-Filter
Das ist aber nicht weiter schlimm, denn Internet Explorer kennt - zumindest in der Windows-Version - etwas viel Schöneres: CSS-Filter. Um ein positioniertes Element halb durchsichtig zu machen, brauchen Sie ihm lediglich die CSS-Angabe filter:alpha(opacity=50) zu geben:
";
Der Wert 50 liegt genau in der Mitte zwischen unsichtbar (0) und undurchsichtig (100).
Wie alle style-Angaben lässt sich auch die "Filterstärke" mit JavaScript verändern. Schreiben Sie eine Seite, deren gesamter Inhalt nach dem Laden langsam eingefadet wird.
schwer
In Übung 14 sahen Sie, wie man bei Netscape 4 mit Hilfe von Layern eine externe HTML-Seite nachträglich in ein bestehendes Dokument einfügen kann. Der Internet Explorer kennt kein Layer-Objekt. Wie könnte man den gewünschten Effekt trotzdem erreichen?
leicht
Zeichnen Sie den DOM-Baum des folgenden Dokuments.
<html> <head> <title>Wo</title> </head> <body> <h2>Wo kämen wir hin...</h2> <p>...wenn jeder sagte: <b>Wo kämen wir hin?</b>,<br> und keiner ginge, um zu sehen, wohin wir kämen, wenn wir gingen?</p> </body> </html>
Vergessen Sie nicht, dass auch TextNodes im DOM eigene Objekte sind!
leicht
Im Dokument der vorherigen Übung: Worauf verweisen diese beiden Ausdrücke?
document.body.childNodes[0].firstChild
document.childNodes[0].lastChild.firstChild. childNodes[0]
leicht
Und worauf zeigt dieses Ungetüm?
document.body.previousSibling.lastChild.parentNode. parentNode.childNodes[1].childNodes[1].previousSibling. lastChild
Gehen Sie Schritt für Schritt der Referenzierung durch den DOM-Baum nach.
leicht
Wieso löschen diese Anweisungen nicht den Inhalt der Überschrift?
var el = document.body.childNodes[0].firstChild; document.body.removeChild(el);
mittel
Schreiben Sie eine Funktion, die, wenn Sie onload aufgerufen wird, alle Überschriften der Seite automatisch durchnummeriert. Das heißt, wenn die erste Überschrift "Der Treibhauseffekt" heißt, dann soll daraus "1. Der Treibhauseffekt" werden, und so weiter.
Gehen Sie der Einfachheit halber davon aus, dass alle Überschriften direkte Kinder des body-Elements sind, so dass Sie den DOM-Baum nicht weiter zu durchsuchen brauchen. Sie müssen allerdings herausfinden, ob es sich bei einem bestimmten Node um eine Überschrift handelt. Dabei hilft Ihnen die Element-Eigenschaft tagName, die den Tag-Namen in Großbuchstaben enthält, also zum Beispiel "H1".
schwer
Verbessern Sie die Funktion aus der letzten Übung, so dass sie nicht nur die Überschriften durchnummeriert, sondern zusätzlich am Anfang der Seite ein kleines Inhaltsverzeichnis einfügt, das mit lokalen Links auf die einzelnen Unterabschnitte verweist. Die Einträge im Inhaltsverzeichnis sollen dem Text der dazugehörigen Überschriften entsprechen. !! IE5/Mac Entity-Probleme??!!!
schwer
Schreiben Sie eine JavaScript-Funktion, die ein neues Fenster öffnet und darin den DOM-Baum des Ausgangsfensters darstellt. Die Ausgabe könnte zum Beispiel so aussehen:
+ HTML | +--+ HEAD | | | +--+ TITLE | | | +-- ein Titel | +--+ BODY | +-- vergessen Sie nie den | +--+ B | +-- Grundgedanken
leicht
Benutzen Sie das Skript aus der letzten Übung, um sich anzusehen, wie die neuesten Browser den DOM-Baum verschiedener Seiten intern abbilden. Dazu können Sie das Bookmark von der CD benutzen oder den Quelltext, den Sie testen wollen, einfach zusammen mit dem Script auf eine Seite stellen.
Sie werden einige Besonderheiten entdecken, die Sie bei der Arbeit mit DOM-Methoden beachten sollten.
Sonderzeichen im DOM
Wir legen in einem style-Element die Schriftgröße aller Absätze auf 15pt fest:
p { font-size: 15pt }
Den einen Absatz, der anders dargestellt werden soll, versehen wir mit einer ID und weisen ihm so eine andere Schriftgröße zu:
#wichtigerAbsatz { font-size: 25pt }
body { width:520px; padding:20px; font-family:Arial }
So jedenfalls sollte es funktionieren. Wenn Sie es ausprobieren, werden Sie aber bemerken, dass sich hier bei Netscape und Internet Explorer Bugs eingeschlichen haben: Der Internet Explorer ignoriert die width-Angabe, bei Netscape 4 geht häufig die Schriftart verloren, zum Beispiel in und nach einer Tabelle.
Auf solche Bugs werden Sie noch häufig stoßen. Es empfielt sich deshalb, CSS-Angaben immer sofort mit den Browsern zu testen, um sich später eine mühsame Fehlersuche zu ersparen.
Die Style-Definition für die beiden Elemente könnte so aussehen:
<style type="text/css"> #schrift { position:absolute; left:25px; top: 15px; color:#3333ff; font-size:30px; z-index:20; } #schatten { position:absolute; left:27px; top: 18px; color:#bbbbbb; font-size:30px; z-index:10; } </style>
Im body brauchen nur noch die beiden Elemente angelegt zu werden:
<div id="schrift">Wo Schatten ist, ist Licht.</div> <div id="schatten">Wo Schatten ist, ist Licht.</div>
Der gesamte Inhalt des body steht in einem Layer. Die linke Kante des Layers ist auf -100 Pixel gesetzt, das heißt auf 100 Pixel links vom linken Rand des Browserfensters. Da außerdem die Layerbreite auf 100 Pixel beschränkt ist, liegt der ganze Layer außerhalb des sichtbaren Bereichs.
Die horizontale Position des Layers ist in der left-Eigenschaft des Layer-Objekts festgelegt. Um die Layerposition zu verändern, brauchen Sie diesen Wert nur zu überschreiben:
document.layers["nichts"].left = 0;
Jetzt befindet sich der Layer genau in der linken oberen Ecke des Fensters.
Die neun Ausdrücke, die Sie gefunden haben sollten, sind:
document.layers[0].document.images[0] document.layers[0].document.images["etwas"] document.layers[0].document.etwas document.layers["nichts"].document.images[0] document.layers["nichts"].document.images["etwas"] document.layers["nichts"].document.etwas document.nichts.document.images[0] document.nichts.document.images["etwas"] document.nichts.document.etwas
Es gibt sogar noch mehr. Zum Beispiel können Sie auf Collection-Elemente auch zugreifen, indem Sie das Element als Eigenschaft der Collection ansprechen:
document.layers.nichts.document.images.etwas
Was dagegen nicht funktioniert, ist:
document.images[0] document.images["etwas"] document.etwas
Die Faustregel lautet: Alle <layer> durch <div> mit absoluter CSS-Positionierung ersetzen. Da positionierte div-Elemente von JavaScript als Layer behandelt werden, ändert sich am Skript-Bereich überhaupt nichts. Nur der Layer selbst wird anders geschrieben:
<div id="vielText" style="position:absolute; left:200px; top:20px"> Hier steht ganz viel Text </div>
Die Positionsangaben im Style-Attribut der div-Tags werden (genau wie die in einem layer-Tag) immer relativ zu demjenigen Dokument ausgewertet, in dem das div-Element sich befindet. Die Beispielseite enthält vier Dokumente: Das Dokument des BraunglasContainers liegt innerhalb des AltglasContainer-Dokuments, dieses wiederum liegt innerhalb des RecyclingHofs, welcher sich schließlich im Hauptdokument befindet. Um die Position des BraunglasContainers zu bestimmen, müssen Sie die Koordinaten zusammenzählen: Seine linke Kante ist 0px entfernt von der linken Kante des BraunglasContainers, diese Kante ist 100px rechts von der des RecyclingHofs, welche 300px von der linken Fensterkante entfernt liegt. Die resultierende x-Koordinate ist also 400px. Die y-Koordinate ergibt, wie Sie leicht nachprüfen können, 310px.
Zum Beispiel mit
document.RecyclingHof.document.AltglasContainer.document. BraunglasContainer.document.Bierflasche.src = "milch.jpg";
Wenn Ihnen Übung 7 Spaß gemacht hat, können Sie jetzt die 255 anderen Möglichkeiten lien, wie man eine Referenz auf das Bild erhalten kann.
Zuerst verteilen wir ein paar Pflanzen:
<body bgcolor="#4077a9"> <div style="position:absolute; left:-10; top:200; z-index:20"> <img src="alge.gif" width="50" height="250"> </div> <div style="position:absolute; left:100; top:300; z-index:30"> <img src="alge.gif" width="30" height="200"> </div> <div style="position:absolute; left:600; top:250; z-index:10"> <img src="alge.gif" width="50" height="350"> </div> <div style="position:absolute; left:200; top:250; z-index:40"> <img src="blatt.gif" width="50" height="90"> </div> <div style="position:absolute; left:550; top:350; z-index:20"> <img src="blatt.gif" width="60" height="100"> </div>
Wie Sie sehen, war ich faul und habe nur zwei Grafiken erstellt, die ich in verschiedene Größen skaliere. Genauso mache ich es bei den Fischen:
<div id="fisch1" style="position:absolute; left:0; top:220; z-index:35"> <img src="fischre.gif" name="f1" width="150" height="75"> </div> <div id="fisch2" style="position:absolute; left:800; top:350; z-index:15"> <img src="fischli.gif" name="f2" width="100" height="50"> </div>
Jetzt müssen wir die Fische animieren. Dazu brauchen wir JavaScript.
Es gibt zahlreiche Herangehensweisen für Animations-Effekte. Hier ein ganz einfacher Vorschlag. Im Laufe dieses und des nächsten Kapitels werden Ihnen noch elegantere Lösungen begegnen.
Erst einmal halten wir die aktuelle Bewegungsrichtung unserer Fische fest:
var richtung_fisch1 = "rechts"; var richtung_fisch2 = "links";
Dann brauchen wir eine Funktion, die die Fische um einen Schritt vorwärts bewegt und gegebenenfalls die Richtung wechselt:
function bewegeFische(){ if (richtung_fisch1=="rechts") { // Fisch schwimmt nach rechts if (document.fisch1.left<800) // 3 Pixel vorwärts document.fisch1.left+=3; else { // wenden richtung_fisch1 = "links"; document.fisch1.document.f1.src="fischli.gif"; } } else { // Fisch schwimmt nach links if (document.fisch1.left>100) document.fisch1.left-=3; else { // wenden richtung_fisch1 = "rechts"; document.fisch1.document.f1.src="fischre.gif"; } } // Dasselbe fuer den zweiten Fisch: if (richtung_fisch2=="rechts") { if (document.fisch2.left<600) // dieser Fisch ist etwas langsamer: document.fisch2.left+=2; else { richtung_fisch2 = "links"; document.fisch2.document.f2.src="fischli.gif"; } } else { if (document.fisch2.left>0) document.fisch2.left-=2; else { richtung_fisch2 = "rechts"; document.fisch2.document.f2.src="fischre.gif"; } } }
Mit setInterval rufen wir diese Funktion alle 50 Millisekunden auf:
setInterval("bewegeFische()",50);
Für flüssige Bewegungen sollten Sie stets einen Zeitabstand von 30-50 Millisekunden wählen. Ein gewisses Ruckeln ist dabei leider immer noch zu erkennen. Niedrigere Werte können die Browser aber (zumindest auf Windows-Betriebssystemen) nicht verarbeiten. Nur auf MacIntosh und Unix/Linux sind wirklich weiche Bewegungsabläufe möglich.
Wir schreiben erst einmal die Layer. So sieht der erste aus:
<div id="q1" style="position:absolute; left:200px; top:200px; clip:rect(0px 200px 200px 0px); z-index:1; background-color:#000099; layer-background-color:#000099"> Quadrat 1 </div>
Um die Stapelreihenfolge festzulegen, habe ich ihm neben einer Position und einer Hintergrundfarbe einen festen z-index-Wert zugewiesen. Lässt man bei einer Layer-Definition die z-index-Angabe weg, dann gibt Netscape dem Layer automatisch den z-index-Wert des zuletzt erzeugten Layers. Bei gleichem z-index-Wert liegt der zuletzt definierte Layer oben.
Die anderen Quadrate sehen ähnlich aus, wir ändern einfach Namen, Position, Farbe und z-index:
<div id="q2" style="position:absolute; left:210px; top:190px; clip:rect(0px 200px 200px 0px); z-index:2; background-color:#0033cc; layer-background-color:#0033cc"> Quadrat 2 </div> <div id="q3" style="position:absolute; left:220px; top:180px; clip:rect(0px 200px 200px 0px); z-index:3; background-color:#0066ff; layer-background-color:#0066ff"> Quadrat 3 </div> <div id="q4" style="position:absolute; left:230px; top:170px; clip:rect(0px 200px 200px 0px); z-index:4; background-color:#3399ff; layer-background-color:#3399ff"> Quadrat 4 </div> <div id="q5" style="position:absolute; left:240px; top:160px; clip:rect(0px 200px 200px 0px); z-index:5; background-color:#66ccff; layer-background-color:#66ccff"> Quadrat 5 </div>
Als Nächstes brauchen wir ein Formular zur Steuerung der Stapelreihenfolge:
<form name="steuerung"> <input type="button" value="hell nach oben" onclick="hellhoch()"> <br> <input type="button" value="dunkel nach oben" onclick="dunkelhoch()"> <br> <input type="button" value="mischen" onclick="mischen()"> </form>
Jetzt fehlen nur noch die JavaScript-Funktionen. Diese sind ganz einfach:
function hellhoch() { for (i=1;i<=5;i++) { document.layers["q"+i].zIndex=i; } } function dunkelhoch() { for (i=1;i<=5;i++) { document.layers["q"+i].zIndex=6-i; } } function mischen() { for (i=1;i<=5;i++) { document.layers["q"+i].zIndex=Math.random()*10; } }
Wir machen uns hier die Tatsache zu Nutze, dass beim Verweisen auf Layer mittels
document.layers["LayerID"]
der Layername als String angegeben wird. Deshalb können wir innerhalb der eckigen Klammern String-Operationen ausführen und Variablen einsetzen. Mit anderen Schreibweisen wie
document.LayerID
wäre das nicht möglich. Zusammen mit den strategisch günstig gewählten Layernamen erhalten wir so angenehm schlanke Funktionen.
Nachdem die CSS-Angaben im style-Bereich untergebracht sind, sieht das Menü wie folgt aus:
<div id="menu"> <a href="eins.html">eine andere Seite</a><br> <a href="zwei.html">ein anderes Buch</a><br> <a href="drei.html">ein anderes Papier</a><br> <a href="vier.html">eine andere Erde</a><br> <a href="fuenf.html">eine andere Welt</a> </div>
Dazu kommt der einfache Button, der die JavaScript-Funktion aufruft:
<form name="steuerung"> <input type="button" value="Menü anzeigen" onclick="menuEinAus()"> </form>
Die Funktion will erst einmal wissen, ob das Menü im Moment aus- oder eingeklappt ist. Deshalb definieren wir eine globale Variable, die den aktuellen Menüzustand speichert:
var zustand = "versteckt";
Die Funktion selbst sollte Ihnen keine allzu großen Schwierigkeiten bereiten, sie entspricht weitgehend den Funktionen zum Bewegen der Fische im Aquarium. Mein Vorschlag sieht diesmal so aus:
function menuEinAus() { if (zustand == "versteckt") { document.menu.clip.bottom+=5; if (document.menu.clip.bottom>150) { zustand = "sichtbar"; return; } } else { document.menu.clip.bottom-=5; if (document.menu.clip.bottom<1) { zustand = "versteckt"; return; } } setTimeout("menuEinAus()",30); }
Diesmal habe ich die return-Anweisung eingesetzt: Wenn die Bewegung an ihrem Ziel angelangt ist, wird damit die Abarbeitung der Funktion beendet.
Sie brauchen zwei ineinander verschachtelte Layer hintergrund und inhalt:
<div id="hintergrund"> <div id="inhalt"> </div> </div>
Die Style-Definitionen aus Übung 13 muss dazu um die folgenden Einträge ergänzt werden:
#hintergrund { position:absolute; left:250; top:30; clip:rect(0px 500px 500px 0px); layer-background-image:url(semitrans.gif) } #inhalt { position:absolute; left:10; top:10 }
In der JavaScript-Funktion, die den Inhalt von inhalt wechselt, können Sie entweder mit src oder mit load arbeiten. Die erste Variante sieht so aus:
function lade(url) { document.hintergrund.document.inhalt.src = url; }
Wir nehmen aber besser load, um dadurch die Layer-Breite bestimmen zu können. Außerdem wollen wir, dass nach der Auswahl eine Menüpunktes das Menü wieder zuklappt. Deshalb wird noch menuEinAus() aufgerufen:
function lade(url) { document.hintergrund.document.inhalt.load(url,480); menuEinAus(); }
Anschließend müssen nur noch die Menü-Einträge angepasst werden, damit sie die Funktion lade() aufrufen:
<div id="menu"> <a href="javascript:lade('eins.html')">Seite</a><br> <a href="javascript:lade('zwei.html')">Buch</a><br> <a href="javascript:lade('drei.html')">Papier</a><br> <a href="javascript:lade('vier.html')">Erde</a><br> <a href="javascript:lade('fuenf.html')">Welt</a> </div>
Mit
document.all["Satie"]
oder
document.all.Satie
oder
window.Satie
oder
Satie
Ob sich das Element in einem div befindet (positioniert oder nicht), ist dem Internet Explorer ziemlich egal.
Was passiert ist Folgendes: Dem Objekt document.all.Satie wird eine neue Eigenschaft verpasst, nämlich visibility, und dieser Eigenschaft wird als Wert der String "hidden" zugewiesen.
Sonst passiert nichts.
Um das Satie-Element unsichtbar zu machen, muss die Eigenschaft visibility seines style-Objekts geändert werden:
document.all["Satie"].style.visibility = "hidden";
<p style="color:gray" onmouseover="this.style.color='black'" onmouseout="this.style.color='gray'"> ... erster Absatz ... </p> <p style="color:gray" onmouseover="this.style.color='black'" onmouseout="this.style.color='gray'"> ... zweiter Absatz ... </p> <p style="color:gray" onmouseover="this.style.color='black'" onmouseout="this.style.color='gray'"> ... dritter Absatz ... </p>
Zuerst brauchen wir ein Element, in dem der Text steht. Anfangs hat dieser eine sehr kleine Schriftgröße:
<div id="zoomDiv" align="center" style="font-size:2px"> der Zoom-Text </div>
Wenn die Seite fertig geladen ist, wird eine JavaScript-Funktion aufgerufen, die die Schrift vergrößert:
<body onload="zoom()">
Um nicht jedesmal die aktuelle Schriftgröße auslesen zu müssen, legen wir eine Variable an, die den derzeitigen Wert enthält:
var schriftGroesse = 2;
Bei jedem Funktionsaufruf wird die Schrift um 5 Pixel vergrößert. Wenn 200px erreicht sind, bricht die Funktion ab, andernfalls ruft sie sich mit 30 Millisekunden Verzögerung erneut auf.
function zoom() { schriftGroesse+=5; zoomDiv.style.fontSize = schriftGroesse+"px"; if (schriftGroesse<200) setTimeout("zoom()",30); }
Wenn Sie das Beispiel ausprobiert haben, konnten Sie vermutlich (wenn Sie nicht gerade eine Kinoleinwand als Bildschirm verwenden) feststellen, wie der Internet Explorer das Dokument ständig neu rendert: Er fügt zum Beispiel wenn nötig Zeilenumbrüche ein, um den Text im Fenster unterzubringen.
Drei Textbereiche sollen eingezoomt werden:
<div id="zoomDiv1" align="center" style="font-size:2px; color:#ffffff"> Kein Angst! </div> <div id="zoomDiv2" align="center" style="font-size:2px; color:#ffffff"> Es ist nur </div> <div id="zoomDiv3" align="center" style="font-size:2px; color:#ffffff"> DHTML... </div>
Für die zoom-Funktion brauchen wir diesmal neben der Größen-Variable auch eine Variable, die den aktuellen Grauwert speichert. Am Anfang ist er 255, die Schrift also weiß:
var schriftGroesse = 2; var farbe = 255;
Jetzt könnte man einfach drei Funktionen schreiben, von denen die erste den ersten div-Bereich einzoomt, wenn sie fertig ist, die zweite aufruft, die den zweiten einzoomt, und so weiter. Es geht aber kompakter, indem das aktuelle div-Element ebenfalls in einer Variablen mitgezählt wird. Die Referenzierung auf das Element geht dann so:
document.all["zoomDiv"+divZaehler]
Hier die vollständige Funktion:
var divZaehler = 1; function zoom(){ schriftGroesse += 5; // jeder Absatz wird in 20 Schritten gezoomt, deshalb // machen wir die Schrift bei jedem Schritt um 255/20 // dunkler, so dass wir am Schluss bei 0 ankommen: farbe -= 255/20; var el = document.all["zoomDiv"+divZaehler]; el.style.fontSize = schriftGroesse+"px"; el.style.color = "rgb("+farbe+","+farbe+","+farbe+")"; if (schriftGroesse>100) { // ab in die nächste Runde divZaehler++; schriftGroesse = 2; farbe = 255; } if (divZaehler<4) setTimeout("zoom()",30); }
Zuerst das Formular mit dem Eingabefeld:
<form name="formular"> <textarea name="eingabe" cols="50" rows="10"> </textarea> <input type="button" value="anzeigen" onclick="schreib()"> </form>
Dann das graue Rechteck:
<div id="rechteck" style="position:absolute; left:10px; top:200px; width:400; height:300; background-color:#cccccc;"> </div>
(Beachten Sie, dass bei Internet Explorer keine clip-Angabe nötig ist, um die Fläche des div zu erweitern, width und height reichen aus. Das Attribut layer-background-color gibt es natürlich auch nicht.)
Schließlich die verblüffend simple JavaScript-Funktion:
function schreib() { document.all.rechteck.innerHTML = document.forms['formular'].eingabe.value; }
Sie können den "HTML-Editor"-Effekt übrigens noch verbessern, indem Sie den Button weglassen und stattdessen im textarea-Tag einen onkeyup-Handler einsetzen:
<textarea name="eingabe" cols=50 rows=10 onkeyup="schreib()"> </textarea>
Damit wirkt sich jede Eingabe ins Formularfeld automatisch im Anzeige-Rechteck aus.
Ich wende den Filter auf das body-Element an:
<html> <head> <title>gar nicht fade</title> <script> var z = 0; function fadein(){ z+=5; document.body.style.filter = "alpha(opacity:"+z+")"; if (z<100) setTimeout("fadein()",50); } </script> </head> <body style="position:absolute; filter:alpha(opacity:0)" onload="fadein()"> ...der Seiteninhalt... </body> </html>
Für einfache Effekte wie Ein-, Aus- und Überblenden bietet Microsoft vorgefertigte dynamische Filter an. Das folgende Beispiel zeigt einen eleganten, mit Hilfe des blendTrans-Filters realisierten Mouseover-Effekt:
<html> <head> <script> function rollover() { document.all.bild.filters.blendTrans.Apply(); document.all.bild.src = "bildOver.gif"; document.all.bild.filters.blendTrans.Play(); } function rollout(){ document.all.bild.filters.blendTrans.Apply(); document.all.bild.src = "bild.gif"; document.all.bild.filters.blendTrans.Play(); } </script> </head> <body> <img src="bild.gif" id="bild" style="filter:blendTrans(Duration=0.5)" onmouseover="rollover()" onmouseout="rollout()"> </body> </html>
Dynamische Filter funktionieren derzeit nur mit Internet Explorer auf Windows, und auch hier nicht in allen Versionen: Manche IE 4 ignorieren sie völlig, und selbst IE 5.5 versteht viele Filtereffekte nicht mehr (- dafür kennt er ein paar Neue).
Im HTML-Quelltext der Hauptseite steht ein Element, in dem das externe Dokument angezeigt werden soll:
<div id="anzeige" style="background-color:#dddddd; width:400px; height:400px"> </div>
Dann brauchen wir einen Iframe, der den Seiteninhalt zwischenspeichert. Mit geeigneten Style-Angaben wird er unsichtbar:
<iframe id="puffer" style="width:0px; height:0px"> </iframe>
Um die externe Seite einzubinden, wird die Funktion lade() aufgerufen:
<a href="javascript:lade('eins.html')"> eine andere Seite </a>
Diese Funktion tut nichts anderes, als die übergebene Adresse in den Iframe zu laden:
function lade(url) { puffer.location.href = url; }
Schließlich brauchen wir noch eine Funktion, die aufgerufen wird, wenn der Iframe-Inhalt fertig geladen ist. Dann nämlich kann der Inhalt des Iframe-body ausgelesen und in den anzeige-div kopiert werden:
function fertig(){ document.all.anzeige.innerHTML = puffer.document.body.innerHTML; }
Was noch fehlt, ist nur ein entsprechender Eintrag im body-Tag der externen Seite:
<body onload="parent.fertig()">
Das war's.
In Version 5 des Internet Explorers gibt es noch einen besseren Weg, der auf einem DHTML-Behavior beruht. Behaviors werden derzeit von Netscape 6 und der Windows-Version des IE5 unterstützt (das Format ist allerdings zwischen beiden sehr unterschiedlich). Es handelt sich dabei um externe Komponenten, die das Standardverhalten bestimmter HTML-Elemente festlegen. Bei Microsoft gibt eine Reihe von Default-Behaviors, die jedoch keine Extra-Datei verlangen. Dazu gehört auch das Download-Behavior. Die Syntax ist ganz einfach:
Wir nehmen irgendein Element und verpassen ihm das Behavior:
<p id="schaufel" style="behavior:url(#default#download)"> </p>
(Bei gewöhnlichen Behaviors würde man dort, wo hier #default#download steht, den URL der externen Datei eintragen.)
Damit besitzt das Element automatisch die Methode startDownload(), der zwei Parameter übergeben werden: Eine einzulesende (Text-)Datei und eine Funktion, die aufgerufen wird, wenn die Datei fertig gelesen ist. Dieser Funktion wird dann der Datei-Inhalt automatisch als String übergeben. Für unser Beispiel sähe das so aus:
schaufel.startDownload('eins.html', fertig);
function fertig(text) { document.all.anzeige.innerHTML = text; }
Abbildung 9.3: der DOM-Baum von Übung 23
Beide Ausdrücke zeigen auf den TextNode "Wo kämen wir hin...".
document.childNodes[0].lastChild entspricht auf der Beispielseite document.body, und "Wo kämen wir hin..." ist das erste Kind des ersten Kindes (das h2-Element) des body. Das erste Kind eines Elements erreicht man wahlweise mit firstChild oder childNodes[0].
Sie ahnten es: Auch dieser Ausdruck verweist auf "Wo kämen wir hin...". Schauen wir uns die einzelnen Schritte an: Wir starten mit
document.body.previousSibling
beim head-Element, machen mit
lastChild.parentNode
von dort einen nutzlosen Abstecher zum title und zurück. Über
parentNode
landen wir beim Eltern-Element des head, also bei html, von da an geht es mit
childNodes[1].childNodes[1]
über den body zum TextNode "...wenn jeder sagte: ". Dessen vorangehender Node,
previousSibling
ist das h2-Element.
lastChild
führt uns schließlich zu dessen einzigem Kind: "Wo kämen wir hin...".
Die Methoden zum Anhängen und Entfernen von Nodes beziehen sich immer auf die Kinder des Elements, von dem aus Sie aufgerufen werden. (Daher das "child" in appendChild und removeChild.) Der Inhalt der Überschrift ist aber ein Kind des h2-Elements, nicht von document.body. Korrekt müsste es also heißen:
var el = document.body.childNodes[0].firstChild; document.body.childNodes[0].removeChild(el);
oder:
var el = document.body.childNodes[0].firstChild; el.parentNode.removeChild(el);
function ordnung() { // In einem Array speichern wir die zu überprüfenden // Tags: var tags = new Array("H1","H2","H3","H4","H5"); // Dann brauchen wir eine Variable, die die Überschriften // zählt: var zaehler = 1; // Jetzt durchsuchen wir die Kinder von body // und ändern den Inhalt aller Überschriften: for (i=0; i<document.body.childNodes.length; i++){ kind = document.body.childNodes[i]; for (j=0; j<tags.length; j++){ if (kind.tagName == tags[j]) { kind.firstChild.nodeValue = zaehler+". "+kind.firstChild.nodeValue; zaehler++; } } } }
function ordnung(){ // Zuerst die globalen Variablen, angefangen mit dem // Überschriften-Zähler und dem Array für die gesuchten // Tags: var tags = new Array("H1","H2","H3","H4","H5"); var zaehler = 1; // Wir brauchen außerdem einen Array für die Texte der // Überschriften, aus denen wir das Inhaltsverzeichnis // aufbauen: var inhalt = new Array(); // Als Nächstes durchsuchen wir die Kinder des body // nach Überschriften, geben ihnen IDs, benennen ihren // Inhalt um und sammeln ihn im Array inhalt: for (i=0; i<document.body.childNodes.length; i++){ kind = document.body.childNodes[i]; for (j=0; j<tags.length; j++){ if (kind.tagName == tags[j]) { kind.firstChild.nodeValue = zaehler+". "+kind.firstChild.nodeValue; kind.id="absatz"+zaehler; inhalt[inhalt.length] = kind.firstChild.nodeValue; zaehler++; } } } // Jetzt erstellen wir den div für's Inhaltsverzeichnis // und dekorieren ihn ein bisschen: var inhaltEl = document.createElement("div"); document.body.insertBefore(inhaltEl, document.body.firstChild); inhaltEl.style.padding = "10px"; inhaltEl.style.backgroundColor = "#eeeeee"; inhaltEl.style.width = "400px"; // Schließlich stellen wir dort für jede Überschrift // einen Link hinein: for (i=0; i<inhalt.length; i++) { var punktLink = document.createElement("a"); punktLink.href = "#absatz"+(i+1); var punktTxt = document.createTextNode(inhalt[i]); punktLink.appendChild(punktTxt); inhaltEl.appendChild(punktLink); // hinter jeden Link einen Zeilenumbruch: var punktBr=document.createElement("br"); inhaltEl.appendChild(punktBr); } }
// Neues Fenster öffnen: popup=open("","ausgabeFenster"); // pre-Element für den Baum erzeugen: var pd = popup.document; var baum = pd.createElement("PRE"); pd.body.appendChild(baum); // unterste DOM-Ebene schreiben: for (var i=0; i<document.childNodes.length; i++){ var kind = document.childNodes[i]; var el = pd.createElement("DIV"); if (document.childNodes[i].nodeType==1){ var inh = pd.createTextNode("+ "+kind.tagName); el.appendChild(inh); baum.appendChild(el); holeKinder("",document.childNodes[i]); } } function holeKinder(plusminus, element){ for (var i=0; i<element.childNodes.length; i++){ // Erst einmal den Baum um eine Zeile weitermalen. // Die Reihe von Strichen und Plus-Zeichen, die // links von denen der aktuellen DOM-Ebene stehen, // wurde als Parameter plusminus übergeben. var el = pd.createElement("DIV"); var inh = pd.createTextNode(plusminus+"|"); el.appendChild(inh); baum.appendChild(el); // Dann schreiben wir die Inhalte der TextNodes und // die Tag-Namen der Elemente dieser Ebene: var kind = element.childNodes[i]; var el = pd.createElement("DIV"); if (element.childNodes[i].nodeType==1){ var neuInh = plusminus + "+--+ " + kind.tagName; var inh = pd.createTextNode(neuInh); el.appendChild(inh); baum.appendChild(el); // nächsten Rekursionsschritt starten: if (element.childNodes.length>i+1) holeKinder(plusminus+"| ", kind); else holeKinder(plusminus+" ", kind); } else if (element.childNodes[i].nodeType==3){ var neuInh = plusminus + "+-- " + kind.nodeValue; var inh = pd.createTextNode(neuInh); el.appendChild(inh); baum.appendChild(el); } } }
Auf der CD finden Sie eine Version dieses Skripts, die Sie als Bookmark speichern können. Wenn Sie dieses Bookmark auf einer beliebigen Seite aufrufen, malt es Ihnen den DOM-Baum des Dokuments in ein neues Fenster.
Eine eigentliche Lösung zu dieser Übung gibt es natürlich nicht. Falls Sie jedoch bei Ihren Versuchen auf nichts Interessantes gestoßen sind, hier ein paar Anregungen:
- Sehen Sie sich die Unterschiede zwischen der DOM-Darstellung von Netscape 6 und Internet Explorer 5 an. Beispielsweise werden Sie entdecken, dass bei IE5 der im title angegebene Titel kein Kind des title-Elements ist. Auch die Behandlung von Zeilenumbrüchen zwischen Tags und in TextNodes ist unterschiedlich: Netscape macht (genau wie IE5 auf MacIntosh) aus jedem Zeilenumbruch zwischen einzelnen Elementen im body einen TextNode.
- Nehmen Sie einmal unter die Lupe, was die Browser aus falschem HTML-Quellcode machen, etwa aus:
<b>au<p></b>weia
Sie werden feststellen: Um die Fehler auszugleichen, werden intern Elemente erzeugt, die im Quelltext gar nicht vorkommen.
- Wenn Sie nicht regelmäßig HTML-Spezifikationen lesen, dürften Sie auch beim Betrachten einer table in der Baum-Ansicht überrascht sein: Laut W3C steht innerhalb des table-Elements stets ein tbody-Element. Wurde es vom Autor der Seite weggelassen, fügen es die Browser von alleine ein.