This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
491-0.book Seite XIV Mittwoch, 4. April 2007 9:55 09
e-bol.net
491-0.book Seite XV Mittwoch, 4. April 2007 9:55 09
e-bol.net
Vorwort
Nachdem die vierte Auflage von JavaScript: Das umfassende Handbuch veröffentlicht wurde, wurde das Document Object Model – die grundlegende API für die clientseitige JavaScript™-Programmierung – zu großen Teilen, wenn auch nicht vollständig in Webbrowsern implementiert. Das bedeutete, dass Webentwickler eine stabile, reife Sprache (JavaScript 1.5) und eine gemeinsame API für die Manipulation von Webseiten auf dem Client hatten. Es folgten einige Jahre der Stabilität. Aber die Dinge haben begonnen, wieder interessant zu werden. Entwickler verwenden JavaScript jetzt, um HTTP zu skripten, um XML-Daten zu manipulieren und sogar um dynamische Grafiken in Webbrowsern zu zeichnen. Viele JavaScript-Entwickler haben auch begonnen, längere Programme zu schreiben und ausgefeiltere Programmiertechniken zu verwenden. Diese aktualisierte Auflage wurde vollständig für die neue Welt von Ajax und Web 2.0-Technologien überarbeitet.
Was in dieser Auflage neu ist In Teil I, Der JavaScript-Sprachkern, wurde das Kapitel zu Funktionen (Kapitel 8) erweitert. Ein Schwerpunkt liegt dabei auf eingebetteten Funktionen und Closures. Das Material zur Definition eigener Klassen wurde ebenfalls erweitert und in ein eigenes Kapitel (Kapitel 9) verschoben. Kapitel 10 ist ein weiteres neues Kapitel, das Namensräume behandelt, die grundlegend für das Schreiben von modularem, wiederverwendbarem Code sind. Schließlich zeigt Kapitel 12, wie man JavaScript einsetzt, um tatsächlich Java zu skripten. Es zeigt, wie man einen JavaScript-Interpreter in eine Java 6-Anwendung einbettet und wie man JavaScript verwendet, um Java-Objekte zu erstellen und auf diesen Objekten Methoden aufzurufen. In Teil II, Clientseitiges JavaScript, wurde die Behandlung des alten Document Object Models (Level 0) mit der Behandlung des W3C-Standard-DOMs verschmolzen. Weil das DOM jetzt universell implementiert ist, gibt es keinen Grund für zwei separate Kapitel
| XV
491-0.book Seite XVI Mittwoch, 4. April 2007 9:55 09
e-bol.net zur Manipulation von Dokumenten mehr. Die größte Veränderung in Teil II ist aber die Menge an neuem Material: • Kapitel 19, Cookies und Persistenz auf der Clientseite, hat die Behandlung von Cookies aktualisiert und schließt die Behandlung anderer Techniken für clientseitige Persistenz ein. • Kapitel 20, HTTP skripten, erklärt, wie man unter Verwendung des mächtigen XMLHttpRequest-Objekts geskriptete HTTP-Anfragen macht, die die Technologie für Ajax-artige Webanwendungen sind. • Kapitel 21, JavaScript und XML, zeigt, wie man JavaScript verwendet, um XMLDokumentinhalte zu erzeugen, zu laden, zu parsen, zu transformieren, abzufragen, zu serialisieren und herauszuziehen. Es führt außerdem in die E4X-Erweiterung der Kern-JavaScript-Sprache ein. • Kapitel 22, Skriptgesteuerte Grafiken auf der Clientseite, erklärt die Grafikfähigkeiten von JavaScript. Es behandelt einfache Image-Rollover und Animationen, erklärt aber auch fortgeschrittene geskriptete Grafiken mit dem brandneuen -Tag. Es zeigt auch andere Mittel, um dynamische, geskriptete clientseitige Grafiken mit SVG, VML, dem Flash-Plug-in und dem Java-Plug-in zu erzeugen. • In Kapitel 23, Java-Applets und Flash-Movies skripten, wurde die Behandlung des Java-Plug-ins um eine Behandlung des Flash-Plug-ins erweitert. Es erklärt jetzt, wie man Flash-Filme und Java-Applets skriptet. Teil III, der Referenzteil für die Kern-JavaScript-API, wurde im Vergleich zur vorangehenden Auflage nur wenig geändert, weil diese API stabil geblieben ist. Wenn Sie die vorangegangene Auflage verwendet haben, wird Ihnen dieser Teil des Buchs angenehm vertraut vorkommen. Die größte Änderung am Referenzmaterial ist, dass die Dokumentation der DOM API, die zuvor in einen eigenen Teil ausgelagert war, vollständig in Teil IV, die Referenz zu clientseitigem JavaScript, integriert wurde. Jetzt muss nur noch in einer clientseitigen Referenz nachgeschlagen werden. Es ist nicht mehr notwendig, das Document-Objekt in einem Referenzabschnitt nachzuschlagen und das HTMLDocument-Objekt dann in dem anderen. Referenzmaterial zu den DOM-Interfaces, die in Webbrowsern nie (sonderlich verbreitet) implementiert waren, wurde weggelassen. Das NodeIterator-Interface ist in Webbrowsern einfach nicht verfügbar und verstopft jetzt nicht mehr sinnlos dieses Buch. Die Perspektive wurde außerdem von den schrecklich formalen Interfaces, die von der DOM-Spezifikation definiert werden, zu den JavaScript-Objekten verschoben, die diese Interfaces tatsächlich implementieren. Beispielsweise ist getComputedStyle( ) jetzt als Methode des Window-Objekts dokumentiert, wo man sie auch erwarten würde, nicht mehr als Methode des Interfaces AbstractView. Für clientseitige JavaScript-Programmierer gibt es keinen Grund, sich über AbstractView Gedanken zu machen, deswegen wurde dieses Interface einfach aus der Referenz entfernt. All diese Änderungen führen zu einem einfacheren, leichter zu verwendenden clientseitigen Referenzteil.
XVI
| Vorwort
491-0.book Seite XVII Mittwoch, 4. April 2007 9:55 09
e-bol.net
Wie man dieses Buch verwendet Kapitel 1 bietet eine Einführung in JavaScript. Der Rest des Buchs ist in vier Teile eingeteilt. Teil I, der unmittelbar auf dieses Kapitel folgt, dokumentiert den Sprachkern von JavaScript. Die Kapitel 2 bis 6 behandeln etwas langweiliges, aber erforderliches Material. Diese Kapitel enthalten die grundlegenden Informationen, die man verstehen muss, wenn man eine neue Programmiersprache lernt: • Kapitel 2, Lexikalische Struktur, erklärt die Grundstruktur der Sprache. • Kapitel 3, Datentypen und Werte, dokumentiert die Datentypen, die von JavaScript unterstützt werden. • Kapitel 4, Variablen, behandelt Variablen, Geltungsbereiche von Variablen und verwandte Themen. • Kapitel 5, Ausdrücke und Operatoren, erklärt Ausdrücke in JavaScript und dokumentiert alle Operatoren, die von JavaScript unterstützt werden. Weil JavaScript an Java angelehnt ist, das seinerseits an C und C++ angelehnt ist, können erfahrene C-, C++- oder Java-Programmierer große Teile von diesem Kapitel überspringen. • Kapitel 6, Anweisungen, beschreibt die Syntax und Verwendung aller JavaScriptAnweisungen. Wieder können erfahrene C-, C++- und Java-Programmierer einiges, aber nicht alles, in diesem Kapitel überspringen. Die nächsten sechs Kapitel von Teil I werden interessanter. Sie behandeln immer noch den Kern der Sprache JavaScript, dokumentieren aber Teile der Sprache, mit denen man auch dann noch nicht vertraut ist, wenn man bereits C oder Java kennt. Diese Kapitel müssen Sie sorgfältig studieren, wenn Sie JavaScript wirklich verstehen wollen. • Kapitel 7, Objekte und Arrays, erklärt Objekte und Arrays in JavaScript. • Kapitel 8, Funktionen, zeigt, wie in JavaScript Funktionen definiert, aufgerufen und manipuliert werden. Es schließt außerdem fortgeschrittenes Material zu Closures ein. • Kapitel 9, Klassen, Konstruktoren und Prototypen, behandelt die OO-Programmierung in JavaScript, erklärt, wie man Konstruktordefinitionen für neue Klassen von Objekten definiert und wie die prototypbasierte Vererbung von JavaScript funktioniert. Dieses Kapitel zeigt auch, wie man traditionelle klassenbasierte OO-Idiome in JavaScript simuliert. • Kapitel 10, Module und Namensräume, zeigt, wie JavaScript-Objekte Namensräume definieren, und erklärt Programmierpraktiken, die Ihre Module mit JavaScript-Code vor Namensraumkollisionen schützen können. • Kapitel 11, Mustervergleich mit regulären Ausdrücken, erklärt, wie man in JavaScript reguläre Ausdrücke verwendet, um Mustervergleichs- und Suchen/Ersetzen-Operationen durchzuführen.
Vorwort |
XVII
491-0.book Seite XVIII Mittwoch, 4. April 2007 9:55 09
e-bol.net • Kapitel 12, Java skripten, zeigt, wie man einen JavaScript-Interpreter in eine JavaAnwendung einbettet, und erklärt, wie JavaScript-Programme, die in so einer Anwendung laufen, Java-Objekte skripten können. Dieses Kapitel ist nur für JavaProgrammierer interessant. Teil II erklärt JavaScript in Webbrowsern. Die ersten sechs Kapitel behandeln Kern-Features von clientseitigem JavaScript: • Kapitel 13, JavaScript in Webbrowsern, erklärt die Integration von JavaScript in Webbrowser. Es betrachtet den Webbrowser als eine Programmierumgebung und erklärt die verschiedenen Weisen, wie JavaScript in Webseiten integriert wird, damit es auf der Clientseite ausgeführt wird. • Kapitel 14, Browserfenster skripten, dokumentiert das zentrale Objekt von clientseitigem JavaScript – das Window-Objekt – und erklärt, wie Sie dieses Objekt verwenden können, um Webbrowser-Fenster zu steuern. • Kapitel 15, Dokumente skripten, behandelt das Document-Objekt und erklärt, wie JavaScript den Inhalt skripten kann, der in einem Webbrowser-Fenster angezeigt wird. Dies ist das wichtigste Kapitel in Teil II. • Kapitel 16, Cascading Style Sheets und dynamisches HTML, erklärt, wie JavaScript und CSS-Stylesheets interagieren. Es demonstriert, wie JavaScript den Style, das Erscheinungsbild und die Position der Elemente in einem HTML-Dokument manipulieren kann, um die visuellen Effekte hervorzubringen, die als DHTML bekannt sind. • Kapitel 17, Events und Event-Handling, behandelt JavaScript-Events und -EventHandler, die zentral für alle JavaScript-Programme sind, die mit dem Benutzer interagieren. • Kapitel 18, Formulare und Formularelemente, erklärt, wie JavaScript mit HTMLFormularen und -Formularelementen arbeiten kann. Das ist die logische Erweiterung von Kapitel 15, aber das Thema ist so wesentlich, dass es ein eigenes Kapitel verdient. Auf diese ersten sechs Kapitel von Teil II folgen fünf weitere, die fortgeschrittenere Themen von clientseitigem JavaScript behandeln. • Kapitel 19, Cookies und Persistenz auf der Clientseite, behandelt die clientseitige Persistenz, d.h. die Fähigkeit von Skripten, Daten auf dem Computer des Benutzers zu speichern, damit diese später abgerufen werden können. Dieses Kapitel erklärt, wie man HTTP-Cookies verwendet, um Daten persistent zu machen, und wie man Persistenz mit proprietären Features des Internet Explorer und des Flash-Plug-ins erzielt. • Kapitel 20, HTTP skripten, zeigt, wie JavaScript das HTTP-Protokoll skripten kann, indem es über das XMLHttpRequest-Objekt Anfragen an Webserver schickt und von ihnen Antworten erhält. Diese Fähigkeit ist der zentrale Punkt in der Webanwendungsarchitektur, die als Ajax bekannt ist.
XVIII
| Vorwort
491-0.book Seite XIX Mittwoch, 4. April 2007 9:55 09
e-bol.net • Kapitel 21, JavaScript und XML, demonstriert, wie man JavaScript verwendet, um Inhalte von XML-Dokumenten zu erzeugen, zu laden, zu parsen, abzufragen, zu serialisieren und herauszuziehen. • Kapitel 22, Skriptgesteuerte Grafiken auf der Clientseite, erklärt die Grafikfähigkeiten von JavaScript. Es behandelt einfache Image-Rollover und Animationen, erklärt aber auch fortgeschrittene grafische Techniken, die Scalable Vector Graphics (SVG), die Vector Markup Language (VML), das -Tag, das Flash-Plug-in und das Java-Plug-in verwenden. • Kapitel 23, Java-Applets und Flash-Movies skripten, erklärt, wie Sie JavaScript einsetzen können, um mit Java-Applets und Flash-Filmen zu kommunizieren und diese zu steuern. Es behandelt auch, wie Sie das Gegenteil tun können – also wie Sie JavaScript-Code aus Java-Applets und Flash-Movies aufrufen können. Die Teile III und IV enthalten Referenzmaterial, das Kern-JavaScript bzw. clientseitiges JavaScript behandelt. Diese Teile dokumentieren die wichtigsten Objekte, Methoden und Eigenschaften in alphabetischer Reihenfolge.
Die in diesem Buch verwendeten Konventionen In diesem Buch werden die folgenden Formatierungskonventionen verwendet: Fett Wird gelegentlich verwendet, um auf bestimmte Tasten auf einer Computer-Tastatur oder Teile einer Benutzerschnittstelle wie auf den Zurück-Button oder auf das Optionen-Menü zu verweisen. Kursiv Wird zur Hervorhebung genutzt und um die erste Verwendung eines Begriffs zu kennzeichnen. Kursiv wird ebenfalls für E-Mail-Adressen, Webseites, FTP-Sites, Datei- und Verzeichnisnamen und Newsgroups verwendet. Schließlich wird Kursiv in diesem Buch für die Namen von Java-Klassen verwendet, um sie leichter von JavaScript-Namen unterscheiden zu können. Nichtproportionalschrift
Wird in allen JavaScript-Code- und HTML-Text-Listings verwendet sowie allgemein für alles, das man beim Programmieren wörtlich eingeben würde. Nichtproportionalschrift fett
Wird verwendet, um Kommandozeilentext anzuzeigen, der vom Benutzer eingegeben werden soll. Nichtproportionalschrift kursiv
Wird für die Namen von Funktionsargumenten verwendet und allgemein als Platzhalter eingesetzt, um Elemente zu kennzeichnen, die in Ihren Programmen durch tatsächliche Werte ersetzt werden sollten.
Vorwort
| XIX
491-0.book Seite XX Mittwoch, 4. April 2007 9:55 09
e-bol.net
Verwendung der Codebeispiele Dieses Buch soll Ihnen bei der Arbeit helfen. Den Code, den wir hier zeigen, dürfen Sie generell in Ihren Programmen und Dokumentationen verwenden. Sie brauchen uns nicht um Genehmigung zu bitten, sofern Sie nicht große Teile des Codes reproduzieren. Wenn Sie zum Beispiel ein Programm schreiben, das mehrere Codeabschnitte aus diesem Buch wiederverwendet, brauchen Sie unser Einverständnis nicht. Doch wenn Sie eine CDROM mit Codebeispielen aus O’Reilly-Büchern verkaufen oder verteilen wollen, müssen Sie sehr wohl eine Erlaubnis einholen. Eine Frage mit einem Zitat aus diesem Buch und seinen Codebeispielen erfordert keine Erlaubnis, aber es ist nicht ohne Weiteres gestattet, große Teile unseres Texts oder Codes in eine eigene Produktdokumentation aufzunehmen. Wir freuen uns über eine Quellenangabe, verlangen sie aber nicht unbedingt. Zu einer Quellenangabe gehören normalerweise der Titel, der Autor, der Verlag und die ISBN, zum Beispiel: »David Flanagan: JavaScript – Das umfassende Referenzwerk. O’Reilly: 2007, ISBN 978-3-89721-491-0«. Wenn Sie das Gefühl haben, dass Ihr Einsatz unserer Codebeispiele über die Grenzen des Erlaubten hinausgeht, schreiben Sie uns bitte eine E-Mail an [email protected].
Website und Codebeispiele zu diesem Buch Auf deutschen Website zu diesem Buch finden Sie Errata, Codebeispiele und Zusatzinformationen: http://www.oreilly.de/catalog/jscript5ger Für Kommentare zu diesem Buch senden Sie uns eine E-Mail an: [email protected]
Danksagungen Brendan Eich von der Mozilla Foundation ist der Urheber und Haupterneuerer von JavaScript. Viele andere Webentwickler und ich schulden Brendan ungeheuere Dankbarkeit für die Entwicklung von JavaScript und dafür, dass er bei seinem verrückten Terminkalender immer noch Zeit findet, unsere Fragen zu beantworten, und uns sogar um Feedback bittet. Brendan hat nicht nur meine Fragen geduldig beantwortet, er hat auch die erste und die dritte Auflage dieses Buchs gelesen und sehr hilfreiche Hinweise gegeben.
XX
| Vorwort
491-0.book Seite XXI Mittwoch, 4. April 2007 9:55 09
e-bol.net Dieses Buch hatte das Glück, von erstklassigen Gutachtern gelesen zu werden, deren Kommentare viel dazu beigetragen haben, das Buch besser und genauer zu machen. Aristotle Pagaltzis (http://plasmasturm.org) hat das neue Material zu Funktionen und die in dieser Auflage neuen Kapitel über Klassen und Namensräume geprüft. Er hat einen besonders genauen Blick auf meinen Code geworfen und hat viele hilfreiche Hinweise gegeben. Douglas Crockford (http://www.crockford.com) hat das neue Material zu Funktionen und Klassen gelesen. Norris Boyd, der Schöpfer des Rhino JavaScript-Interpreters, hat das Kapitel zum Einbetten von JavaScript in Java-Anwendungen geprüft. Peter-Paul Koch (http://www.quirksmode.org), Christian Heilmann (http://www.wait-till-i.com) und Ken Cooper haben die Ajax-bezogenen Kapitel dieses Buchs geprüft. Ken war so nett, am Ende einzuspringen und beim neuen Material für die clientseitige Referenz auszuhelfen. Todd Ditchendorf (http://www.ditchnet.org) und Geoff Stearns (http://blog.deconcept. com) haben das Kapitel zu geskripteten clientseitigen Grafiken gelesen. Todd war so nett, für mich einen Bug zu finden und zu isolieren, und Geoff hat mir geholfen, Flash und ActionScript zu verstehen. Schließlich hat Sanders Kleinfeld das vollständige Buch mit bemerkenswerter Aufmerksamkeit gelesen. Seine Vorschläge und Korrekturen haben das Buch klarer und präziser gemacht. Mein aufrichtiger Dank gilt ihnen allen für ihre Sorgfalt. Alle verbleibenden Fehler sind natürlich meine. Auch den Gutachtern für die vierte englische Auflage bin ich dankbar. Waldemar Horwat von Netscape hat das neue Material zu JavaScript 1.5 geprüft. Das neue Material zum W3C DOM wurde von Philippe Le Hegaret vom W3C und von Peter-Paul Koch, Dylan Schiemann und Jeff Yates geprüft. Obwohl er kein Gutachter war, war Joseph Kesselman von IBM Research sehr hilfreich, indem er meine Fragen zum W3C DOM beantwortet hat. Die dritte englische Auflage dieses Buchs wurde von Brendan Eich, Waldemar Horwat und Vidur Apparao von Netscape, Herman Venter von Microsoft und zwei unabhängigen JavaScript-Entwicklern, Jay Hodges und Angelo Sirigos, geprüft. Dan Shafer hat einige Vorarbeiten für die dritte Auflage geleistet. Obwohl sein Material in dieser Auflage nicht verwendet wurde, waren seine Ideen und sein allgemeines Konzept sehr hilfreich. Norris Boyd und Scott Furman von Netscape haben ebenfalls hilfreiche Informationen für dieses Buch geliefert, und Vidur Apparao von Netscape und Scott Issacs von Microsoft haben sich beide die Zeit genommen, mit mir über den aufkommenden Document Object Model-Standard zu sprechen. Schließlich bot mir Dr. Tankred Hirschmann anspruchsvolle Einsichten in die Feinheiten von JavaScript 1.2. Die zweite englische Auflage hat sehr von der Hilfe und den Kommentaren von Nick Thompson und Richard Yaker von Netscape, Dr. Shon Katzenberger, Larry Sullivan und Dave C. Mitchell von Microsoft und Lynn Rollins von R&B Communications profitiert. Die erste Auflage wurde von Neil Berkman von Bay Networks und Andrew Schulman und Terry Allen von O’Reilly geprüft.
Vorwort
| XXI
491-0.book Seite XXII Mittwoch, 4. April 2007 9:55 09
e-bol.net Dieses Buch schöpft seine Stärke auch aus der Vielzahl von Lektoren, die es hatte. Deb Cameron ist die Lektorin der aktuellen Auflage und hat dafür gesorgt, dass das Buch eine gründliche Bearbeitung und eine höchst erforderliche Auffrischung erhalten hat, insbesondere in Bezug auf die Entfernung des veralteten Materials. Paula Ferguson hat die dritte und die vierte englische Auflage lektoriert. Frank Willison hat die zweite englische Auflage lektoriert und Andrew Schulman die erste. Abschließend mein Dank, wie immer aus so vielen Gründen, an Christie. —David Flanagan http://www.davidflanagan.com/ April 2006
XXII |
Vorwort
491-0.book Seite 1 Mittwoch, 4. April 2007 9:55 09
e-bol.net
KAPITEL 1
Einführung in JavaScript
JavaScript ist eine interpretierte Programmiersprache mit objektorientierten Fähigkeiten. Syntaktisch betrachtet hat der Sprachkern von JavaScript Ähnlichkeit mit C, C++ und Java; hier wie dort gibt es Programmierkonstrukte wie die if-Anweisung, die whileSchleife und den Operator &&. Die Ähnlichkeit ist jedoch auf diesen syntaktischen Bereich beschränkt. JavaScript ist eine lose typisierte Sprache, was bedeutet, dass für Variablen kein Typ angegeben werden muss. In JavaScript bilden Objekte Eigenschaftsnamen auf beliebige Werte ab. Deswegen ähneln sie eher Name/Wert-Listen oder assoziativen Arrays (wie in Perl) als Structs (wie in C) oder Objekten (wie in C++ oder Java). Der OOVererbungsmechanismus von JavaScript basiert auf Prototypen wie der der wenig bekannten Programmiersprache Self. Das ist ganz anders als die Vererbung in C++ und Java. Ebenso wie Perl ist JavaScript eine interpretierte Sprache, und in mancherlei Hinsicht wurde sie von Perl inspiriert. Dies ist zum Beispiel bei den regulären Ausdrücken und der Behandlung von Arrays der Fall. Der Sprachkern von JavaScript unterstützt Zahlen, Strings und Boolesche Werte als elementare Datentypen. Er bietet außerdem eingebaute Objekte für Arrays, Datumswerte und reguläre Ausdrücke. JavaScript wird am häufigsten in Webbrowsern verwendet. In diesem Kontext wird der allgemeine Kern mit Objekten erweitert, die es Skripten ermöglichen, mit dem Benutzer in Interaktion zu treten, den Webbrowser zu steuern und das Dokument zu ändern, das im Webbrowserfenster angezeigt wird. Diese eingebettete Version von JavaScript führt Skripten aus, die in HTML-Webseiten eingebaut sind. Sie wird üblicherweise als clientseitiges JavaScript bezeichnet, um zu betonen, dass die Skripten vom Clientrechner ausgeführt werden und nicht vom Webserver. Der JavaScript-Sprachkern und seine eingebauten Datentypen unterliegen internationalen Standards, und die Kompatibilität der verschiedenen Implementierungen ist sehr gut. Teile des clientseitigen JavaScripts sind formell standardisiert, andere Teile sind De-facto-Standards, und andere Teile sind browserspezifische Erweiterungen. Die browserübergreifende Kompatibilität ist für clientseitige JavaScript-Programmierer oft eine wichtige Sache.
| 1
491-0.book Seite 2 Mittwoch, 4. April 2007 9:55 09
e-bol.net Dieses Kapitel bietet einen groben Überblick über JavaScript. Es bietet die Hintergrundinformationen, die Sie benötigen, bevor Sie mit dem Studium der Sprache beginnen können. Als Motivation und Einführung schließt es einige einfache Beispiele mit clientseitigem JavaScript-Code ein.
1.1
Was ist JavaScript?
Über JavaScript kursieren viele irrige Annahmen. Bevor wir in unserer Beschreibung fortfahren, müssen wir mit zwei verbreiteten und hartnäckigen Irrtümern über diese Sprache aufräumen.
1.1.1
JavaScript ist nicht Java
Eines der häufigsten Missverständnisse bezüglich JavaScript ist der Glaube, es sei eine vereinfachte Version von Java, der Programmiersprache von Sun Microsystems. Abgesehen von einer teilweisen syntaktischen Ähnlichkeit und der Tatsache, dass sowohl Java als auch JavaScript in Webbrowsern ausführbare Inhalte bereitstellen können, haben die beiden Sprachen nichts miteinander gemein. Die Ähnlichkeit der Namen ist eine reine Marketingmaßnahme von Netscape und Sun (die Sprache hieß ursprünglich LiveScript, und der Name wurde erst in letzter Minute in JavaScript geändert). Allerdings kann JavaScript tatsächlich Java skripten (siehe Kapitel 12 und 23).
1.1.2
JavaScript ist nicht einfach
Weil JavaScript interpretiert statt kompiliert wird, wird es häufig als Skriptsprache und nicht als eine richtige Programmiersprache bezeichnet. Dabei wird unterstellt, dass Skriptsprachen einfacher sind, Programmiersprachen für Nichtprogrammierer gewissermaßen. Der Umstand, dass JavaScript nicht streng typisiert ist, macht es Fehlern gegenüber weniger empfindlich und für unerfahrene Programmierer leichter verwendbar. Und viele Webdesigner waren in der Lage, JavaScript für begrenzte, kochbuchartige Programmieraufgaben zu verwenden. Hinter dieser Fassade einer scheinbaren Einfachheit ist JavaScript jedoch eine vollständige Programmiersprache, die mindestens so komplex ist wie alle anderen Sprachen. Programmierer, die mit JavaScript schwierigere Aufgaben zu lösen versuchen, stellen häufig fest, dass die Arbeit mit JavaScript frustrierend ist, wenn man die Sprache nicht wirklich gut beherrscht. Da das vorliegende Buch JavaScript umfassend dokumentiert, gibt es Ihnen die Möglichkeit, die Sprache in all ihren Feinheiten zu verstehen. Wenn Sie kochbuchartige JavaScript-Anleitungen kennen, werden Sie vielleicht von der Tiefe und Informationsfülle der kommenden Kapitel überrascht sein.
2 | Kapitel 1: Einführung in JavaScript
491-0.book Seite 3 Mittwoch, 4. April 2007 9:55 09
e-bol.net
1.2
Versionen von JavaScript
Wie alle neuen Technologien hat sich JavaScript sehr schnell entwickelt, als es neu war. Vorangehende Versionen dieses Buchs haben diese Entwicklung Schritt für Schritt dokumentiert und genau erläutert, welche Sprachfeatures in welcher Version der Sprache eingeführt wurden. Mittlerweile hat sich die Sprache allerdings stabilisiert und wurde von der European Computer Manufacturer’s Association (ECMA) standardisiert.1 Implementierungen dieses Standards sind beispielsweise der JavaScript 1.5-Interpreter von Netscape und der Mozilla Foundation und der JScript 5.5-Interpreter von Microsoft. Alle Webbrowser, die neuer sind als Netscape 4.5 oder Internet Explorer 4, unterstützen die neueste Version der Sprache. In der Praxis ist es also unwahrscheinlich, dass Sie auf einen nicht-konformen Interpreter stoßen könnten. Beachten Sie, dass der offizielle Name der Sprache gemäß dem ECMA-262-Standard ECMAScript ist. Aber dieser umständliche Name wird normalerweise nur verwendet, wenn explizit auf den Standard verwiesen wird. Genau genommen verweist der Name »JavaScript« nur auf die Sprachimplementierungen von Netscape und der Mozilla Foundation. In der Praxis nennt allerdings jeder die Sprache JavaScript. Nach einer langen Phase der Stabilität gibt es jetzt einige Vorboten von Änderungen an JavaScript. Der Webbrowser Firefox 1.5 von der Mozilla Foundation schließt einen neuen JavaScript-Interpreter mit der Versionsnummer 1.6 ein, Firefox 2.0 wird sogar mit JavaScript 1.7 ausgeliefert. Diese Versionen schließen einige neue (nicht-standardisierte) Methoden zur Manipulation von Arrays ein, die in Abschnitt 7.6 beschrieben werden, und bieten außerdem Unterstützung für E4X, das im Folgenden erläutert wird. Zusätzlich zur ECMA-262-Spezifikation, die den JavaScript-Sprachkern standardisiert, hat die ECMA einen weiteren JavaScript-bezogenen Standard veröffentlicht. ECMA-357 standardisiert eine Erweiterung für JavaScript, die als E4X oder ECMAScript for XML bekannt ist. Diese Erweiterung fügt der Sprache einen XML-Datentyp sowie Operatoren und Anweisungen zur Manipulation von XML-Werten hinzu. Aktuell wird E4X nur von JavaScript 1.6 und Firefox ab Version 1.5 implementiert. E4X wird in diesem Buch nicht explizit dokumentiert, aber Kapitel 21 schließt eine ausführlichere Einführung in Tutorial-Form ein. Vorschläge für eine vierte Auflage der ECMA-262-Spezifikation zur Standardisierung von JavaScript 2.0 sind seit einigen Jahren auf dem Tisch. Diese Vorschläge beschreiben eine Generalüberholung der Sprache, die strenge Typisierung und eine echte klassenbasierte Vererbung einschließt. Bisher wurden aber nur wenige Fortschritte in Bezug auf eine Standardisierung von JavaScript 2.0 erzielt. Mit Microsofts JScript.NET-Sprache und den Sprachen ActionScript 2.0 und ActionScript 3.0, die vom Adobe (früher Macromedia) 1 Der Standard ist ECMA-262, Version 3 (verfügbar unter http://www.ecma-international.org/publications/files/ ecma-st/ECMA-262.pdf).
1.2 Versionen von JavaScript
| 3
491-0.book Seite 4 Mittwoch, 4. April 2007 9:55 09
e-bol.net Flash-Player verwendet werden, gibt es allerdings schon Implementierungen, die auf den Entwurfsvorschlägen basieren. Aktuell gibt es Anzeichen dafür, dass die Arbeit an JavaScript 2.0 wieder aufgenommen wird, und die Veröffentlichung von JavaScript 1.6 und 1.7 kann als erster Schritt in diese Richtung angesehen werden. Natürlich ist davon auszugehen, dass jede neue Version der Sprache rückwärtskompatibel mit der hier beschriebenen Version ist. Und auch wenn JavaScript 2.0 standardisiert ist, wird es noch einige Jahre dauern, bis es in Webbrowsern weit verbreitet ist.
1.3
Clientseitiges JavaScript
Wenn ein JavaScript-Interpreter in einen Webbrowser eingebettet wird, ist das Ergebnis clientseitiges JavaScript. Dies ist die bei weitem gebräuchlichste Variante von JavaScript: Die meisten Menschen meinen clientseitiges JavaScript, wenn sie von JavaScript sprechen. Dieses Buch dokumentiert clientseitiges JavaScript in Verbindung mit dem Sprachkern von JavaScript, der im clientseitigen JavaScript enthalten ist. Clientseitiges JavaScript kombiniert die Skripting-Fähigkeiten eines JavaScript-Interpreters mit dem von einem Webbrowser definierten Document Object Model (DOM). Dokumente können JavaScript-Skripten enthalten, und diese Skripten können das DOM nutzen, um das Dokument zu modifizieren oder den Webbrowser zu steuern, der das Dokument anzeigt. Man könnte auch sagen, dass clientseitiges JavaScript ansonsten statischen Webinhalten Verhalten hinzufügt. Clientseitiges JavaScript ist das Herz von Webentwicklungstechniken wie DHTML (siehe Kapitel 16) und Architekturen wie Ajax (siehe Kapitel 20). Die Einführung in Kapitel 13 enthält einen Überblick über die vielen Möglichkeiten von clientseitigem JavaScript. Genau wie die ECMA-262-Spezifikation eine Standardversion der JavaScript-Kernsprache definiert, hat das World Wide Web Consortium (W3C) eine DOM-Spezifikation veröffentlicht, die die Features standardisiert, die ein Browser in seinem DOM unterstützen muss. (In den Kapiteln 15, 16 und 17 werden Sie noch viel mehr zu diesem Standard lernen.) Die Kernteile des W3C DOM-Standards werden von den meisten wichtigen Browsern gut unterstützt. Eine wichtige Ausnahme ist Microsofts Internet Explorer, der den W3C-Standard für das Event-Handling nicht unterstützt.
1.3.1
Clientseitige JavaScript-Beispiele
Wenn ein Webbrowser um einen JavaScript-Interpreter erweitert wird, können ausführbare Inhalte als JavaScript-Skripten über das Internet verbreitet werden. Beispiel 1-1 zeigt, wie das aussieht: Es ist ein einfaches JavaScript-Programm oder -Skript, das in eine HTML-Datei eingebettet ist.
4 | Kapitel 1: Einführung in JavaScript
491-0.book Seite 5 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 1-1: Ein einfaches JavaScript-Programm Fakultäten Fakultätstabelle var fact = 1; for(i = 1; i < 10; i++) { fact = fact*i; document.write(i + "! = " + fact + ""); }
Wenn dieses Skript in einen JavaScript-fähigen Browser geladen wird, liefert es die in Abbildung 1-1 gezeigte Ausgabe.
Abbildung 1-1: Eine Webseite, die mit JavaScript generiert wurde
Wie Sie in diesem Beispiel sehen, werden die Tags und dafür verwendet, JavaScript-Code in eine HTML-Datei einzubetten. Über das -Tag werden Sie in Kapitel 13 mehr erfahren. Das wichtigste JavaScript-Merkmal, das dieses Beispiel zeigt, ist die Methode document.write( ).2 Diese Methode wird verwendet, um dynamisch HTML-Text in ein HTML-Dokument auszugeben, während es in den Browser geladen wird. JavaScript kann nicht nur den Inhalt von HTML-Dokumenten, sondern auch das Verhalten dieser Dokumente steuern. Das heißt, ein JavaScript-Programm könnte auf bestimmte Weise reagieren, wenn Sie in ein Eingabefeld einen Wert eingeben oder die Maus über ihm 2 »Methode« ist der objektorientierte Begriff für eine Funktion oder Prozedur; dieser Begriff wird im ganzen Buch verwendet.
1.3 Clientseitiges JavaScript
| 5
491-0.book Seite 6 Mittwoch, 4. April 2007 9:55 09
e-bol.net schweben lassen. Dazu definiert JavaScript für das Dokument Event-Handler, d.h. JavaScript-Code, der dann ausgeführt wird, wenn ein bestimmtes Event eintritt, zum Beispiel wenn der Anwender einen Button anklickt. Beispiel 1-2 zeigt ein einfaches HTML-Fragment, das einen Event-Handler enthält, der ausgeführt wird, wenn auf einen Button geklickt wird. Beispiel 1-2: Ein HTML-Button, für den ein JavaScript-Event-Handler definiert ist Hier klicken
Abbildung 1-2 zeigt das Ergebnis nach dem Anklicken des Buttons.
Abbildung 1-2: Die JavaScript-Reaktion auf ein Event
Das in Beispiel 1-2 vorgeführte Attribut onclick enthält einen String mit JavaScript-Code, der ausgeführt wird, wenn der Benutzer auf den Button klickt. In diesem Fall ruft der Event-Handler onclick die Funktion alert( ) auf. Wie Sie in Abbildung 1-2 sehen, öffnet alert( ) ein Dialogfenster, um die angegebene Nachricht anzuzeigen. Die Beispiele 1-2 und 1-3 demonstrieren nur die einfachsten Features von clientseitigem JavaScript. Die wahre Macht von JavaScript auf der Clientseite besteht darin, dass Skripten Zugriff auf den Inhalt von HTML-Dokumenten haben. Beispiel 1-3 enthält ein vollständiges, nicht-triviales JavaScript-Programm. Das Programm berechnet die monatlichen Zahlungen für eine Immobilienhypothek oder für einen anderen Kredit, bei dem Kreditbetrag, Zinssatz und Zahlungszeitraum festgelegt sind. Es liest die Benutzereingaben aus HTMLFormularfeldern, führt anhand dieser Eingaben die Berechnungen durch und ändert dann das Dokument, um das Ergebnis der Berechnung anzuzeigen.
6 | Kapitel 1: Einführung in JavaScript
491-0.book Seite 7 Mittwoch, 4. April 2007 9:55 09
e-bol.net Abbildung 1-3 zeigt, wie das Programm aussieht, wenn es in einem Webbrowser angezeigt wird. Wie Sie sehen können, besteht es aus einem HTML-Formular und etwas zusätzlichem Text. Allerdings kann die Abbildung nur eine statische Momentaufnahme des Programms wiedergeben. Durch JavaScript-Code wird das Formular dynamisch: Jedes Mal, wenn der Anwender die Kreditsumme, den Zinssatz oder die Anzahl der Raten verändert, berechnet der JavaScript-Code die monatliche Rate, die Summe aller Raten und die Zinsen, die während der gesamten Laufzeit des Kredits gezahlt werden, neu.
Abbildung 1-3: Ein JavaScript-Rechner für eine Kreditrückzahlung
Die erste Hälfte von Beispiel 1-3 ist ein einfaches CSS-Stylesheet und ein HTML-Formular, das in einer HTML-Tabelle formatiert ist. Beachten Sie, dass Formularelemente die Event-Handler onchange oder onclick definieren. Der Webbrowser löst diese EventHandler aus, wenn der Anwender die Eingabe ändert oder den Button Berechnen anklickt, der auf dem Formular angezeigt wird. In beiden Fällen ist der Wert des EventHandler-Attributs ein String mit JavaScript-Code: berechnen( ). Wenn der Event-Handler ausgelöst wird, führt er diesen Code aus, der die Funktion berechnen( )aufruft. Die Funktion berechnen( ) ist in der zweiten Hälfte des Beispiels innerhalb der Tags definiert. Die Funktion liest die Benutzereingaben aus dem Formular, führt die Berechnungen aus, die erforderlich sind, um die monatliche Rate zu ermitteln, und fügt die Ergebnisse dieser Berechnungen in -Tags, denen extra mit id-Attributen ein Name gegeben wurde, in das Dokument ein. Beispiel 1-3 ist ein kurzes, aber gradliniges Beispiel, das es verdient, dass Sie es sich genau ansehen. Sie sollten nicht erwarten, dass Sie jetzt schon den ganzen Code verstehen, aber
1.3 Clientseitiges JavaScript
| 7
491-0.book Seite 8 Mittwoch, 4. April 2007 9:55 09
e-bol.net das HTML, CSS und JavaScript sind jeweils kommentiert, und eine genaue Betrachtung dieses Beispiels sollte Ihnen ein Gefühl für clientseitiges JavaScript vermitteln.3 Beispiel 1-3: Mit JavaScript Kreditraten berechnen JavaScript-Kreditrechner /* Dies ist ein CSS-Stylesheet: Es fügt der Programmausgabe Styles hinzu. */ .ergebnis { font-weight: bold; } /* Für Elemente mit class="ergebnis" */ #zahlung { text-decoration: underline; } /* Für das Element mit der id="zahlung" */
Geben Sie die Kreditinformationen an:
1) Kreditbetrag (in beliebiger Währung):
2) Jährlicher Zinssatz in Prozent:
3) Rückzahlungszeitraum in Jahren:
Zahlungsinformationen:
4) Ihre monatliche Raten:
3 Wenn Ihr Gefühl Ihnen sagt, dass es keine gute Idee ist, HTML-Markup, CSS-Styles und JavaScript-Code auf diese Weise zu mischen, sind Sie nicht allein. Der Trend unter JavaScript-Programmierern und Webdesignern geht dahin, Inhalt, Darstellung und Verhalten in separate Dateien zu packen. Abschnitt 13.1.5 von Kapitel 13 erklärt, wie man das macht.
8 | Kapitel 1: Einführung in JavaScript
491-0.book Seite 9 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 1-3: Mit JavaScript Kreditraten berechnen (Fortsetzung)
€
5) Ingesamt zu zahlende Summe:
€
6) Ihre insgesamt zu zahlenden Zinsen:
€
/* * Das ist die JavaScript-Funktion, die bewirkt, dass das Beispiel funktioniert. Beachten * Sie, dass dieses Skript die Funktion berechnen( ) definiert, die von den Event-Handlern * im Formular aufgerufen wird. Die Funktion liest die Werte aus den -Feldern des * Formulars und verwendet dazu die im vorangehenden HTML-Code definierten Namen. Sie * gibt ihre Ergebnisse in den benannten -Elementen aus. */ function berechnen() { // Hole die Benutzereingabe aus dem Formular, und nimm an, dass alles // korrekt ist. Konvertiere die Zinsen von Prozenten in Dezimalform // und von einem Jahres- in einen Monatssatz sowie den Rückzahlungszeitraum // von Jahren in die Anzahl der Monatsraten. var betrag = document.kreditdaten.betrag.value; var zinssatz = document.kreditdaten.zinssatz.value / 100 / 12; var zahlungen = document.kreditdaten.jahre.value * 12; // Berechne die Höhe der Monatsrate mit esoterischen Matheregeln. var x = Math.pow(1 + zinssatz, zahlungen); var monatsrate = (betrag*x*zinssatz)/(x-1); // Die benannten -Elemente aus dem Formular abrufen. var zahlung = document.getElementById("zahlung"); var gesamt = document.getElementById("gesamt"); var gesamtzinsen = document.getElementById("gesamtzinsen"); // Prüfen, dass das Ergebnis eine endliche Zahl ist. Wenn das der Fall ist, wird // das Ergebnis angezeigt, indem der HTML-Inhalt der -Elemente gesetzt wird. if (isFinite(monatsrate)) { zahlung.innerHTML = monatsrate.toFixed(2); gesamt.innerHTML = (monatsrate * zahlungen).toFixed(2); gesamtzinsen.innerHTML = ((monatsrate*zahlungen)-betrag).toFixed(2); } // Andernfalls war die Benutzereingabe wahrscheinlich ungültig, und es wird nichts // angezeigt. else { zahlung.innerHTML = "";
1.3 Clientseitiges JavaScript
| 9
491-0.book Seite 10 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 1-3: Mit JavaScript Kreditraten berechnen (Fortsetzung) gesamt.innerHTML = "" gesamtzinsen.innerHTML = ""; } }
1.4
JavaScript in anderen Kontexten
JavaScript ist eine Allzweck-Programmiersprache; ihre Verwendung ist nicht auf Webbrowser beschränkt. JavaScript wurde dafür entworfen, in eine Anwendung eingebettet zu werden und sie mit Skriptfähigkeiten auszustatten. Von Anfang an enthielten die Webserver von Netscape einen JavaScript-Interpreter, damit serverseitige Skripten in JavaScript geschrieben werden konnten. Auch Microsoft verwendet den JScript-Interpreter nicht nur im Internet Explorer, sondern auch im IIS-Webserver und im Windows Scripting Host. Adobe nutzt eine von JavaScript abgeleitete Sprache für das Scripting des Flash-Players. Und Sun bündelt seine Java 6.0-Distribution mit einem JavaScript-Interpreter, damit Java-Anwendungen problemlos Scripting-Fähigkeiten hinzugefügt werden können (wie das geht, zeigt Kapitel 12). Sowohl Netscape als auch Microsoft haben ihre JavaScript-Interpreter den Unternehmen und Programmierern zur Verfügung gestellt, die die Interpreter in ihre Anwendungen einbetten möchten. Netscapes Interpreter wurde als Open Source-Produkt veröffentlicht und steht nun über die Organisation Mozilla (http://www.mozilla.org/js/) zur Verfügung. Mozilla bietet zwei verschiedene Versionen des Interpreters für JavaScript 1.5 an. Eine ist in C geschrieben und heißt SpiderMonkey, die andere ist in Java geschrieben und heißt Rhino – eine schmeichelhafte Anspielung auf dieses Buch. Es wird zunehmend mehr Anwendungen geben, die JavaScript als eingebettete Skriptsprache verwenden. Wenn Sie Skripten für solche Anwendungen schreiben, ist der erste Teil dieses Buchs, der den Sprachkern dokumentiert, für Sie von Nutzen. Die Kapitel, die sich speziell auf Webbrowser beziehen, werden für Ihre Skripten wahrscheinlich weniger relevant sein.
1.5
JavaScript erkunden
Der beste Weg, eine neue Programmiersprache wirklich zu erlernen, besteht darin, Programme mit ihr zu schreiben. Ich möchte Sie dazu ermuntern, nicht nur das Buch zu lesen, sondern die Merkmale von JavaScript, die Sie dabei kennenlernen, auch gleich auszuprobieren. Mehrere Verfahren erleichtern das Experimentieren mit JavaScript.
10 | Kapitel 1: Einführung in JavaScript
491-0.book Seite 11 Mittwoch, 4. April 2007 9:55 09
e-bol.net Die nächstliegende Art, JavaScript zu erkunden, besteht darin, einfache Skripten zu schreiben. Eine der angenehmen Eigenschaften von JavaScript ist, dass jeder, der einen Webbrowser und einen einfachen Texteditor besitzt, über eine vollständige Entwicklungsumgebung verfügt. Sie können mit dem Schreiben von JavaScript-Skripten beginnen, ohne vorher spezielle Software kaufen oder herunterladen zu müssen. Beispielsweise könnten Sie Beispiel 1-1 so verändern, dass die Fibonacci-Folge anstelle von Fakultäten angezeigt wird: document.write("Tabelle der Fibonacci-Zahlen"); for (i=0, j=1, k=0, fib =0; i" ausgegeben werden: f1.document.write(""); f1.document.write("document.write('Dies ist das auszugebende Skript')"); f1.document.write("");
Stattdessen kann auch der Schrägstrich in durch einen Backslash maskiert werden: f1.document.write("");
In XHTML werden Skripten in CDATA-Abschnitte eingeschlossen. Das Problem mit den schließenden -Tags tritt dort deswegen nicht auf.
13.2.7 Skripten vor älteren Browsern verbergen Als JavaScript neu war, erkannten einige Browser das -Tag nicht und haben den Inhalt des entsprechenden Elements deswegen (richtigerweise) als Text dargestellt. Der Benutzer, der die Webseite besuchte, sah den JavaScript-Code dann formatiert als einen großen sinnlosen Abschnitt und als Webseiteninhalt dargestellt! Der Workaround für
274 | Kapitel 13: JavaScript in Webbrowsern
491-0.book Seite 275 Mittwoch, 4. April 2007 9:55 09
e-bol.net dieses Problem war ein einfacher Hack, der HTML-Kommentare innerhalb des Skriptelementes verwendet. JavaScript-Programmierer schrieben ihre Skripten üblicherweise wie hier:
clientseitiges JavaScript
Oder etwas kompakter auf diese Weise:
Damit das funktioniert, modifiziert clientseitiges JavaScript die JavaScript-Kernsprache leicht, damit sich die Zeichenfolge Das ist der normale HTML-Inhalt. Aber der IE zeigt ihn wegen der Kommentare darüber und darunter nicht an. Das ist normaler Inhalt, der von allen Browsern angezeigt wird.
Bedingte Kommentare werden auch im JavaScript-Interpreter des IE unterstützt, und für C- und C++-Programmierer werden sie Ähnlichkeit mit der #ifdef/#endif-Funktionalität des C-Präprozessors haben. Im IE beginnt ein bedingter JavaScript-Kommentar mit dem Text /*@cc_on und endet mit dem Text @*/. (Das cc in cc_on steht für bedingte Kompilierung, engl. conditional compilation.) Der folgende bedingte Kommentar schließt Code ein, der nur im IE ausgeführt werden soll: /*@cc_on @if (@_jscript) // Dieser Code befindet sich in einem JS-Kommentar, wird vom IE aber ausgeführt. alert("In IE"); @end @*/
290 | Kapitel 13: JavaScript in Webbrowsern
491-0.book Seite 291 Mittwoch, 4. April 2007 9:55 09
e-bol.net Innerhalb eines bedingten Kommentars begrenzen die Schlüsselwörter @if, @else und @end den Code, der vom JavaScript-Interpreter des IE bedingt ausgeführt werden soll. Meist brauchen Sie nur die oben gezeigte einfache Bedingung: @if (@_jscript). JScript ist Microsofts Name für den eigenen JavaScript-Interpreter, und die Variable @_jscript ist im IE immer true.
/*@cc_on @if (@_jscript) // Code in einem bedingten Kommentar, der auch ein gewöhnlicher // JavaScript-Kommentar ist. Der IE führt ihn aus, andere Browser ignorieren ihn. alert('Sie nutzen den Internet Explorer); @else*/ // Dieser Code befindet sich nicht mehr in einem JavaScript-Kommentar, // aber immer noch im bedingten IE-Kommentar. Das heißt, dass alle Browser außer // dem IE diesen Code ausführen. alert('Sie nutzen nicht den Internet Explorer'); /*@end @*/
Bedingte Kommentare sind sowohl in ihrer HTML- als auch ihrer JavaScript-Form vollkommen standardfremd. Aber gelegentlich können sie nützliche Mittel sein, um Kompatibilität mit dem IE zu erzielen.
13.7 Zugänglichkeit Das Web ist ein wunderbares Werkzeug für die Verbreitung von Informationen, und JavaScript-Programme können den Zugriff auf diese Informationen verbessern. JavaScript-Programmierer müssen allerdings aufpassen: Es passiert schnell, dass man JavaScript-Code schreibt, der Benutzern mit visuellen oder körperlichen Behinderungen unbeabsichtigterweise Informationen verweigert. Blinde Benutzer können eine Form von »Hilfstechnologie« einsetzen, die als Screenreader (auch Bildschirmleseprogramm) bezeichnet wird, um geschriebene Wörter in gesprochene Wörter umzuwandeln. Einige Screenreader berücksichtigen JavaScript, andere funktionieren am besten, wenn JavaScript abgeschaltet ist. Wenn Sie eine Website entwerfen, die zur Anzeige ihrer Informationen JavaScript benötigt, schließen Sie die Nutzer dieser Screenreader aus. (Und Sie haben auch jeden ausgeschlossen, der mit einem Mobilgerät wie einem Handy im Web ist, das keine JavaScript-Unterstützung bietet, und auch alle, die JavaScript in ihren Browsern absichtlich deaktivieren.) Die eigentliche Rolle von JavaScript ist es, die Darstellung der Informationen zu erweitern, und nicht, die Darstellung der Informationen zu übernehmen. Eine Grundregel der JavaScript-Zugäng-
13.7 Zugänglichkeit |
291
clientseitiges JavaScript
Durch eine geschickte Vermischung bedingter Kommentare und gewöhnlicher JavaScript-Kommentare können Sie einen Codeblock so einrichten, dass er im IE läuft, und einen anderen so, dass er in allen anderen Browsern läuft:
491-0.book Seite 292 Mittwoch, 4. April 2007 9:55 09
e-bol.net lichkeit ist es, Ihren Code so zu entwerfen, dass die Webseite, auf der er verwendet wird, immer noch (zumindest in gewisser Weise) funktioniert, wenn der JavaScript-Interpreter abgeschaltet ist. Weitere wichtige Zugänglichkeitsbedenken betreffen Benutzer, die die Tastatur, aber kein Zeigegerät wie eine Maus verwenden können (oder wollen). Wenn Sie JavaScriptCode schreiben, der von mausspezifischen Events abhängig ist, schließen Sie Benutzer aus, die die Maus nicht verwenden. Webbrowser ermöglichen eine Durchquerung und Aktivierung von Webseiten mit der Tastatur, und Ihr JavaScript-Code sollte das auch tun. Aber gleichermaßen sollten Sie auch keinen Code schreiben, der eine Tastatureingabe verlangt, oder Sie schließen Benutzer aus, die keine Tastatur verwenden können, sowie Benutzer vieler Tablet-PC- und Handy-Browser. Wie in Kapitel 17 gezeigt wird, unterstützt JavaScript geräteunabhängige Events wie onfocus und onchange neben geräteabhängigen Events wie onmouseover und onmousedown. Der Zugänglichkeit halber sollten Sie, wenn das möglich ist, die geräteunabhängigen Events vorziehen. Zugängliche Webseiten zu erstellen ist kein triviales Problem, für das es eindeutige Lösungen gibt. Aktuell dauern die Diskussionen an, wie man JavaScript am besten einsetzt, um die Zugänglichkeit zu befördern, anstatt sie zu beeinträchtigen. Eine vollständige Diskussion von JavaScript und der Zugänglichkeit von Webseiten geht über den Horizont dieses Buchs hinaus. Eine Internetsuche liefert Ihnen viele Informationen zu diesem Thema, von denen viele als Empfehlungen autoritativer Quellen verfasst sind. Denken Sie aber daran, dass sich die Praktiken der clientseitigen JavaScript-Programmierung und Hilfstechnologien in der Entwicklung befinden und Zugänglichkeitsrichtlinien damit nicht immer mithalten.
13.8 JavaScript-Sicherheit Die Internet-Sicherheit ist ein weites und komplexes Feld. Dieser Abschnitt konzentriert sich auf Fragen der clientseitigen JavaScript-Sicherheit.
13.8.1 Was JavaScript nicht machen kann Die Einführung von JavaScript-Interpretern in Webbrowser bedeutet, dass das Laden einer Webseite bewirken kann, dass auf Ihrem Rechner beliebiger JavaScript-Code ausgeführt wird. Sichere Webbrowser – und verbreitet verwendete moderne Browser, die relativ sicher zu sein scheinen – schränken Skripten auf verschiedene Weise ein, um bösartigen Code davon abzuhalten, vertrauliche Daten zu lesen, Ihre Daten zu verändern oder Ihre Privatsphäre zu kompromittieren. JavaScripts erste Verteidigungslinie gegen bösartigen Code ist, dass die Sprache bestimmte Funktionalitäten einfach nicht unterstützt. Beispielsweise bietet JavaScript keine Möglichkeit, Dateien oder Verzeichnisse auf dem Clientcomputer zu lesen, zu
292 | Kapitel 13: JavaScript in Webbrowsern
491-0.book Seite 293 Mittwoch, 4. April 2007 9:55 09
e-bol.net schreiben oder zu löschen. Ohne ein File-Objekt und ohne Funktionen für den Dateizugriff kann ein JavaScript-Programm die Daten eines Benutzers nicht löschen oder Viren in das System eines Benutzers einschleusen.
Die folgende Liste enthält Features, die eingeschränkt werden können. Beachten Sie, dass diese Liste nicht vollständig ist. Unterschiedliche Browser haben unterschiedliche Einschränkungen, und viele von diesen Einschränkungen können vom Benutzer konfiguriert werden: • Ein JavaScript-Programm kann neue Browserfenster öffnen, aber um Pop-up-Missbrauch durch Werbung zu verhindern, schränken viele Browser dieses Feature so ein, dass das nur in Reaktion auf ein vom Benutzer initiiertes Event wie einen MausKlick passieren kann. • Ein JavaScript-Programm kann Browserfenster schließen, die es selbst geöffnet hat, aber es darf ohne Benutzerbestätigung keine anderen Fenster schließen. Das verhindert, dass bösartige Skripten self.close( ) aufrufen, um das Browserfenster des Benutzers zu schließen und damit zu bewirken, dass das Programm beendet wird. • Ein JavaScript-Programm kann das Ziel eines Links nicht verschleiern, indem es den Statusleistentext verändert, wenn die Maus über dem Link schwebt. (In der Vergangenheit war es verbreitet, in der Statusleiste zusätzliche Informationen zu einem Link anzuzeigen. Missbrauch durch Phishing-Versuche hat viele Browserhersteller veranlasst, die Funktionalität zu deaktivieren.) • Ein Skript kann kein Fenster öffnen, das zu klein ist (üblicherweise weniger als 100 Pixel auf einer Seite), oder ein Fenster zu stark verkleinern. Gleichermaßen kann ein Skript kein Fenster aus dem Bildschirm schieben oder ein Fenster erzeugen, das größer als der Bildschirm ist. Das hält Skripten davon ab, Fenster zu öffnen, die der Benutzer nicht sehen oder leicht übersehen kann. Ein solches Fenster könnte Skripten enthalten, die weiterlaufen, nachdem der Benutzer denkt, dass sie beendet wurden. Außerdem kann ein Skript kein Browserfenster ohne Titelleiste oder Statusleiste erzeugen, weil ein solches Fenster ein Betriebssystemfenster vortäuschen und den Benutzer so austricksen könnte, dass er beispielsweise ein geheimes Passwort eingibt. • Die value-Eigenschaft von HTML-FileUpload-Elementen kann nicht gesetzt werden. Könnte diese Eigenschaft gesetzt werden, könnte ein Skript einen gewünschten Dateinamen einsetzen und das Formular veranlassen, den Inhalt einer beliebigen angegebenen Datei (wie einer Passwortdatei) auf den Server hochzuladen.
13.8 JavaScript-Sicherheit |
293
clientseitiges JavaScript
Die zweite Verteidigungslinie ist, dass JavaScript bestimmten Features, die es unterstützt, Einschränkungen auferlegt. Beispielsweise kann clientseitiges JavaScript das HTTP-Protokoll skripten, um Daten mit einem Webserver auszutauschen, und kann sogar Daten von FTP-Servern oder anderen Servern herunterladen. Aber JavaScript bietet keine allgemeinen Netzwerk-Grundfunktionen und kann kein Socket für einen anderen Host öffnen oder eine Verbindung von einem anderen Host annehmen.
491-0.book Seite 294 Mittwoch, 4. April 2007 9:55 09
e-bol.net • Ein Skript kann den Inhalt von Dokumenten nicht lesen, die von anderen Servern geladen wurden als das Dokument, das das Skript enthält. Gleichermaßen kann ein Skript keine Event-Listener auf Dokumenten von anderen Servern registrieren. Das verhindert, dass Skripten Benutzereingaben (wie die Tastendrücke, die ein Passwort bilden) für andere Seiten ausspioniert. Diese Einschränkung ist unter dem Namen Same Origin Policy bekannt und wird im folgenden Abschnitt ausführlicher beschrieben.
13.8.2 Die Same Origin Policy Die Same Origin Policy (Gleiche-Herkunft-Richtlinie) ist eine durchschlagende Sicherheitsbeschränkung für die Inhalte, mit denen JavaScript-Code interagieren kann. Üblicherweise kommt sie zum Tragen, wenn eine Webseite mehrere Frames verwendet, -Tags enthält oder andere Browserfenster öffnet. Dann steuert die Same Origin Policy die Interaktion von JavaScript-Code in einem Fenster oder Frame mit anderen Fenstern oder Frames. Sie bewirkt, dass ein Skript nur Eigenschaften von Fenstern und Dokumenten lesen kann, die die gleiche Herkunft wie das Dokument haben, das das Skript enthält (wie Sie JavaScript mit mehreren Fenstern oder Frames verwenden, erfahren Sie in Abschnitt 14.8). Die Same Origin Policy spielt auch eine Rolle, wenn HTTP mit dem XMLHttpRequestObjekt geskriptet wird. Dieses Objekt ermöglicht es clientseitigem JavaScript-Code, beliebige HTTP-Anfragen durchzuführen, allerdings nur an den Webserver, von dem das Dokument geladen wurde, das das Skript enthält (mehr Informationen zum XMLHttpRequest-Objekt finden Sie in Kapitel 20). Die Herkunft eines Dokuments wird über das Protokoll, den Host und den Port der URL definiert, von der das Dokument geladen wurde. Dokumente, die von unterschiedlichen Webservern geladen werden, sind unterschiedlicher Herkunft. Dokumente, die über unterschiedliche Ports auf dem gleichen Host geladen wurden, sind unterschiedlicher Herkunft. Und ein Dokument, das mit dem http:-Protokoll geladen wurde, hat eine andere Herkunft als ein Dokument, das mit dem https:-Protokoll geladen wurde, selbst wenn beide Dokumente vom gleichen Webserver geladen wurden. Es ist wichtig, dass man versteht, dass die Herkunft des Skripts selbst für die Same Origin Policy irrelevant ist: Es geht nur um die Herkunft des Dokuments, in das das Skript eingebettet ist. Nehmen wir beispielsweise an, dass ein Skript von Domain A (über das srcAttribut des -Tag) in eine Webseite von Domain B eingeschlossen ist. Das Skript hat vollständigen Zugriff auf den Inhalt des Dokuments, das es enthält. Wenn das Skript ein neues Fenster öffnet und ein zweites Dokument von Domain B lädt, hat das Skript auch vollständigen Zugriff auf den Inhalt des zweiten Dokuments. Aber wenn das Skript ein drittes Fenster öffnet und darin ein Dokument von Domain C (oder sogar von Domain A) lädt, tritt die Same Origin Policy auf den Plan und verhindert, dass das Skript auf dieses Dokument zugreift.
294 | Kapitel 13: JavaScript in Webbrowsern
491-0.book Seite 295 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Die Same Origin Policy ist erforderlich, um zu verhindern, dass Skripten persönliche Informationen stehlen. Bestände diese Einschränkung nicht, könnte ein bösartiges Skript (das durch eine Firewall hindurch in einen Browser in einem sicheren Unternehmensnetzwerk geladen wird) in der Hoffnung ein leeres Fenster öffnen, dass der Benutzer dieses Fenster verwendet, um Dateien aus dem Unternehmensnetzwerk zu lesen. Das bösartige Skript würde dann den Inhalt dieses Fensters lesen und an seinen eigenen Server zurücksenden. Die Same Origin Policy verhindert derartiges Verhalten. Unter bestimmten Umständen ist die Same Origin Policy zu streng. Insbesondere stellt sie größere Websites vor Probleme, die mehrere Server nutzen. Beispielsweise könnte ein Skript von home.example.com legitimerweise Eigenschaften eines von developer. example.com geladenen Dokuments lesen wollen oder könnten Skripten von orders. example.com Eigenschaften von einem Dokument aus catalog.example.com lesen müssen. Um große Websites dieser Art zu unterstützen, können Sie die domain-Eigenschaft des Document-Objekts einsetzen. Per Default enthält die Eigenschaft domain den Hostnamen des Servers, von dem das Dokument geladen wurde. Sie können diese Eigenschaft setzen, allerdings nur auf einen String, der selbst ein gültiges Domain-Suffix ist. Wenn domain ursprünglich der String »home.example.com« ist, können Sie es also auf den String »example.com« setzen, aber nicht auf »home.example« oder »ample.com«. Außerdem muss der domain-Wert mindestens einen Punkt enthalten. Sie können ihn nicht auf »com« oder eine andere Toplevel-Domain setzen. Wenn zwei Fenster (oder Frames) Skripten enthalten, deren domain auf den gleichen Wert gesetzt ist, wird die Same Origin Policy für diese beiden Fenster gelockert: Die beiden Fenster können dann miteinander interagieren. Beispielsweise können kooperierende Skripten, die von orders.example.com und catalog.example.com geladen wurden, ihre document.domain-Eigenschaften auf »example.com« setzen und es so scheinen lassen, dass sie die gleiche Herkunft haben, und es damit den beiden Dokumenten ermöglichen, die Eigenschaften des jeweils anderen zu lesen.
13.8.3 Plug-ins und ActiveX-Steuerelemente skripten Obwohl der JavaScript-Kernsprache und dem grundlegenden clientseitigen Objektsystem die Dateisystem- und Netzwerkfunktionalitäten fehlen, die bösartiger Code in der
13.8 JavaScript-Sicherheit |
295
clientseitiges JavaScript
Die Same Origin Policy gilt eigentlich nicht für alle Eigenschaften aller Objekte in einem Fenster von einer anderen Domain. Aber sie gilt für viele von ihnen und insbesondere für fast alle Eigenschaften des Document-Objekts (siehe Kapitel 15). Außerdem implementieren die einzelnen Browserhersteller diese Sicherheitsrichtlinie etwas unterschiedlich. (Beispielsweise erlaubt Firefox 1.0 einem Skript auf Fenstern mit anderer Herkunft history.back( ) aufzurufen, der IE 6 aber nicht.) Fenster, die Dokumente von einem anderen Server enthalten, sollten für Ihre Skripten also in jeder Hinsicht tabu sein. Wenn Ihr Skript ein Fenster geöffnet hat, kann Ihr Skript es wieder schließen, aber es kann auf keine Weise in es »hineinblicken«.
491-0.book Seite 296 Mittwoch, 4. April 2007 9:55 09
e-bol.net Regel benötigt, ist die Situation nicht so einfach, wie sie erscheint. In vielen Webbrowsern wird JavaScript als »Script-Engine« für andere Software-Komponenten wie die ActiveX-Steuerelemente des Internet Explorers und die Plug-ins anderer Browser eingesetzt. Das eröffnet clientseitigen Skripten wichtige und mächtige Features. In Kapitel 20 werden Sie Beispiele sehen, in denen ein ActiveX-Steuerelement verwendet wird, um HTTP zu skripten. Ähnliche Beispiele sehen Sie in den Kapiteln 19 und 22, in denen die Javaund Flash-Plug-ins verwendet werden, um Daten persistent zu machen und fortgeschrittene clientseitige Grafiken zu erstellen. Die Möglichkeit, ActiveX-Steuerelemente und Plug-ins zu skripten, hat Auswirkungen auf die Sicherheit. Beispielsweise haben Java-Applets Zugriff auf Lowlevel-Netzwerkfunktionalitäten. Die Java-Sicherheits-»Sandbox« verhindert, dass Applets mit einem anderen Server als dem Server kommunizieren, von dem sie geladen wurden. Das öffnet also keine Sicherheitslücke. Es zeigt aber ein grundlegendes Problem: Wenn Plug-ins geskriptet werden können, müssen Sie nicht nur der Sicherheitsarchitektur des Webbrowsers, sondern auch der Sicherheitsarchitektur des Plug-ins vertrauen. In der Praxis scheint es, als hätten die Java- und Flash-Plug-ins eine robuste Sicherheit, und sie scheinen in clientseitiges JavaScript keine Sicherheitsprobleme einzuführen. ActiveX-Scripting hat allerdings eine kontroversere Vergangenheit. Der IE-Browser hat Zugriff auf eine Vielzahl skriptbarer ActiveX-Steuerelemente, die Teil des Windows-Betriebssystems sind, und in der Vergangenheit hatten einige dieser skriptbaren Steuerelemente ausnutzbare Sicherheitslücken. Aktuell scheint es jedoch so, als wären diese Probleme gelöst worden.
13.8.4 Cross Site Scripting Cross Site Scripting oder XSS ist ein Begriff für eine Kategorie von Sicherheitsproblemen, bei denen ein Angreifer HTML-Tags oder Skripten in eine Ziel-Website einschleust. Der Schutz vor XSS-Angriffen ist normalerweise Aufgabe der serverseitigen Entwickler. Allerdings müssen sich clientseitige JavaScript-Programmierer des Problems Cross Site Scripting bewusst sein und ihren Code davor schützen. Eine Webseite ist für Cross Site Scripting empfänglich, wenn sie dynamisch Dokumentinhalte erzeugt und diese Inhalte auf Daten basieren, die von Benutzern eingegeben wurden und verwendet werden, ohne dass sie zuvor »gesäubert« wurden, indem alle eventuell darin enthaltenen HTML-Tags entfernt werden. Betrachten Sie als Beispiel die folgende Webseite, die JavaScript einsetzt, um den Benutzer mit seinem Namen zu begrüßen: var name = decodeURIComponent(window.location.search.substring(6)) || ""; document.write("Hallo " + name);
296 | Kapitel 13: JavaScript in Webbrowsern
491-0.book Seite 297 Mittwoch, 4. April 2007 9:55 09
e-bol.net Dieses zweizeilige Skript verwendet window.location.search, um einen Teil der eigenen URL zu erhalten, der mit ? beginnt. Dann nutzt es document.write( ), um dem Dokument dynamisch generierten Inhalt hinzuzufügen. Die Seite soll mit einer URL wie dieser aufgerufen werden: http://www.example.com/greet.html?name=David
Mit dieser URL generiert das Skript ein weiteres Skript (%3C und %3E sind die Codes für die spitzen Klammern)! In diesem Fall zeigt das eingeschleuste Skript nur ein Dialogfenster an. Das ist relativ unkritisch. Aber sehen Sie sich folgenden Fall an: http://siteA/greet.html?name=%3Cscript src=siteB/evil.js%3E%3C/script%3E
Cross Site Scripting-Angriffe werden so genannt, weil mehrere Sites beteiligt sind. Die Site B (oder auch Site C) enthält einen besonders aufgebauten Link (wie den oben) auf Site A, der in Site A ein Skript von Site B einschleust. Das Skript evil.js befindet sich auf der bösartigen Site B, ist jetzt aber in Site A eingebettet und kann mit dem Inhalt von Site A absolut alles machen, was es machen will. Es könnte die Seite verunstalten oder bewirken, dass sie nicht mehr funktioniert (indem beispielsweise einer der Denial-of-ServiceAngriffe gestartet wird, die im nächsten Abschnitt beschrieben werden). Das wäre schlecht für die Kundenbeziehungen von Site A. Gefährlicher ist, dass ein bösartiges Skript Cookies lesen kann, die von Site A geschrieben wurden (die vielleicht Kontonummern und andere persönliche zuschreibbare Informationen enthalten), und diese Daten an Site B zurücksenden kann. Das eingeschleuste Skript kann sogar die Tastenbetätigungen des Benutzers aufzeichnen und diese Daten an Site B zurücksenden. Das Mittel zur Verhinderung von XSS-Angriffen ist in der Regel die Entfernung von HTML-Tags aus nicht vertrauenswürdigen Daten, bevor diese verwendet werden, um dynamische Dokumentinhalte zu erzeugen. Die zuvor gezeigte Datei greet.html können Sie reparieren, indem Sie die folgende Codezeile hinzufügen, um die spitzen Klammern zu entfernen, die das -Tag umgeben. name = name.replace(//g, ">");
Cross Site Scripting ermöglicht eine schädliche Schwachstelle, deren Wurzeln tief in die Architektur des Webs reichen. Es lohnt sich, diese Schwachstelle gründlich zu verstehen. Eine weitergehende Erörterung würde über den Horizont dieses Buchs hinausgehen. Es gibt viele Online-Quellen, die Ihnen helfen, sich vor Cross Site Scripting zu schützen. Eine wichtige Primärquelle ist das CERT Advisory zu diesem Problem: http://www.cert. org/advisories/CA-2000-02.html.
13.8 JavaScript-Sicherheit |
297
clientseitiges JavaScript
Wenn sie auf diese Weise verwendet wird, zeigt sie den Text »Hallo David« an. Aber überlegen Sie, wenn sie mit dieser URL aufgerufen wurde:
491-0.book Seite 298 Mittwoch, 4. April 2007 9:55 09
e-bol.net
13.8.5 Denial-of-Service-Angriffe Die Same Origin Policy und andere hier beschriebene Sicherheitsbeschränkungen leisten gute Arbeit, um zu verhindern, dass bösartiger Code versucht, Ihre Daten zu beschädigen oder Ihre Privatssphäre zu verletzen. Allerdings schützen Sie sie nicht vor Denial-of-Service-Angriffen mit brutaler Gewalt. Wenn Sie bei aktiviertem JavaScript eine bösartige Webseite besuchen, kann diese Website Ihren Browser mit einer Endlosschleife mit alert( )-Dialogfenstern lahmlegen und Sie beispielsweise zwingen, den Unix-Befehl kill oder den Windows Task Manager einzusetzen, um Ihren Browser zu schließen. Eine bösartige Website kann auch versuchen, Ihre CPU mit einer Endlosschleife oder sinnlosen Berechnungen lahmzulegen. Einige Browser (wie Firefox) entdecken lange laufende Skripten und geben Benutzern eine Möglichkeit, diese abzubrechen. Das verhindert versehentliche Endlosschleifen, aber bösartiger Code kann Techniken wie den Befehl window.setInterval( ) einsetzen, um zu verhindern, dass er heruntergefahren wird. Ein ähnlicher Angriff legt Ihr System lahm, indem er Massen an Speicherplatz reserviert. Es gibt kein Patentrezept dafür, wie Webbrowser derartige ungeschickte Angriffe verhindern können. In der Praxis ist das im Web aber kein verbreitetes Problem, weil niemand zu einer Site zurückkehrt, die derartigen Skriptmissbrauch treibt!
13.9 Andere webbezogene JavaScript-Einbettungen Neben clientseitigem JavaScript besitzt die Sprache JavaScript weitere webbezogene Einbettungen. Diese weiteren Einbettungen werden in diesem Buch nicht behandelt. Aber Sie sollten sie kennen, damit Sie sie nicht mit clientseitigem JavaScript verwechseln: Benutzer-Scripting Benutzer-Scripting ist eine Neuerung, bei der benutzerdefinierte Skripten auf HTMLDokumente angewendet werden, bevor sie im Webbrowser dargestellt werden. Anstatt allein vom Seitenautor kontrolliert zu werden, können Webseiten jetzt auch vom Besucher der Seite gesteuert werden. Das bekannteste Beispiel für Benutzer-Scripting wird durch die Greasemonkey-Erweiterung für den Firefox-Webbrowser (http:// greasemonkey.mozdev.org) ermöglicht. Die Benutzer-Skripten zur Verfügung gestellte Programmierumgebung ähnelt der Programmierumgebung von clientseitigem JavaScript, ist aber nicht mit ihr identisch. Dieses Buch wird Ihnen nicht zeigen, wie Sie Greasemonkey-Benutzer-Skripten schreiben, aber das Lernen von clientseitiger JavaScript-Programmierung kann als Voraussetzung für das Lernen von Benutzer-Scripting betrachtet werden. SVG SVG (Scalable Vector Graphics) ist ein XML-basiertes Grafikformat, das die Einbettung von JavaScript-Skripten ermöglicht. Clientseitiges JavaScript kann das HTMLDokument skripten, in das es eingebettet ist, und der JavaScript-Code, der in eine
298 | Kapitel 13: JavaScript in Webbrowsern
491-0.book Seite 299 Mittwoch, 4. April 2007 9:55 09
e-bol.net SVG-Datei eingebettet ist, kann die XML-Elemente dieses Dokuments skripten. Das Material der Kapitel 15 und 17 ist auf SVG-Scripting übertragbar, reicht aber nicht aus: Das DOM für SVG unterscheidet sich grundlegend vom HTML DOM.
XUL XUL ist eine XML-basierte Grammatik für die Beschreibung von Benutzerschnittstellen. Das GUI des Firefox-Webbrowsers wird über XUL-Dokumente definiert. Wie SVG gestattet die XUL-Grammatik die Verwendung von JavaScript. Wie bei SVG ist das Material in den Kapiteln 15 und 17 für die XUL-Programmierung relevant. Allerdings hat der JavaScript-Code in einem XUL-Dokument Zugriff auf andere Objekte und APIs und ist außerdem einem anderen Sicherheitsmodell unterworfen als clientseitiger JavaScript-Code. Mehr über XUL erfahren Sie unter http://www.mozilla.org/projects/xul und http://www.xulplanet.com. ActionScript ActionScript ist eine JavaScript-artige Sprache (die von der gleichen ECMAScript-Spezifikation abgeleitet ist, aber in eine objektorientierte Richtung entwickelt wurde), die in Flash-Filmen verwendet wird. Der größte Teil des JavaScript-Materials in Teil I dieses Buchs ist für die ActionScript-Programmierung relevant. Flash ist nicht XML- oder HTML-basiert, und die von Flash veröffentlichten APIs sind nicht mit denen verwandt, die in diesem Buch behandelt werden. Dieses Buch enthält in den Kapiteln 19, 22 und 23 Beispiele dazu, wie clientseitiges JavaScript Flash-Movies skripten kann. Diese Skripten werden notwendigerweise einige Fragmente von ActionScript-Code enthalten, aber der eigentliche Fokus liegt darauf, wie man gewöhnliches clientseitiges JavaScript verwendet, um mit diesem Code zu interagieren.
13.9 Andere webbezogene JavaScript-Einbettungen |
299
clientseitiges JavaScript
Die SVG-Spezifikation finden Sie unter http://www.w3.org/TR/SVG. Appendix B dieser Spezifikation definiert das SVG DOM. Kapitel 22 nutzt clientseitiges JavaScript, das in ein HTML-Dokument eingebettet ist, um ein SVG-Dokument zu erzeugen, das in ein HTML-Dokument eingebettet ist. Da sich der JavaScript-Code nicht im SVG-Dokument befindet, ist das eher ein Beispiel für gewöhnliches clientseitiges JavaScript statt ein Beispiel für die SVG-Einbettung von JavaScript.
491-0.book Seite 300 Mittwoch, 4. April 2007 9:55 09
e-bol.net
KAPITEL 14
Browserfenster skripten
In Kapitel 13 habe ich das Window-Objekt und die zentrale Rolle beschrieben, die es in clientseitigem JavaScript spielt: Es ist das globale Objekt für die clientseitige JavaScriptProgrammierung. In diesem Kapitel untersuchen wir die Eigenschaften und Methoden des Window-Objekts, die es Ihnen ermöglichen, den Browser und seine Fenster und Frames zu steuern. Sie werden hier lernen, wie Sie Folgendes tun: • JavaScript-Code registrieren, damit er später entweder einmal oder öfter ausgeführt wird • Die URL des Dokuments abrufen, das in einem Fenster angezeigt wird, und die Abfrageargumente aus dieser URL herausziehen • Den Browser dazu bringen, ein neues Dokument zu laden und anzuzeigen • Dem Browser sagen, dass er im Verlauf vor- oder zurückgehen und andere Browserfunktionen wie das Drucken aufrufen soll • Neue Browserfenster öffnen, manipulieren und schließen • Einfache Dialogfenster anzeigen • Ermitteln, in welchem Browser Ihr JavaScript-Code ausgeführt wird, und andere Informationen zur clientseitigen Umgebung erhalten • In der Statusleiste eines Browserfensters beliebigen Text anzeigen • Unbehandelte JavaScript-Fehler behandeln, die in einem Fenster auftreten • JavaScript-Code schreiben, der mit mehreren Fenstern oder Frames interagiert Ihnen wird aufgefallen sein, dass es in diesem Kapitel nur um die Manipulation von Browserfenstern geht und nichts zum Inhalt gesagt wird, der in diesen Fenstern angezeigt wird. Als JavaScript neu war, konnte der Dokumentinhalt nur auf sehr eingeschränkte Weise geskriptet werden, während die in diesem Kapitel beschriebenen Scripting-Techniken für Fenster aufregend und frisch waren. Heutzutage, mit vollständig skriptbaren
300 |
491-0.book Seite 301 Mittwoch, 4. April 2007 9:55 09
e-bol.net Dokumenten (siehe Kapitel 15), ist das Scripting des Browsers nicht mehr so topaktuell. Außerdem werden einige der in diesem Kapitel gezeigten Techniken durch Sicherheitsbeschränkungen behindert und funktionieren nicht mehr so gut, wie sie einmal funktioniert haben. Andere Techniken funktionieren noch, sind bei Webdesignern aber nicht mehr so beliebt und werden nicht mehr häufig verwendet.
14.1 Timer Ein wichtiges Feature jeder Programmierumgebung ist die Fähigkeit, Code zu terminieren, dass er zu einem späteren Zeitpunkt ausgeführt wird. Die JavaScript-Kernsprache bietet eine solche Funktionalität nicht, aber clientseitiges JavaScript bietet es in der Form der globalen Funktionen setTimeout( ), clearTimeout( ), setInterval( ) und clearInterval( ). Eigentlich haben diese Funktionen nichts mit dem Window-Objekt zu tun, aber sie werden in diesem Kapitel dokumentiert, weil das Window-Objekt das globale Objekt von clientseitigem JavaScript ist und diese globalen Methoden deswegen Methoden dieses Objekts sind. Die setTimeout( )-Methode des Window-Objekts terminiert eine Funktion so, dass sie ausgeführt wird, nachdem eine bestimmte Anzahl von Sekunden verstrichen ist. setTimeout( ) liefert einen opaken Wert zurück, der an die Funktion clearTimeout( ) übergeben werden kann, um die Ausführung der terminierten Funktion abzubrechen. setInterval( ) ist wie setTimeout( ), bewirkt aber, dass die angegebene Funktion mehr-
fach im Abstand der angegebenen Anzahl von Millisekunden aufgerufen wird. Wie setTimeout( ) liefert setInterval( ) einen opaken Wert zurück, der an clearInterval( )
übergeben werden kann, um weitere Aufrufe der terminierten Funktion abzubrechen. Obwohl empfohlen wird, setTimeout( ) und setInterval( ) so aufzurufen, dass eine Funktion als erstes Argument übergeben wird, ist es auch erlaubt, stattdessen einen String mit JavaScript-Code zu übergeben. Wenn Sie das tun, wird der String (einmal oder mehrfach) aufgerufen, nachdem die angegebene Zeit verstrichen ist. In älteren Browsern wie dem IE 4 werden keine Funktionen unterstützt. In ihnen müssen Sie diese Methode mit einem String als erstem Argument aufrufen. setTimeout( ) und setInterval( ) sind in einer Reihe von Situationen nützlich. Wenn Sie einen Tooltip anzeigen wollen, wenn der Benutzer die Maus länger als eine halbe Sekunde über einem Dokumentelement schweben lässt, können Sie setTimeout( ) ver-
14.1 Timer |
301
clientseitiges JavaScript
Obwohl dieses Kapitel heute weniger relevant ist, ist es nicht vollkommen irrelevant. Deswegen rate ich Ihnen nicht, es zu überspringen. Das Kapitel ist so aufgebaut, dass (der größte Teil) des wichtigsten Materials am Anfang kommt. Darauf folgen weniger wichtige und weniger häufig verwendete Techniken. Einen wichtigeren, aber komplizierteren Abschnitt dazu, wie man JavaScript verwendet, um mit mehreren Fenstern und Frames zu interagieren, spare ich mir bis zum Ende des Kapitels auf, und das Kapitel schließt mit einem nützlichen Beispiel.
491-0.book Seite 302 Mittwoch, 4. April 2007 9:55 09
e-bol.net wenden, um den Code zur Anzeige des Tooltips zu terminieren. Wenn sich die Maus wegbewegt, bevor der Code ausgelöst wird, können Sie clearTimeout( ) verwenden, um den terminierten Code abzubrechen. setTimeout( ) wird später in Beispiel 14-7 vorgeführt. Wenn Sie irgendwelche Animationen durchführen, verwenden Sie üblicherweise setInterval( ), um den Code zu terminieren, der die Animation durchführt. Anwendungen davon werden Sie in den Beispielen 14-4 und 14-6 sehen. Ein nützlicher Trick mit setTimeout( ) ist die Registrierung einer Funktion, die nach einer Verzögerung von 0 Millisekunden aufgerufen wird. Der Code wird nicht sofort aufgerufen, sondern »so bald wie möglich«. In der Praxis heißt das, dass setTimeout( ) dem Browser sagt, dass er die Funktion aufrufen soll, wenn die Ausführung der Event-Handler für die aktuell ausstehenden Events und die Aktualisierung des aktuellen Zustands des Dokuments abgeschlossen ist. Event-Handler (siehe Kapitel 17), die Dokumentinhalt abfragen oder verändern (siehe Kapitel 15), müssen gelegentlich zu diesem Trick greifen, um die Ausführung Ihres Codes hinauszuzögern, bis sich das Dokument wieder in einem stabilen Zustand befindet. Referenzinformationen zu diesen Timer-Funktionen des Window-Objekts finden Sie in Teil IV.
14.2 Die Location- und History-Objekte Dieser Abschnitt betrachtet die Location- und History-Objekte eines Fensters. Diese Objekte bieten Zugriff auf die URL des aktuell angezeigten Objekts und ermöglichen es Ihnen, neue Dokumente zu laden oder den Browser dazu zu bringen, zurück (oder vor) zu einem zuvor betrachteten Dokument zu gehen.
14.2.1 URLs parsen Die location-Eigenschaft eines Fensters (oder eines Frames) ist eine Referenz auf ein Location-Objekt. Es repräsentiert die URL des Dokuments, das aktuell in diesem Fenster angezeigt wird. Die href-Eigenschaft des Location-Objekts ist ein String, der den vollständigen Text der URL enthält. Die toString( )-Methode des Location-Objekts liefert den Wert der href-Eigenschaft zurück. Statt location.href können Sie also auch location verwenden. Andere Eigenschaften dieses Objekts – wie protocol, host, pathname und search – geben die verschiedenen einzelnen Bestandteile der URL an (vollständige Informationen finden Sie beim Location-Objekt in Teil IV). Die search-Eigenschaft des Location-Objekts ist interessant. Sie enthält einen eventuellen Teil einer URL, der auf ein Fragezeichen folgt (und dieses einschließt). Häufig ist das eine Art Abfragestring. Im Allgemeinen ist die Fragezeichensyntax in einer URL eine Technik, über die in eine URL Argumente eingebettet werden können. Während diese Argumente
302 | Kapitel 14: Browserfenster skripten
491-0.book Seite 303 Mittwoch, 4. April 2007 9:55 09
e-bol.net in der Regel für Skripten gedacht sind, die auf einem Server laufen, gibt es keinen Grund dafür, warum sie nicht auch in JavaScript-gesteuerten Webseiten verwendet werden sollen. Beispiel 14-1 zeigt die Definition einer allgemeinen getArgs( )-Funktion, die verwendet werden kann, um Argumente aus der search-Eigenschaft einer URL hinauszuziehen.
/* * * * * * *
clientseitiges JavaScript
Beispiel 14-1: Argumente aus einer URL herausziehen Diese Funktion parst durch Ampersands getrennte Name=Wert-Argumentpaare aus dem Abfragestring der URL. Sie speichert die Name=Wert-Paare in den Eigenschaften eines Objekts und liefert das Objekt zurück. Verwenden Sie sie folgendermaßen:
var args = getArgs( ); // Argumente aus der URL parsen var q = args.q || ""; // Argument verwenden, wenn es definiert ist, sonst einen // Default-Wert * var n = args.n ? parseInt(args.n) : 10; */ function getArgs( ) { var args = new Object( ); var abfrage = location.search.substring(1); // Abfragestring abrufen var paare = abfrage.split("&"); // Bei Ampersand-Zeichen zerlegen for(var i = 0; i < paare.length; i++) { var pos = paare[i].indexOf('='); // Nach "Name=Wert" suchen if (pos == -1) continue; // Wird keiner gefunden, überspringen var argname = paare[i].substring(0,pos); // Den Namen herausziehen var wert = paare[i].substring(pos+1); // Den Wert herausziehen value = decodeURIComponent(wert); // Den Wert, falls erforderlich, dekodieren args[argname] = wert; // Name/Wert-Paar als Eigenschaft speichern } return args; // Das Objekt zurückliefern }
14.2.2 Neue Dokumente laden Obwohl die location-Eigenschaft eines Fensters auf ein Location-Objekt verweist, können Sie der Eigenschaft einen Stringwert zuweisen. Wenn Sie das tun, interpretiert der Browser diesen String als eine URL und versucht, sie zu laden und das Dokument unter dieser URL anzuzeigen. Beispielsweise könnten Sie der Eigenschaft location folgendermaßen eine URL zuweisen: // Wenn der Browser die Funktion Document.getElementById nicht unterstützt, // zu einer statischen Seite umleiten, die diese Funktion nicht benötigt. if (!document.getElementById) location = "staticpage.html";
Beachten Sie, dass die der Eigenschaft location zugewiesene URL in diesem Beispiel eine relative URL ist. Relative URLs werden in Bezug auf die Seite interpretiert, in der sie erscheinen, genauso als würden sie in einem Hyperlink verwendet. Beispiel 14-7 am Ende dieses Kapitels nutzt die Eigenschaft location ebenfalls, um ein neues Dokument zu laden.
14.2 Die Location- und History-Objekte |
303
491-0.book Seite 304 Mittwoch, 4. April 2007 9:55 09
e-bol.net Es ist überraschend, dass das Window-Objekt keine Methode besitzt, die den Browser veranlasst, eine neue Seite zu laden und anzuzeigen. Früher war die Zuweisung einer URL zur location-Eigenschaft eines Fensters die unterstützte Technik zum Laden neuer Seiten. Das Location-Objekt hat allerdings zwei Methoden für verwandte Zwecke. Die Methode reload( ) lädt die aktuell angezeigte Webseite neu vom Webserver. Die Methode replace( ) lädt eine von Ihnen angegebene URL und zeigt sie an. Es hat allerdings andere Auswirkungen, wenn Sie die zweite Methode für eine bestimmte URL aufrufen, als wenn Sie der location-Eigenschaft eines Fensters eine neue URL zuweisen. Wenn Sie replace( ) aufrufen, ersetzt die angegebene URL die aktuelle URL im Verlauf des Browsers, anstatt einen neuen Eintrag in dieser Liste zu erzeugen. Wenn Sie replace( ) einsetzen, um ein Dokument mit einem anderen zu überschreiben, führt der Zurück-Button den Benutzer deswegen nicht zum ursprünglichen Dokument zurück, wie er es macht, wenn Sie ein neues Dokument laden, indem Sie der Eigenschaft location eine URL zuweisen. Bei Webseiten, die Frames einsetzen und viele (vielleicht von einem Serverskript generierte) temporäre Seiten laden, ist replace( ) oft nützlich. Da temporäre Seiten nicht im Verlauf gespeichert werden, ist der Zurück-Button für den Benutzer nützlicher. Verwechseln Sie außerdem die location-Eigenschaft des Window-Objekts, die auf ein Location-Objekt verweist, nicht mit der location-Eigenschaft des Document-Objekts, die einfach ein schreibgeschützter String ist, der keine der besonderen Funktionalitäten des Location-Objekts besitzt. document.location ist ein Synonym für document.URL, dem vorgezogenen Namen für diese Eigenschaft (weil er mögliche Verwirrungen vermeidet). In den meisten Fällen ist document.location mit location.href identisch. Aber wenn es eine Server-Umleitung gibt, enthält document.location die geladene URL, während location.href die URL enthält, die ursprünglich angefordert wurde.
14.2.3 Das History-Objekt Die history-Eigenschaft des Window-Objekts verweist auf das History-Objekt für das Fenster. Ursprünglich wurde das History-Objekt entworfen, um den Surfverlauf in einem Fenster als ein Array der zuletzt besuchten URLs zu modellieren. Es hat sich allerdings herausgestellt, dass das eine schlechte Entwurfsentscheidung war. Aus Gründen der Sicherheit und Privatsphäre ist es fast nie passend, einem Skript Zugriff auf die Liste der Webseiten zu geben, die der Benutzer zuvor besucht hat. Deswegen kann auf die ArrayElemente des History-Objekts über Skripten tatsächlich nie zugegriffen werden. Obwohl auf seine Array-Elemente nicht zugegriffen werden kann, unterstützt das History-Objekt drei Methoden. Die Methoden back( ) und forward( ) gehen im Verlauf eines Fensters (oder Frames) zurück und vor und ersetzen das aktuell angezeigte Dokument durch ein zuvor betrachtetes. Das ähnelt dem, was passiert, wenn der Benutzer auf die Zurück- und Vor-Buttons des Browsers klickt. Die dritte Methode, go( ), erwartet ein ganzzahliges Argument und kann im Verlauf eine beliebige Anzahl von Seiten vor (bei
304 | Kapitel 14: Browserfenster skripten
491-0.book Seite 305 Mittwoch, 4. April 2007 9:55 09
e-bol.net einem positiven Argument) oder zurück (bei einem negative Argument) gehen. Beispiel 14-7 am Ende dieses Kapitels führt die Verwendung der back( )- und forward( )-Methoden des History-Objekts vor.
14.3 Window-, Screen- und Browser-Informationen abrufen Skripten müssen sich manchmal auch Informationen zum Fenster, Desktop oder Browser verschaffen, in dem sie laufen. Dieser Abschnitt beschreibt Eigenschaften der Window-, Screen- und Navigator-Objekte, die es Ihnen ermöglichen, Dinge wie die Größe des Browserfensters, die Größe des Desktops und die Versionsnummer des Webbrowsers zu ermitteln. Diese Informationen ermöglichen es einem Skript, sein Verhalten auf Basis seiner Umgebung anzupassen.
14.3.1 Window-Geometrie Die meisten Browser (die bemerkenswerteste Ausnahme ist der Internet Explorer) unterstützen einen einfachen Satz von Eigenschaften auf dem Window-Objekt, die Informationen zur Größe und Position des Fensters enthalten: // Die Gesamtgröße des Browserfensters auf dem Desktop var windowWidth = window.outerWidth; var windowHeight = window.outerHeight; // Die Position des Browserfensters auf dem Desktop var windowX = window.screenX var windowY = window.screenY // Die Größe des Inhaltsbereichs, in dem das HMTL-Dokument angezeigt wird // Das ist die Fenstergröße abzüglich der Menü-, Werkzeug- und Bildlaufleisten usw. var viewportWidth = window.innerWidth; var viewportHeight = window.innerWidth; // Diese Werte geben die Positionen der horizontalen und vertikalen Bildlaufleisten an. // Sie werden zur Umwandlung zwischen Dokument- und Fensterkoordinaten verwendet. // Diese Werte geben an, welcher Bereich des Dokuments in der linken oberen Ecke // des Bildschirms erscheint. var horizontalScroll = window.pageXOffset; var verticalScroll = window.pageYOffset;
Beachten Sie, dass diese Eigenschaften schreibgeschützt sind. Methoden zur Fenstermanipulation, die es Ihnen ermöglichen, das Fenster zu verschieben, die Fenstergröße zu
14.3 Window-, Screen- und Browser-Informationen abrufen |
305
clientseitiges JavaScript
Netscape- und Mozilla-basierte Browser unterstützen back( )- und forward( )-Methoden auf dem Window-Objekt selbst. Diese nicht-portierbaren Methoden führen die gleichen Aktionen durch wie die Zurück- und Vor-Buttons des Browsers. Wenn Frames verwendet werden, kann es sein, dass window.back( ) eine andere Aktion durchführt als history.back( ).
491-0.book Seite 306 Mittwoch, 4. April 2007 9:55 09
e-bol.net ändern oder das Fenster zu scrollen, werden weiter unten in diesem Kapitel beschrieben. Beachten Sie auch, dass es unterschiedliche Koordinatensysteme gibt, derer Sie sich bewusst sein müssen. Bildschirmkoordinaten beschreiben die Position des Browserfensters auf dem Desktop. Sie werden in Bezug auf die linke obere Ecke des Desktops gemessen. Fensterkoordinaten beschreiben eine Position im Inhaltsbereich des Webbrowsers. Sie werden in Bezug auf die linke obere Ecke des Inhaltsbereichs gemessen. Dokumentkoordinaten beschreiben die Position innerhalb eines HTML-Dokuments. Sie werden in Bezug auf die linke obere Ecke des Dokuments gemessen. Wenn das Dokument länger oder breiter als der Inhaltsbereich ist (was bei Webseiten häufig der Fall ist), sind Dokumentkoordinaten und Fensterkoordinaten nicht identisch. Dann müssen Sie die Position der Bildlaufleisten berücksichtigen, wenn Sie zwischen diesen beiden Koordinatensystemen konvertieren. Mehr zu Dokumentkoordinaten erfahren Sie in den Kapiteln 15 und 16. Wie bereits gesagt wurde, sind die hier aufgeführten Eigenschaften des Window-Objekts im Internet Explorer nicht definiert. Aus irgendeinem Grund packt der IE die Eigenschaften für die Fenstergeometrie in den eines HTML-Dokuments. Und der IE 6 packt diese Eigenschaften, um die Sache noch etwas verwirrender zu machen, in das Element document.documentElement statt in document.body, wenn er ein Dokument mit einer -Deklaration anzeigt. Beispiel 14-2 liefert ausführliche Informationen dazu. Es definiert ein Geometry-Objekt mit Methoden, die eine portable Abfrage der Größe des Inhaltsbereichs, der Position der Bildlaufleiste und der Bildschirmposition ermöglichen. Beispiel 14-2: Portables Abfragen der Fenstergeometrie /** * Geometry.js: Portable Funktionen für die Geometrie von Fenster und Dokument. * * Dieses Modul definiert Funktionen für die Abfrage der Geometrie von Fenster und Dokument. * * getWindowX/Y( ): liefern die Position des Fensters auf dem Bildschirm zurück * getViewportWidth/Height( ): liefern die Größe des Inhaltsbereichs des Browser * getDocumentWidth/Height( ): liefern die Größe des Dokuments * getHorizontalScroll( ): liefert die Position der horizontalen Bildlaufleiste * getVerticalScroll( ): liefert die Position der vertikalen Bildlaufleiste * * Beachten Sie, dass es keine portable Möglichkeit gibt, die Gesamtgröße des Browserfensters * abzufragen. Deswegen gibt es keine getWindowWidth/Height( )-Funktionen. * * ACHTUNG: Dieses Modul muss in den eines Dokuments eingeschlossen werden, * nicht in den des Dokuments. */ var Geometry = {}; if (window.screenLeft) { // IE und andere Geometry.getWindowX = function( ) { return window.screenLeft; }; Geometry.getWindowY = function( ) { return window.screenTop; }; }
306 | Kapitel 14: Browserfenster skripten
491-0.book Seite 307 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 14-2: Portables Abfragen der Fenstergeometrie (Fortsetzung) else if (window.screenX) { // Firefox und andere Geometry.getWindowX = function( ) { return window.screenX; }; Geometry.getWindowY = function( ) { return window.screenY; }; }
clientseitiges JavaScript
if (window.innerWidth) { // Alle Browsers außer dem IE Geometry.getViewportWidth = function( ) { return window.innerWidth; }; Geometry.getViewportHeight = function( ) { return window.innerHeight; }; Geometry.getHorizontalScroll = function( ) { return window.pageXOffset; }; Geometry.getVerticalScroll = function( ) { return window.pageYOffset; }; } else if (document.documentElement && document.documentElement.clientWidth) { // Funktionen für den IE 6, wenn es einen DOCTYPE gibt Geometry.getViewportWidth = function( ) { return document.documentElement.clientWidth; }; Geometry.getViewportHeight = function( ) { return document.documentElement.clientHeight; }; Geometry.getHorizontalScroll = function( ) { return document.documentElement.scrollLeft; }; Geometry.getVerticalScroll = function( ) { return document.documentElement.scrollTop; }; } else if (document.body.clientWidth) { // Funktionen für IE4, IE5 und IE6 ohne DOCTYPE Geometry.getViewportWidth = function( ) { return document.body.clientWidth; }; Geometry.getViewportHeight = function( ) { return document.body.clientHeight; }; Geometry.getHorizontalScroll = function( ) { return document.body.scrollLeft; }; Geometry.getVerticalScroll = function( ) { return document.body.scrollTop; }; } // Diese Funktionen liefern die Größe des Dokuments zurück. Sie sind nicht fensterbezogen, // sind aber trotzdem nützlich. if (document.documentElement && document.documentElemnet.scrollWidth) { Geometry.getDocumentWidth = function( ) { return document.documentElement.scrollWidth; }; Geometry.getDocumentHeight = function( ) { return document.documentElement.scrollHeight; }; } else if (document.body.scrollWidth) { Geometry.getDocumentWidth = function( ) { return document.body.scrollWidth; }; Geometry.getDocumentHeight = function( ) { return document.body.scrollHeight; }; }
14.3 Window-, Screen- und Browser-Informationen abrufen |
307
491-0.book Seite 308 Mittwoch, 4. April 2007 9:55 09
e-bol.net
14.3.2 Das Screen-Objekt Die screen-Eigenschaft eines Window-Objekts verweist auf ein Screen-Objekt, das Informationen zur Größe der Anzeige des Benutzers und der auf ihr verfügbaren Farben enthält. Die Eigenschaften width und height geben die Größe der Anzeige in Pixeln an. Sie könnten diese Eigenschaften beispielsweise nutzen, um zu entscheiden, welche Größe die Bilder haben sollen, die in ein Dokument eingeschlossen werden sollen. Die Eigenschaften availWidth und availHeight geben die tatsächlich verfügbare Anzeigegröße an. Sie schließen den Raum aus, der von Elementen wie einer Desktop-Taskleiste eingenommen wird. Firefox und verwandte Browser (aber nicht der IE) definieren außerdem availLeft- und availTop-Eigenschaften für das Screen-Objekt. Diese Eigenschaften geben die Koordinaten der ersten verfügbaren Position auf dem Bildschirm an. Wenn Sie ein Skript schreiben, das ein neues Browserfenster öffnet (wie Sie das tun, werden Sie später in diesem Kapitel erfahren), könnten Sie diese Eigenschaften verwenden, um es leichter auf dem Bildschirm zu zentrieren. Beispiel 14-4 weiter unten in diesem Kapitel führt die Verwendung des Screen-Objekts vor.
14.3.3 Das Navigator-Objekt Die navigator-Eigenschaft eines Window-Objekts verweist auf ein Navigator-Objekt, das Informationen zu einem Webbrowser als Ganzem enthält. Beispiele sind die Version und die Liste der Datenformate, die er anzeigen kann. Das Navigator-Objekt hat seinen Namen vom Netscape Navigator, wird aber auch von allen anderen Browsern unterstützt. (Als herstellerneutrales Synonym für navigator unterstützt der IE außerdem clientInformation. Leider haben andere Browser diese vernünftiger benannte Eigenschaft nicht übernommen.) In der Vergangenheit wurde das Navigator-Objekt von Skripten verbreitet verwendet, um zu ermitteln, ob sie im Internet Explorer oder in Netscape laufen. Dieses Verfahren zur Browserermittlung ist problematisch, weil es eine kontinuierliche Anpassung erfordert, wenn neue Browser oder neue Versionen vorhandener Browser eingeführt werden. Heutzutage wird ein Verfahren vorgezogen, das auf einer Funktionalitätsprüfung basiert. Anstatt Annahmen in Bezug auf bestimmte Browser und ihre Funktionalitäten zu machen, prüfen Sie einfach auf die Funktionalität (d.h. die Methode), die Sie benötigen. Als Beispiel sehen Sie hier, wie Sie ein Funktionalitätsprüfungsverfahren für die Methoden zur Event-Handler-Registrierung verwenden (die in Kapitel 17 betrachtet werden): if (window.addEventListener) { // Wenn die Methode addEventListener( ) unterstützt wird, wird diese verwendet. // Das deckt den Fall standardkonformer Browser wie Netscape/Mozilla/Firefox ab. } else if (window.attachEvent) { // Andernfalls wird die Methode attachEvent( ) verwendet, wenn sie existiert.
308 | Kapitel 14: Browserfenster skripten
491-0.book Seite 309 Mittwoch, 4. April 2007 9:55 09
e-bol.net // Das deckt den IE und alle nicht-standardmäßigen Browser ab, die ihn emulieren. } else { // Andernfalls ist keine der Methoden verfügbar. // Das passiert bei älteren Browsern, die kein DHTML unterstützen. }
Das Navigator-Objekt hat fünf Eigenschaften, die Versionsinformationen zu dem Browser liefern, der läuft: appName
Der einfache Name des Webbrowsers. Beim IE ist das »Microsoft Internet Explorer«. Bei Firefox und anderen Browsern, die von der Netscape-Codebasis abgeleitet sind (wie Mozilla und Netscape selbst), ist das »Netscape«. appVersion
Die Versionsnummer und/oder andere Versionsinformationen zu dem Browser. Beachten Sie, dass das als interne Versionsnummer betrachtet werden sollte, da sie nicht immer mit der Versionsnummer übereinstimmt, die für den Benutzer angezeigt wird. Beispielsweise melden Netscape 6 und alle nachfolgenden Versionen von Mozilla und Firefox die Versionsnummer 5.0. Gleichermaßen melden die IE-Versionen 4 bis 6 alle die Versionsnummer 4.0, um eine Kompatibilität mit der Basisfunktionalität dieser vierten Browsergeneration anzuzeigen. userAgent
Der String, den der Browser in seinem USER-AGENT-HTTP-Header sendet. Diese Eigenschaft enthält üblicherweise alle Informationen in appName und appVersion und kann oft noch weitere Informationen enthalten. Es gibt allerdings keine Standardformatierung für diese Informationen. Es ist also nicht möglich, sie auf browserunabhängige Weise zu parsen. appCodeName
Der Codename des Browsers. Netscape nutzt den Codenamen »Mozilla« als Wert dieser Eigenschaft. Aus Kompatibilitätsgründen macht der IE das Gleiche. platform
Die Hardware-Plattform, auf der der Browser läuft. Diese Eigenschaft wurde in JavaScript 1.2 eingeführt. Die folgenden Zeilen JavaScript-Code zeigen alle Eigenschaften des Navigator-Objekts in einem Dialogfenster an: var browser = "BROWSER-INFORMATIONEN:\n"; for(var eigenschaft in navigator) { browser += eigenschaft + ": " + navigator[eigenschaft] + "\n" } alert(browser);
14.3 Window-, Screen- und Browser-Informationen abrufen |
309
clientseitiges JavaScript
Browserermittlung ist manchmal aber trotzdem nützlich. Das ist beispielsweise der Fall, wenn Sie einen bestimmten Fehler umgehen wollen, der in einer bestimmten Version eines bestimmten Browsers auftritt. Das ermöglicht Ihnen das Navigator-Objekt.
491-0.book Seite 310 Mittwoch, 4. April 2007 9:55 09
e-bol.net Abbildung 14-1 zeigt das Dialogfenster, das angezeigt wird, wenn der Code in Firefox 1.5 ausgeführt wird.
Abbildung 14-1: Die Eigenschaften des Navigator-Objekts
Wie Sie auf Abbildung 14-1 sehen können, haben die Eigenschaften des Navigator-Objekts Werte, die manchmal komplexer als das sind, was Sie benötigen. Vielleicht interessieren Sie sich beispielsweise nur für die erste Ziffer der Eigenschaft appVersion. Wenn Sie das Navigator-Objekt verwenden, um Browserinformationen zu prüfen, können Sie Methoden wie parseInt( ) und String.indexOf( ) einsetzen, um nur die Informationen herauszuziehen, die Sie benötigen. Beispiel 14-3 zeigt etwas Code, der das macht: Er verarbeitet die Eigenschaften des Navigator-Objekts und speichert sie in einem Objekt namens browser.
310 | Kapitel 14: Browserfenster skripten
491-0.book Seite 311 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Beispiel 14-3: Browserhersteller und -version ermitteln /** * browser.js: Ein einfacher Client-Sniffer * * Dieses Modul definiert ein Objekt namens "browser", das sich leichter verwenden * lässt als das "navigator"-Objekt. */ var browser = { version: parseInt(navigator.appVersion), isNetscape: navigator.appName.indexOf("Netscape") != -1, isMicrosoft: navigator.appName.indexOf("Microsoft") != -1 };
Ein wichtiger Punkt, den Sie aus diesem Abschnitt mitnehmen sollten, ist, dass die Eigenschaften des Navigator-Objekts keine zuverlässige Browserbeschreibung liefern. Firefox 1.0, zum Beispiel, hat den appName »Netscape« und eine appVersion, die mit »5.0« beginnt. Safari, der nicht auf Mozilla-Code basiert, liefert die gleichen Werte zurück! Und der IE 6.0 hat den appCodeName »Mozilla« und eine appVersion, die mit der Zahl »4.0« beginnt. Der Grund dafür ist, dass früher in alten, bestehenden Webseiten so viel Browser-Sniffing-Code verwendet wurde, dass die Browserhersteller es sich nicht leisten können, die Rückwärtskompatibilität zu brechen, indem sie diese Eigenschaften aktualisieren. Das ist einer der Gründe dafür, dass das Browser-Sniffing weniger hilfreich geworden ist und vom Feature Testing überholt wurde.
14.4 Fenster öffnen und manipulieren Das Window-Objekt definiert eine Reihe von Methoden, die eine hochgradige Steuerung des Fensters selbst ermöglichen. Die folgenden Abschnitte untersuchen, wie diese Methoden es Ihnen ermöglichen, Fenster zu öffnen und zu schließen, die Fenstergröße und -position zu steuern, den Tastaturfokus anzufordern und freizugeben und den Inhalt eines Fensters zu scrollen. Dieser Abschnitt schließt mit einem Beispiel, das einige dieser Features vorführt.
14.4 Fenster öffnen und manipulieren |
311
clientseitiges JavaScript
In ihrer verarbeiteten Form sind diese Eigenschaften leichter zu verwenden als die rohen navigator-Eigenschaften. Der allgemeine Begriff für Code wie diesen ist Client-Sniffer. Komplexeren und allgemeineren Sniffer-Code können Sie im Internet finden. (Siehe beispielsweise http://www.mozilla.org/docs/web-developer/sniffer/browser_type. html.) Aber für viele Zwecke ist Code, der so einfach ist wie der in Beispiel 14-3 gezeigte, vollkommen ausreichend.
491-0.book Seite 312 Mittwoch, 4. April 2007 9:55 09
e-bol.net
14.4.1 Fenster öffnen Ein neues Webbrowserfenster können Sie mit der open( )-Methode des Window-Objekts öffnen. Window.open( ) ist die Methode, die verwendet wird, um über oder unter dem Browser-
fenster neue Fenster zu öffnen, während Sie im Web surfen. Aufgrund dieser Flut nervender Pop-ups haben die meisten Browserhersteller irgendeine Art Pop-up-Blocker integriert. Üblicherweise sind Aufrufe der open( )-Methode nur als Antwort auf eine Benutzeraktion erfolgreich, beispielsweise wenn der Benutzer auf einen Button oder einen Link klickt. JavaScript-Code, der versucht ein Pop-up-Fenster zu öffnen, wenn der Browser eine Seite zum ersten Mal lädt (oder entlädt), schlägt fehl. Window.open( ) erwartet vier optionale Argumente und liefert ein Window-Objekt zurück, das das neu geöffnete Fenster repräsentiert. Das erste Argument für open( ) ist die URL
des Dokuments, das in dem neuen Fenster angezeigt werden soll. Wird dieses Argument weggelassen (oder ist es null oder der leere String), bleibt das Fenster leer. Das zweite Argument für open( ) ist der Name des Fensters. Wie in diesem Kapitel bereits besprochen wurde, kann dieser Wert als Name des target-Attributs eines - oder -Tags nützlich sein. Wenn Sie den Namen eines Fensters angeben, das bereits geöffnet ist, liefert open( ) einfach eine Referenz auf das bestehende Fenster zurück und öffnet kein neues. Das dritte Argument für open( ) ist eine Liste mit Features, die die Fenstergröße und GUIDekorationen angeben. Wenn Sie dieses Argument weglassen, erhält das neue Fenster die Default-Größe und einen vollständigen Satz von Standard-Features: eine Menüleiste, eine Statusleiste, Werkzeugleisten und so weiter. Aber wenn Sie dieses Argument angeben, können Sie explizit die Größe des Fensters und die Features angeben, die es einschließen soll. Beispielsweise können Sie die folgende Zeile JavaScript verwenden, um ein kleines, größenveränderbares Fenster mit einer Statusleiste, aber ohne Menüleiste oder Adressleiste zu erzeugen: var w = window.open("smallwin.html", "Kleines Fenster", "width=400,height=350,status=yes,resizable=yes");
Beachten Sie, dass alle Features weggelassen werden, die Sie nicht explizit angeben, wenn Sie ein drittes Argument angeben. Bei Window.open( ) in Teil IV finden Sie eine vollständige Liste der verfügbaren Features und ihrer Namen. Aus unterschiedlichen Sicherheitsgründen besitzen Browser verschiedene Einschränkungen für die Features, die Sie angeben können. Üblicherweise wird Ihnen beispielsweise nicht gestattet, ein Fenster anzugeben, das zu klein ist oder außerhalb des Bildschirms positioniert wird. Und einige Browser erlauben Ihnen nicht, ein Fenster ohne Statusleiste zu erzeugen. Während Spammer, Phisher und andere Protagonisten der dunklen Seite des Webs immer wieder neue Möglichkeiten finden, Benutzer auszuspionieren, erlegen Browserhersteller der Verwendung der open( )-Methode mehr und mehr Einschränkungen auf.
312 | Kapitel 14: Browserfenster skripten
491-0.book Seite 313 Mittwoch, 4. April 2007 9:55 09
e-bol.net Das vierte Argument für open( ) ist nur dann nützlich, wenn das zweite Argument ein bestehendes Fenster angibt. Dieses vierte Argument ist ein Boolescher Wert, der angibt, ob die URL, die als erstes Argument angegeben wurde, den aktuellen Eintrag im Verlauf des Browserfensters ersetzen soll (true) oder ob ein neuer Eintrag im Verlauf des Browserfensters erzeugt werden soll (false). Das zweite Verhalten ist das Default-Verhalten.
14.4.2 Fenster schließen Genau wie die Methode open( ) ein neues Fenster öffnet, schließt die Methode close( ) ein Fenster. Wenn Sie ein Window-Objekt w erzeugt haben, können Sie es folgendermaßen schließen: w.close( );
JavaScript-Code, der in diesem Fenster selbst läuft, kann es folgendermaßen schließen: window.close( );
Beachten Sie die explizite Verwendung des Bezeichners window, um die close( )-Methode des Window-Objekts von der close( )-Methode des Document-Objekts zu unterscheiden. Die meisten Browser ermöglichen es Ihnen, nur die Fenster automatisch zu schließen, die Ihr eigener JavaScript-Code erzeugt hat. Wenn Sie versuchen, ein anderes Fenster zu schließen, schlägt die Anforderung entweder fehl oder es wird dem Benutzer ein Dialogfenster präsentiert, das ihn auffordert, die Anforderung, das Fenster zu schließen, zu bestätigen (oder abzubrechen). Diese Vorsichtsmaßnahme verhindert, dass unvorsichtige Skripter Code schreiben, der das Haupt-Surffenster schließt. Ein Window-Objekt besteht weiter, nachdem das Fenster geschlossen wurde, das es repräsentiert. Sie sollten allerdings nicht versuchen, eine seiner Eigenschaften zu verwenden. Nur die Eigenschaft closed können Sie prüfen. Diese Eigenschaft ist true, wenn das Fenster geschlossen wurde. Denken Sie daran, dass der Benutzer jedes Fenster jederzeit schließen kann. Es empfiehlt sich, regelmäßig zu prüfen, ob ein Fenster, das Sie zu verwenden versuchen, immer noch geöffnet ist.
14.4 Fenster öffnen und manipulieren |
313
clientseitiges JavaScript
Der Rückgabewert der open( )-Methode ist ein Window-Objekt, das das neu erzeugte Fenster repräsentiert. Sie können dieses Window-Objekt in Ihrem JavaScript-Code verwenden, um das neue Fenster zu referenzieren, wie Sie das implizite Window-Objekt window verwenden, um das Fenster zu referenzieren, in dem Ihr Code läuft. Aber wie ist das mit der umgekehrten Situation? Was ist, wenn JavaScript-Code im neuen Fenster das Fenster referenzieren will, durch das er geöffnet wurde? Die opener-Eigenschaft eines Fensters verweist auf das Fenster, durch das es geöffnet wurde. Wenn das Fenster vom Benutzer statt von JavaScript-Code geöffnet wurde, ist der Wert der opener-Eigenschaft null.
491-0.book Seite 314 Mittwoch, 4. April 2007 9:55 09
e-bol.net
14.4.3 Fenster manipulieren Das Window-Objekt definiert Methoden, die die Größe eines Fensters ändern und das Fenster bewegen. Die Verwendung dieser Methoden wird üblicherweise als sehr schlechter Stil betrachtet: Die Kontrolle über die Größe und Position aller Fenster auf dem Desktop sollte ausschließlich dem Benutzer überlassen bleiben. Moderne Browser haben üblicherweise eine Option, die verhindert, dass JavaScript Fenster bewegt oder ihre Größe ändert, und Sie sollten davon ausgehen, dass diese Option bei einem großen Prozentsatz der Browser aktiviert ist. Außerdem schränken Browser üblicherweise Ihre Möglichkeiten ein, Fenster aus dem Bildschirm zu schieben oder zu klein zu machen, um bösartigen Skripten entgegenzuwirken, die sich auf Code stützen, der in kleinen Fenstern oder Fenstern außerhalb des Bildschirms läuft, die vom Benutzer nicht bemerkt werden. Lesen Sie weiter, wenn Sie, nach all diesen Vorbehalten, immer noch die Größe von Fenstern ändern oder Fenster verschieben wollen. moveTo( ) verschiebt die linke obere Ecke des Fensters an die angegebenen Koordinaten. Gleichermaßen verschiebt moveBy( ) das Fenster um die angegebene Anzahl von Pixeln nach links oder rechts und nach oben oder unten. resizeTo( ) und resizeBy( ) ändern die
Fenstergröße um einen absoluten oder relativen Betrag. Ausführliche Informationen finden Sie in Teil IV.
14.4.4 Tastaturfokus und Sichtbarkeit Die Methoden focus( ) und blur( ) bieten ebenfalls hochgradige Steuerungsmöglichkeiten über ein Fenster. Ein Aufruf von focus( ) fordert, dass das System dem Fenster den Tastaturfokus gibt, und ein Aufruf von blur( ) gibt den Tastaturfokus frei. Außerdem sichert die Methode focus( ), dass das Fenster sichtbar ist, indem es in der Stapelreihenfolge nach oben verschoben wird. Wenn Sie die Methode Window.open( ) verwenden, um ein neues Fenster zu erzeugen, erzeugt der Browser dieses Fenster automatisch oben auf dem Stapel. Aber wenn das zweite Argument den Namen eines Fensters angibt, das bereits besteht, macht die Methode open( ) dieses nicht automatisch sichtbar. Deswegen ist es eine verbreitete Praxis, auf Aufrufe von open( ) einen Aufruf von focus( ) folgen zu lassen.
14.4.5 Scrollen Das Window-Objekt enthält außerdem Methoden, die das Dokument in einem Fenster oder Frame scrollen. scrollBy( ) scrollt das Dokument, das im Fenster angezeigt wird, um die angegebene Anzahl von Pixeln nach links oder rechts und nach oben oder unten. scrollTo( ) scrollt das Dokument zu einer absoluten Position. Es bewegt das Dokument so, dass sich die angegebenen Dokumentkoordinaten in der linken oberen Ecke des Dokumentbereichs des Fensters befinden.
314 | Kapitel 14: Browserfenster skripten
491-0.book Seite 315 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Eine andere Herangehensweise für das Scrolling ist es, die focus( )-Methode von Dokumentelementen (wie Formularfeldern und Buttons) aufzurufen, die den Tastaturfokus annehmen können. Wenn der Fokus auf das Element übertragen wird, wird das Dokument auch gescrollt, um das Element sichtbar zu machen. Beachten Sie, dass das das Element nicht notwendigerweise in die linke obere Ecke des Fensters bringt. Aber es sorgt dafür, dass das Element irgendwo im Fenster sichtbar ist. Die meisten modernen Browser haben eine weitere Scrolling-Methode: Auf einem beliebigen HTML-Dokument kann scrollIntoView( ) aufgerufen werden, um es sichtbar zu machen. Diese Methode versucht, das Element oben im Fenster zu positionieren, aber kann das natürlich nicht, wenn sich das Element in der Nähe des Dokumentendes befindet. scrollIntoView( ) ist nicht so weit verbreitet implementiert wie die Methode focus( ), funktioniert aber auf allen HTML-Elementen, nicht nur auf denen, die den Tastaturfokus annehmen. Mehr zu dieser Methode erfahren Sie im HTMLElementAbschnitt von Teil IV. Eine letzte Möglichkeit, ein Fenster mithilfe der Skriptsteuerung zu scrollen, besteht darin, an allen Orten, zu denen Sie das Dokument scrollen wollen, mit -Tags Anker zu definieren. Dann verwenden Sie die Ankernamen mit der hash-Eigenschaft des Location-Objekts. Wenn Sie am Anfang Ihres Dokuments einen Anker mit dem Namen »top« definieren, können Sie beispielsweise mit Code wie diesem wieder an den Anfang des Dokuments zurückspringen: window.location.hash = "#top";
Diese Technik ist eine wirksame Anwendung der Fähigkeit von HTML, über benannte Anker in einem Dokument zu navigieren. Sie macht die aktuelle Dokumentposition in der Adressleiste des Browsers sichtbar, ermöglicht es, Lesezeichen für diese Position zu setzen, und ermöglicht es dem Benutzer, mit dem Zurück-Button zu seiner vorangehenden Position zurückzugehen, was ein ansprechendes Feature sein kann. Andererseits kann es unter manchen Umständen als Ärgernis betrachtet werden, wenn man den Browserverlauf des Benutzers mit benannten Ankern verstopft, die von einem Skript generiert wurden. Um zu einem benannten Anker zu scrollen, ohne (in den meisten Browsern) einen neuen Verlaufseintrag zu erzeugen, verwenden Sie stattdessen die Methode Location.replace( ): window.location.replace("#top");
14.4 Fenster öffnen und manipulieren |
315
clientseitiges JavaScript
In modernen Browsern haben die HTML-Elemente eines Dokuments (siehe Kapitel 15) offsetLeft- und offsetTop-Eigenschaften, die die X- und Y-Koordinaten des Elements angeben (Methoden zur Ermittlung der Position aller Elemente werden in Abschnitt 16.2.3 behandelt). Nachdem Sie die Position eines Elements ermittelt haben, können Sie die Methode scrollTo( ) verwenden, um ein Fenster so zu scrollen, dass sich ein beliebiges angegebenes Element in der linken oberen Ecke des Fensters befindet.
491-0.book Seite 316 Mittwoch, 4. April 2007 9:55 09
e-bol.net
14.4.6 Beispiel zu Window-Methoden Beispiel 14-4 führt die open( )-, close( )- und moveTo( )-Methoden des Window-Objekts und eine Reihe weiterer Programmiertechniken für Fenster vor, die in diesem Kapitel behandelt wurden. Es erzeugt ein neues Fenster und verwendet dann setInterval( ), um wiederholt eine Funktion aufzurufen, die es über den Bildschirm bewegt. Es ermittelt über das Screen-Objekt die Größe des Bildschirms und verwendet diese Informationen dann, um das Fenster zurückspringen zu lassen, wenn es einen der Ränder des Bildschirms erreicht. Beispiel 14-4: Fenster erzeugen und manipulieren var abprallen = { x:0, y:0, w:200, h:200, dx:5, dy:5, intervall: 100, fenster: null, timer: null,
// // // // //
Fensterposition und Größe Fenstergeschwindigkeit Millisekunden zwischen Aktualisierungen Das Fenster, das wir erzeugen werden Der Rückgabewert von setInterval( )
// Die Animation beginnen. start: function( ) { // Mit dem Fenster im Zentrum des Bildschirms beginnen. abprallen.x = (screen.width - abprallen.w)/2; abprallen.y = (screen.height - abprallen.h)/2; // Das Fenster erzeugen, das wir herumbewegen werden. // Die javascript:-URL ist einfach ein Mittel, um ein kurzes Dokument anzuzeigen. // Das letzte Argument gibt die Fenstergröße an. abprallen.fenster = window.open('javascript:"ABPRALLEN!"', "", "left=" + abprallen.x + ",top=" + abprallen.y + ",width=" + abprallen.w + ",height=" +abprallen.h+ ",status=yes"); // setInterval( ) verwenden, um die Methode naechsterFrame( ) alle intervall // Millisekunden aufzurufen. Den Rückgabewert speichern, damit die Animation // angehalten werden kann, indem er an clearInterval( ) übergeben wird. abprallen.timer = setInterval(abprallen.naechsterFrame, abprallen.intervall); }, // Die Animation anhalten. stop: function( ) { clearInterval(abprallen.timer); // Timer abbrechen if (!abprallen.fenster.closed) abprallen.fenster.close( ); // Fenster schließen }, // Den nächsten Frame der Animation anzeigen. Wird von setInterval( ) aufgerufen. naechsterFrame: function( ) { // Wenn der Benutzer das Fenster geschlossen hat, wird die Animation beendet. if (abprallen.fenster.closed) {
316 | Kapitel 14: Browserfenster skripten
491-0.book Seite 317 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 14-4: Fenster erzeugen und manipulieren (Fortsetzung) clearInterval(abprallen.timer); return; }
clientseitiges JavaScript
// Zurückspringen, wenn der rechte oder linke Rand erreicht wurde. if ((abprallen.x+abprallen.dx > (screen.availWidth - abprallen.w)) || (abprallen.x+abprallen.dx < 0)) abprallen.dx = -abprallen.dx; // Zurückspringen, wenn der obere oder untere Rand erreicht wurde. if ((abprallen.y+abprallen.dy > (screen.availHeight - abprallen.h)) || (abprallen.y+abprallen.dy < 0)) abprallen.dy = -abprallen.dy; // Die aktuelle Position des Fensters aktualisieren. abprallen.x += abprallen.dx; abprallen.y += abprallen.dy; // Schließlich das Fenster in die neue Position bewegen. abprallen.fenster.moveTo(abprallen.x,abprallen.y); // Die aktuelle Position in der Statusleiste des Fensters anzeigen. abprallen.fenster.defaultStatus = "(" + abprallen.x + "," + abprallen.y + ")"; } } Start Stop
14.5 Einfache Dialogfenster Das Window-Objekt bietet drei Methoden, um dem Benutzer einfache Dialogfenster anzuzeigen. alert( ) zeigt dem Benutzer eine Meldung an und wartet, dass der Benutzer das Dialogfenster schließt. confirm( ) fordert den Benutzer auf, auf einen OK- oder einen Abbrechen-Button zu klicken, um eine Operation zu bestätigen bzw. abzubrechen. Und prompt( ) fordert den Benutzer zur Eingabe eines Strings auf. Obwohl diese Methoden sehr einfach und leicht zu verwenden sind, verlangt gutes Design, dass Sie sie spärlich – am besten überhaupt nicht – einsetzen. Dialogfenster wie diese sind kein gewöhnliches Feature des Webparadigmas und werden mittlerweile immer seltener eingesetzt, da fähige Webbrowser das Scripting des Dokumentinhaltes selbst unterstützen. Die meisten Benutzer werden die Dialogfenster, die von den Methoden alert( ), confirm( ) und prompt( ) erzeugt werden, als Störung ihres Surferlebnisses empfinden. Heutzutage werden diese Methoden oft nur noch für das Debugging verwendet: JavaScript-Progammierer fügen in Code, der nicht funktioniert, häuft alert( )Methoden ein, um zu versuchen, das Problem zu diagnostizieren. (In Beispiel 15-9 finden Sie eine alternative Technik für das Debugging.)
14.5 Einfache Dialogfenster |
317
491-0.book Seite 318 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beachten Sie, dass der Text, der von diesen Dialogfenstern angezeigt wird, Klartext ist, und nicht HTML-formatierter Text. Sie können den Text in diesen Dialogfenstern nur mit Leerzeichen, Zeilenumbrüchen und verschiedenen Interpunktionszeichen steuern. Einige Browser zeigen in der Titelleiste oder der linken oberen Ecke aller Dialogfenster, die mit alert( ), confirm( ) und prompt( ) erzeugt wurden, das Wort »JavaScript« an. Obwohl Designer das nervend finden, sollte das als Feature, nicht als Fehler betrachtet werden: Es dient dazu, dem Benutzer die Herkunft des Dialogfensters klarzumachen und verhindert, dass Hacker Trojaner-Code schreiben, der System-Dialogfenster vortäuscht und den Benutzer so austrickst, dass dieser sein Passwort eingibt oder andere Dinge tut, die er nicht tun sollte. Die Methoden confirm( ) und prompt( ) blockieren – das heißt, dass diese Methoden erst zurückkehren, wenn der Benutzer das Dialogfenster schließt, das von ihnen angezeigt wird. Das bedeutet, dass Ihr Code nicht mehr weiterläuft, wenn eines dieser Dialogfenster geöffnet wird, und dass das Laden des aktuell geladenen Dokuments (wenn es ein solches gibt) angehalten wird, bis der Benutzer die angeforderte Eingabe liefert. Diese Methoden müssen blockieren, weil ihr Rückgabewert die Eingabe des Benutzers ist und die Methoden deswegen auf den Benutzer warten müssen, bevor sie zurückkehren können. In den meisten Browsern blockiert auch die alert( )-Methode und wartet darauf, dass der Benutzer das Dialogfenster schließt. Beispiel 14-5 zeigt eine mögliche Verwendung der Methode confirm( ), die das in Abbildung 14-2 gezeigte Dialogfenster hervorbringt. Beispiel 14-5: Die confirm( )-Methode verwenden function sendeAbfrage( ) { // Das wollen wir den Benutzer fragen. Eine eingeschränkte Formatierung // kann mit Unterstrichen und Zeilenumbrüchen erreicht werden. var meldung = "\n\n\n\n" + "________________________________________________________\n\n" + "Bitte beachten Sie, dass komplexe Abfragen wie Ihre eine\n" + "Minute oder mehr an Suchzeit in Anspruch nehmen können.\n" + "________________________________________________________\n\n\n" + "Bestätigen Sie mit OK oder brechen Sie mit Abbrechen ab."; // Um Bestätigung bitten und abbrechen, wenn diese nicht erteilt wird. if (!confirm(meldung)) return; /* Hier kämme der Code zur Ausführung der Abfrage hin. */ }
318 | Kapitel 14: Browserfenster skripten
491-0.book Seite 319 Mittwoch, 4. April 2007 9:55 09
e-bol.net
clientseitiges JavaScript
Abbildung 14-2: Ein confirm( )-Dialogfenster
14.6 Die Statusleiste skripten Webbrowser zeigen am unteren Rand jedes Fensters üblicherweise eine Statusleiste an, in der der Browser Meldungen für den Benutzer anzeigen kann. Wenn der Benutzer die Maus über einen Hyperlink bewegt, zeigt ein Browser beispielsweise üblicherweise die URL an, auf die der Link zeigt. In alten Browsern können Sie die Eigenschaft status setzen, um Text anzugeben, den der Browser vorübergehend in der Statusleiste anzeigen soll. Die Eigenschaft wurde üblicherweise verwendet, wenn der Benutzer die Maus über einem Hyperlink schweben lies, um anstelle der für Maschinen gedachten URL des Dokuments eine für Menschen lesbare Beschreibung des verlinkten Elements anzuzeigen. Code, der das gemacht hat, sah üblicherweise so aus: Verwirrt? Versuchen Sie die Online-Hilfe.
Wenn sich die Maus über diesen Hyperlink bewegt, wird der JavaScript-Code im onmouseover-Attribut ausgewertet. Er setzt die status-Eigenschaft des Fensters und liefert dann true zurück, um dem Browser zu sagen, dass dieser seine Aktion nicht durchführen soll (d.h., nicht die URL des Hyperlinks anzeigen soll). Dieses Codefragment funktioniert nicht mehr. Häufig wurde Code wie dieser eingesetzt, um Benutzer vorsätzlich über das Ziel eines Links zu täuschen (beim Phishing-Betrug beispielsweise). Moderne Browser haben deswegen die Funktionalität zum Setzen der status-Eigenschaft deaktiviert. Das Window-Objekt definiert außerdem eine defaultStatus-Eigenschaft, die Text angibt, der in der Statusleiste angezeigt werden soll, wenn der Browser nichts anderes (wie Hyperlink-URLs) hat, die dort angezeigt werden sollen. In einigen Browsern funk-
14.6 Die Statusleiste skripten |
319
491-0.book Seite 320 Mittwoch, 4. April 2007 9:55 09
e-bol.net tioniert defaultStatus noch (aber nicht in allen: Firefox 1.0 deaktiviert die Eigenschaft defaultStatus beispielsweise gemeinsam mit der Eigenschaft status). Früher wurde die Eigenschaft defaultStatus beispielsweise verwendet, um StatusleistenAnimationen zu erzeugen. In der Vergangenheit, als Dokumentinhalte noch nicht skriptbar waren, aber die Eigenschaft defaultStatus und die Methode setInterval( ) verfügbar waren, konnten Webentwickler der Versuchung nicht wiederstehen, eine Vielzahl von ablenkenden und grellen Marquee-Animationen zu erzeugen, die eine Meldung über die Statusleiste gescrollt haben. Glücklicherweise sind diese Zeiten vorbei. Allerdings gibt es gelegentlich immer noch Gründe dafür, die Statusleiste zu verwenden, und sogar dafür, sie mit setInterval( ) zu verwenden, wie Beispiel 14-6 zeigt. Beispiel 14-6: Eine geschmackvolle Statusleisten-Animation var VergeudeteZeit = { start: new Date( ), // Die Anfangszeit festhalten zeigeVerstricheneZeit: function( ) { var jetzt = new Date( ); // Wie spät ist es jetzt? // die verstrichenen Minuten berechnen var verstrichen = Math.round((jetzt - VergeudeteZeit.start)/60000); // und versuchen, das in der Statusleiste anzuzeigen. window.defaultStatus = "Sie haben " + verstrichen + " Minuten vergeudet."; } } // Die Statusleiste minütlich aktualisieren. setInterval(VergeudeteZeit.zeigeVerstricheneZeit, 60000);
14.7 Fehlerbehandlung Die onerror-Eigenschaft eines Window-Objekts ist eine besondere Eigenschaft. Wenn Sie dieser Eigenschaft eine Funktion zuweisen, wird diese Funktion jedes Mal aufgerufen, wenn in diesem Fenster ein JavaScript-Fehler auftritt: Die Funktion, die Sie zuweisen, wird zu einem Error-Handler für das Fenster. (Beachten Sie, dass Sie auch einfach eine globale Funktion namens onerror( ) definieren können sollten, da das mit der Zuweisung einer Funktion zur onerror-Eigenschaft eines Window-Objekts äquivalent sein müsste. Im IE funktioniert die Definition einer globalen onerror( )-Funktion allerdings nicht.) Wenn ein JavaScript-Fehler auftritt, werden einem Error-Handler drei Argumente übergeben. Das erste ist eine Nachricht, die den Fehler beschreibt. Das könnte etwas sein wie »missing operator in expression«, »self is read-only« oder »meinname is not defined«. Das zweite Argument ist ein String, der die URL des Dokuments enthält, das den JavaScriptCode enthält, der den Fehler verursacht hat. Das dritte Argument ist die Nummer der Zeile im Dokument, auf der der Fehler aufgetreten ist. Ein Error-Handler kann diese Argumente für beliebige Zwecke verwenden. Ein typischer Error-Handler könnte dem Benutzer die Fehlermeldung anzeigen, den Fehler irgendwo protokollieren oder es erzwingen, dass der
320 | Kapitel 14: Browserfenster skripten
491-0.book Seite 321 Mittwoch, 4. April 2007 9:55 09
e-bol.net Fehler ignoriert wird. Vor JavaScript 1.5 kann der onerror-Handler auch als recht armseliger Ersatz für das try/catch-Exception-Handling dienen (siehe Kapitel 6).
Im Lauf der Zeit haben Browser die Art geändert, wie sie mit JavaScript-Fehlern umgehen. Als JavaScript neu und Webbrowser jung waren, haben Browser üblicherweise jedes Mal ein Dialogfenster aufspringen lassen, wenn ein JavaScript-Fehler aufgetreten ist. Für Entwickler sind diese Dialoge hilfreich, für Endbenutzer sind sie störend. Um zu verhindern, dass Endbenutzer bei einer Produktions-Website jemals einen Fehlerdialog sehen (viele Websites verursachen JavaScript-Fehler, zumindest in einigen Browsern), können Sie einfach einen Error-Handler schreiben, der alle Fehler stillschweigend ignoriert: // Den Benutzer nicht mit Fehlermeldungen belästigen window.onerror = function( ) { return true; }
Als schlecht geschriebener und inkompatibler JavaScript-Code im Web zu wuchern begann und JavaScript-Fehler alltäglich wurden, begannen Webbrowser, Fehler unaufdringlicher zu protokollieren. Das ist für Endbenutzer besser, aber schwerer für JavaScript-Entwickler, die (in Firefox beispielsweise) ein JavaScript-Konsolenfenster öffnen müssen, um zu sehen, welche Fehler aufgetreten sind. Um das während der Codeentwicklung zu vereinfachen, können Sie einen Error-Handler wie diesen definieren: // Fehlermeldungen in einem Dialogfenster anzeigen, aber nie mehr als 3. window.onerror = function(msg, url, line) { if (onerror.num++ < onerror.max) { alert("FEHLER: " + msg + "\n" + url + ":" + line); return true; } } onerror.max = 3; onerror.num = 0;
14.8 Mehrere Fenster und Frames Die meisten Webanwendungen laufen in einem einzelnen Fenster oder öffnen vielleicht kleine Zusatzfenster, um eine Hilfe anzuzeigen. Aber es ist auch möglich, Anwendungen zu erstellen, die zwei oder mehr Frames oder Fenster verwenden und JavaScript-Code einsetzen, um diese Fenster oder Frames miteinander interagieren zu lassen. Dieser Abschnitt erklärt, wie das gemacht wird.1 1 In den Anfangstagen von JavaScript waren Webanwendungen mit mehreren Frames oder Fenstern weit verbreitet. Mittlerweile hat sich der Webdesign-Konsens stark gegen die Verwendung von Frames (aber nicht von Inline-Frames, d.h. IFrames) gewandt, und man sieht auch nicht mehr so häufig Websites, die interagierende Fenster verwenden.
14.8 Mehrere Fenster und Frames |
321
clientseitiges JavaScript
Neben diesen drei Argumenten ist der Rückgabewert des onerror-Handlers wichtig. Wenn der onerror-Handler true zurückliefert, sagt er dem Browser, dass er den Fehler behandelt hat und keine weiteren Handlungen mehr erforderlich sind – anders gesagt, der Browser soll seine eigene Fehlermeldung nicht mehr anzeigen.
491-0.book Seite 322 Mittwoch, 4. April 2007 9:55 09
e-bol.net Bevor wir in die Betrachtung von mehreren Fenstern und Frames einsteigen, macht es Sinn, dass wir uns noch einmal die Implikationen der Same-Origin-Sicherheitsrichtlinie ansehen, die in Abschnitt 13.8.2 betrachtet wurde. Gemäß dieser Sicherheitsrichtlinie kann JavaScript-Code nur mit Inhalten von dem gleichen Webserver interagieren, von dem das Dokument stammt, in das der JavaScript-Code eingebettet ist. Jeder Versuch, Inhalte oder Eigenschaften eines Dokuments von einem anderen Webserver zu lesen, schlägt fehl. Das bedeutet beispielsweise, dass Sie ein JavaScript-Programm schreiben können, das seine eigene Website indiziert, um eine Liste aller Links zu erzeugen, die auf der Site erscheinen. Aber Sie können das Programm nicht so erweitern, dass es diesen Links folgt und die anderen Sites indiziert: Ihr Versuch, eine Liste der Links in einem externen Dokument zu erhalten, schlägt fehl. Später werden Sie in Beispiel 14-7 Code sehen, der aufgrund der Same Origin Policy nicht funktioniert.
14.8.1 Beziehungen zwischen Frames Sie werden sich sicher daran erinnern, dass die open( )-Methode des Window-Objekts ein neues Window-Objekt zurückliefert, das das neu erzeugte Fenster repräsentiert, und dass dieses neue Fenster eine opener-Eigenschaft hat, die auf das ursprüngliche Fenster zurückweist. Auf diese Weise können zwei Fenster aufeinander verweisen und jeweils die Eigenschaften des anderen lesen und die Methoden des anderen aufrufen. Das Gleiche ist mit Frames möglich. Jeder Frame in einem Fenster kann auf alle anderen Frames über die frames-, parent- und top-Eigenschaften des Window-Objekts zugreifen. Der JavaScript-Code in einem beliebigen Fenster oder Frame kann auf sein eigenes Fenster oder seinen eigenen Frame mit window oder self verweisen. Da jedes Fenster und jeder Frame das globale Objekt für den eigenen Code ist, ist eine Verwendung von window oder self nur dann erforderlich, wenn Sie auf das globale Objekt selbst verweisen müssen. Wenn Sie auf eine Methode oder eine Eigenschaft in diesem Fenster oder Frame verweisen möchten, ist es nicht erforderlich (aber in stilistischer Hinsicht manchmal hilfreich), dass Sie dem Eigenschafts- oder Methodennamen window oder self voranstellen. Jedes Fenster hat eine frames-Eigenschaft. Diese Eigenschaft verweist auf ein Array mit Window-Objekten, die jeweils einen Frame repräsentieren, der in dem Fenster enthalten ist. (Wenn ein Fenster keine Frames hat, ist das Array frames[] leer und frames.length gleich null.) Ein Fenster (oder ein Frame) kann seinen ersten Frame also mit frames[0] referenzieren, seinen zweiten Frame mit frames[1] und so weiter. Gleichermaßen kann JavaScript-Code, der in einem Fenster läuft, auf den dritten Subframe seines zweiten Frames folgendermaßen verweisen: frames[1].frames[2]
Jedes Window-Objekt hat außerdem eine parent-Eigenschaft, die auf das WindowObjekt verweist, in dem es enthalten ist. Der erste Frame in einem Fenster kann auf einen Geschwisterframe (hier den zweiten Frame im Fenster) also so verweisen: parent.frames[1]
322 | Kapitel 14: Browserfenster skripten
491-0.book Seite 323 Mittwoch, 4. April 2007 9:55 09
e-bol.net Wenn ein Window-Objekt ein Toplevel-Fenster und kein Frame ist, verweist parent einfach auf das Fenster selbst: parent == self;
// Gilt für jedes Toplevel-Fenster
Frames werden üblicherweise mit - und -Elementen erzeugt. In HTML 4 kann auch das -Element verwendet werden, um in einem Dokument einen Inline-Frame zu erzeugen. Aus JavaScript-Sicht sind Frames, die mit erzeugt wurden, mit Frames identisch, die mit und erzeugt wurden. Alles, was hier gesagt wird, gilt für beide Arten von Frames. Abbildung 14-3 illustriert diese Beziehungen zwischen Frames und zeigt, wie Code, der in einem beliebigen Frame läuft, auf jeden anderen Frame über die Eigenschaften frames, parent und top verweisen kann. Die Abbildung zeigt ein Browserfenster, das zwei Frames enthält, die aufeinandergestapelt sind. Der zweite Frame (der untere, größere) enthält seinerseits drei nebeneinanderliegende Subframes.
14.8.2 Fensternamen und Frame-Namen Das zweite, optionale Argument für die Methode Window.open( ), über das wir bereits gesprochen haben, ist ein Name für das neu erzeugte Fenster. Wenn Sie mit dem HTMLElement einen neuen Frame erzeugen, können Sie einen Namen mit dem Attribut name erzeugen. Ein wichtiger Grund, Namen für Fenster und Frames anzugeben, ist, dass diese Namen als Wert des target-Attributs von - und -Elementen verwendet werden können, um dem Browser zu sagen, wo das Ergebnis einer Link-Aktivierung oder einer Formular-Übermittlung angezeigt werden soll. Wenn Sie zwei Fenster haben, von denen das eine inhaltsverzeichnis und das andere hauptfenster heißt, könnten Sie im inhaltsverzeichnis-Fenster HTML wie das folgende haben: Kapitel 1, Einführung
Der Browser lädt die angegebene URL, wenn der Benutzer auf diesen Hyperlink klickt, aber anstatt die URL im gleichen Fenster wie den Link anzuzeigen, zeigt er sie in dem Fenster mit dem Namen hauptfenster an. Wenn es kein Fenster mit dem Namen hauptfenster gibt, erzeugt ein Klick auf den Link ein Fenster mit diesem Namen und lädt darin die angegebene URL.
14.8 Mehrere Fenster und Frames |
323
clientseitiges JavaScript
Wenn ein Frame in einem anderen Frame enthalten ist, der in einem Toplevel-Fenster enthalten ist, kann dieser Frame auf das Toplevel-Fenster über parent.parent verweisen. Die Eigenschaft top ist allerdings eine allgemeine Abkürzung: Egal wie tief ein Frame einbettet ist, verweist seine top-Eigenschaft auf das einschließende Fenster auf der obersten Ebene. Wenn ein Window-Objekt ein Toplevel-Fenster repräsentiert, verweist top einfach auf dieses Fenster selbst. Bei Frames, die unmittelbare Kinder eines Toplevel-Fensters sind, ist die Eigenschaft top mit der Eigenschaft parent identisch.
491-0.book Seite 324 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Abbildung 14-3: Beziehungen zwischen Frames
Die Attribute target und name sind Teil von HTML und funktionieren ohne die Intervention von JavaScript. Aber es gibt auch JavaScript-bezogene Gründe, Ihren Frames Namen zu geben. Erinnern Sie sich daran, dass jedes Window-Objekt ein frames[]-Array hat, das Referenzen auf jeden seiner Frames enthält. Dieses Array enthält alle Frames in einem Fenster (oder Frame), egal ob sie Namen haben oder nicht. Wenn Sie einem Frame einen Namen geben, wird jedoch auch eine Referenz auf diesen Frame in einer neuen Eigenschaft des Eltern-Window-Objekts gespeichert. Der Name der neuen Eigenschaft entspricht dem Namen des Frames. Deswegen können Sie einen Frame mit HTML wie diesem erzeugen:
Jetzt können Sie auf diesen Frame so aus einem anderen Geschwister-Frame verweisen: parent.inhaltsverzeichnis
324 | Kapitel 14: Browserfenster skripten
491-0.book Seite 325 Mittwoch, 4. April 2007 9:55 09
e-bol.net Das macht Ihren Code besser lesbar und verstehbar als die Verwendung (und das Verlassen auf) hartcodierte Array-Indizes, wie Sie es bei einem unbenannten Frame machen müssten: parent.frames[1]
14.8.3 JavaScript in interagierenden Fenstern In Kapitel 13 haben Sie gelernt, dass das Window-Objekt als das globale Objekt für clientseitigen JavaScript-Code dient und dass das Fenster als Ausführungskontext für den gesamten JavaScript-Code dient, den es enthält. Das gilt auch für Frames: Jeder Frame ist ein unabhängiger JavaScript-Ausführungskontext. Weil jedes Window-Objekt sein eigenes globales Objekt ist, definiert jedes Fenster seinen eigenen Namensraum und seine eigene Menge globaler Variablen. Betrachtet man sie aus der Perspektive mehrerer Frames oder Fenster, scheinen globale Variablen dann aber doch nicht mehr so global zu sein! Obwohl jedes Fenster und jeder Frame einen unabhängigen JavaScript-Ausführungskontext definiert, bedeutet das nicht, dass der JavaScript-Code, der in einem Fenster läuft, von Code isoliert ist, der in anderen Fenstern läuft. Code, der in dem einen Frame läuft, hat am Anfang seiner Geltungsbereichskette ein anderes Window-Objekt als Code, der in einem anderen Frame läuft. Aber der Code beider Frames wird vom gleichen JavaScript-Interpreter in der gleichen JavaScript-Umgebung ausgeführt. Wie Sie gesehen haben, kann ein Frame auf andere Frames über die Eigenschaften frames, parent und top verweisen. Obwohl der JavaScript-Code in separaten Frames also mit unterschiedlichen Geltungsbereichsketten ausgeführt wird, kann der Code in einem Frame trotzdem auf die Variablen und Funktionen zugreifen, die von Code in einem anderen Frame definiert werden. Nehmen Sie beispielsweise an, dass Code in Frame A eine Variable namens i definiert: var i = 3;
Diese Variable ist nichts anderes als eine Eigenschaft des globalen Objekts – eine Eigenschaft des Window-Objekts. Code in Frame A kann auf die Variable explizit mit einem der folgenden Ausdrücke verweisen: window.i self.i
Nehmen Sie jetzt an, dass Frame A einen Geschwister-Frame B hat, der den Wert der Variablen i setzen möchte, die vom Code in Frame A definiert wurde. Wenn Frame B einfach eine Variable i setzt, führt das einfach nur dazu, dass er eine neue Eigenschaft in
14.8 Mehrere Fenster und Frames |
325
clientseitiges JavaScript
Beispiel 14-7 am Ende dieses Kapitels verwendet diese Technik, um Frames zu referenzieren.
491-0.book Seite 326 Mittwoch, 4. April 2007 9:55 09
e-bol.net seinem eigenen Window-Objekt erzeugt. Stattdessen muss er also explizit mit Code wie diesem auf die Eigenschaft i in seinem Geschwister-Frame verweisen: parent.frames[0].i = 4;
Erinnern Sie sich daran, dass das Schlüsselwort function, das Funktionen definiert, genau wie das Schlüsselwort var nur eine Variable deklariert. Wenn JavaScript-Code in Frame A eine Funktion f deklariert, ist diese Funktion nur in Frame A definiert. Code in Frame A kann f folgendermaßen aufrufen: f( );
Aber Code in Frame B muss auf f als Eigenschaft des Window-Objekts von Frame A verweisen: parent.frames[0].f( );
Wenn der Code in Frame B diese Funktion häufig verwenden muss, könnte er die Funktion einer Variablen in Frame B zuweisen, damit er etwas bequemer auf sie verweisen kann: var f = parent.frames[0].f;
Jetzt kann Code in Frame B die Funktion als f( ) aufrufen, genau wie es der Code in Frame A macht. Wenn Sie Funktionen auf diese Weise zwischen Frames oder Fenstern teilen, ist es sehr wichtig, die Regeln der lexikalischen Geltung im Kopf zu behalten. Eine Funktion wird in dem Geltungsbereich ausgeführt, in dem sie definiert wurde, nicht in dem, in dem sie aufgerufen wurde. Unter den Voraussetzungen des vorangehenden Beispiels heißt das also, dass globale Variablen, wenn die Funktion f auf sie verweist, als Eigenschaften von Frame A nachgeschlagen werden, selbst wenn die Funktion aus Frame B aufgerufen wird. Wenn Sie darauf nicht sorgfältig achten, kann das dazu führen, dass sich Ihre Programme auf unerwartete und verwirrende Weise verhalten. Nehmen Sie beispielsweise an, Sie definieren die folgende Funktion im -Abschnitt eines Dokuments mit mehreren Frames und wollen sie zur Debugging-Unterstützung einsetzen: function debug(msg) { alert("Debugging-Meldung von Frame: " + name + "\n" + msg); }
Der JavaScript-Code in jedem Ihrer Frames kann auf diese Funktion über top.debug( ) verweisen. Aber jedes Mal, wenn diese Funktion aufgerufen wird, schlägt sie die Variable name im Kontext des Toplevel-Fensters nach, in dem die Funktion definiert wurde, und nicht im Kontext des Frames, in dem sie aufgerufen wurde. Deswegen hat die Debugging-Meldung immer den Namen des Toplevel-Fensters statt den Namen des Frames, der die Meldung gesendet hat, wie es beabsichtigt war. Denken Sie daran, dass Konstruktoren auch Funktionen sind. Wenn Sie also mit einer Konstruktorfunktion und einem damit verknüpften Prototyp-Objekt eine Klasse von
326 | Kapitel 14: Browserfenster skripten
491-0.book Seite 327 Mittwoch, 4. April 2007 9:55 09
e-bol.net Objekten definieren, ist diese Klasse nur für ein einziges Fenster definiert. Erinnern Sie sich an die Klasse Komplex, die in Kapitel 9 definiert wurde, und betrachten Sie folgendes HTML-Dokument mit mehreren Frames:
clientseitiges JavaScript
JavaScript-Code in den Dateien frame1.html und frame2.html kann Komplex-Objekte nicht mit einem Ausdruck wie diesem erzeugen: var c = new Komplex(1,2);
// Funktioniert in keinem der Frames
Stattdessen muss Code in diesen Daten die Konstruktorfunktion explizit referenzieren: var c = new top.Komplex(3,4);
Alternativ kann Code in beiden Frames eine eigene Variable definieren, um bequemer auf die Konstruktorfunktion verweisen zu können: var Komplex = top.Komplex; var c = new Komplex(1,2);
Im Unterschied zu benutzerdefinierten Konstruktoren sind vordefinierte Konstruktoren automatisch in allen Fenstern vordefiniert. Beachten Sie allerdings, dass jedes Fenster eine separate Kopie des Konstruktors und eine separate Kopie des Prototyp-Objekts des Konstruktors besitzt. Beispielsweise hat jedes Fenster eine eigene Kopie des String( )Konstruktors und des String.prototype-Objekts. Wenn Sie eine neue Methode für die Manipulation von JavaScript-Strings schreiben und diese dann zu einer Methode der Klasse String machen, indem Sie sie dem String.prototype-Objekt des aktuellen Fensters zuweisen, können alle Strings in diesem Fenster die neue Methode verwenden. Aber Strings, die in anderen Fenstern definiert werden, können nicht auf die neue Methode zugreifen. Beachten Sie allerdings, dass es keine Rolle spielt, welches Fenster die Referenz auf den String hält. Es zählt nur das Fenster, in dem der String tatsächlich erzeugt wurde.
14.9 Beispiel: Eine Navigationsleiste in einem Frame Dieses Kapitel schließt mit einem Beispiel, das viele der wichtigeren der hier beschriebenen Scripting-Techniken illustriert: • Die aktuelle URL mit location.href abfragen und neue Dokumente laden, indem die Eigenschaft location gesetzt wird • Die back( )- und forward( )-Methoden des History-Objekts verwenden • setTimeout( ) verwenden, um den Aufruf einer Funktion hinauszuschieben
14.9 Beispiel: Eine Navigationsleiste in einem Frame |
327
491-0.book Seite 328 Mittwoch, 4. April 2007 9:55 09
e-bol.net • Mit window.open( ) ein neues Browserfenster öffnen • JavaScript in einem Frame verwenden, um mit einem anderen Frame zu interagieren • Mit den Einschränkungen klarkommen, die die Same Origin Policy mit sich bringt Beispiel 14-7 ist ein Skript und ein einfaches HTML-Formular, das für die Verwendung in einem Dokument mit Frames gedacht ist. Es erzeugt eine einfache Navigationsleiste in einem Frame und verwendet diese Leiste, um den Inhalt eines anderen Frames zu steuern. Die Navigationsleiste schließt einen Zurück-Button, einen Vor-Button und ein Textfeld ein, in das der Benutzer eine URL eingeben kann. Sie können die Navigationsleiste am unteren Rand von Abbildung 14-4 sehen.
Abbildung 14-4: Eine Navigationsleiste
Beispiel 14-7 definiert JavaScript-Funktionen in einem -Element und Buttons und ein Textfeld für die URL-Eingabe in einem -Element. Es nutzt HTML-Event-Handler, um diese Funktionen aufzurufen, wenn die Buttons angeklickt werden. Event-Handler und HTML-Formulare habe ich noch nicht ausführlich behandelt. Aber diese Aspekte des Codes sind hier nicht wichtig. In diesem Beispiel werden Sie Anwendungen der Locationund History-Objekte sowie der Funktionen setTimeout( ) und Window.open( ) sehen. Sie werden sehen, wie der JavaScript-Code im Frame mit der Navigationsleiste über den
328 | Kapitel 14: Browserfenster skripten
491-0.book Seite 329 Mittwoch, 4. April 2007 9:55 09
e-bol.net Namen auf den anderen Frame verweist, und werden außerdem die Verwendung von try/catch-Blöcken an Orten sehen, wo die Same Origin Policy dafür verantwortlich sein könnte, dass der Code fehlschlägt. Beispiel 14-7: Eine Navigationsleiste clientseitiges JavaScript
Der Code in dieser Datei steuert den Inhalt im Frame namens "main". --> // Diese Funktion wird vom Zurück-Button der Navigationsleiste aufgerufen. function zurueck( ) { // Erst das Eingabefeld für die URL im Formular leeren. document.navbar.url.value = ""; // Dann das History-Objekt des Haupt-Frames verwenden, um zurückzugehen. // Es sei denn, die Same Origin Policy kommt uns in die Quere. try { parent.main.history.back( ); } catch(e) { alert("Same Origin Policy blockiert History.back( ): " + e.message); } // Die URL des Dokuments anzeigen, zu dem wir zurückgegangen sind, wenn das möglich ist. // Dieser Aufruf von updateURL( ) muss hinausgezögert werden, damit er funktioniert. setTimeout(updateURL, 1000); } // Diese Funktion wird vom Vor-Button der Navigationsleiste aufgerufen. function vor( ) { document.navbar.url.value = ""; try { parent.main.history.forward( ); } catch(e) { alert("Same Origin Policy blockiert History.forward( ): "+e.message);} setTimeout(updateURL, 1000); } // Diese private Funktion wird von back( ) und forward( ) eingesetzt, um das URL-Textfeld // des Formulars zu aktualisieren. In der Regel verhindert die Same Origin Policy, dass // wir die location-Eigenschaft des Haupt-Frames abfragen. function aktualisiereURL( ) { try { document.navbar.url.value = parent.main.location.href; } catch(e) { document.navbar.url.value = ""; } }
14.9 Beispiel: Eine Navigationsleiste in einem Frame |
329
491-0.book Seite 330 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 14-7: Eine Navigationsleiste (Fortsetzung) // Hilfsfunktion: Wenn die URL nicht mit "http://" beginnt, fügen wir das hinzu. function repariere(url) { if (url.substring(0,7) != "http://") url = "http://" + url; return url; } // Diese Funktion wird vom Gehe-Button der Navigationsleiste aufgerufen und auch, // wenn der Benutzer das Formular abschickt. function gehe( ) { // Die angegebene URL in den Haupt-Frame laden. parent.main.location = repariere(document.navbar.url.value); } // Ein neues Fenster anzeigen und die vom Benutzer angegebene URL in ihm anzeigen. function zeigeInNeuemFenster( ) { // Wir öffnen ein gewöhnliches, unbenanntes, vollständiges Fenster, deswegen müssen // wir nur das URL-Argument angeben. Nachdem das Fenster geöffnet wurde, hat unsere // Navigationsleiste keine Kontrolle mehr darüber. window.open(repariere(document.navbar.url.value)); } URL:
330 | Kapitel 14: Browserfenster skripten
491-0.book Seite 331 Mittwoch, 4. April 2007 9:55 09
e-bol.net
KAPITEL 15
Dokumente skripten
Clientseitiges JavaScript dient dazu, statische HTML-Dokumente in interaktive Webanwendungen zu verwandeln. Das Scripting des Inhalts von Webseiten ist die Raison d’Être von JavaScript. Dieses Kapitel – das wichtigste in Teil II – erklärt, wie man das macht. Jedes Fenster (oder jeder Frame) eines Webbrowsers zeigt ein HTML-Dokument an. Das Window-Objekt, das dieses Fenster repräsentiert, hat eine document-Eigenschaft, die auf ein Document-Objekt verweist. Dieses Document-Objekt ist der Gegenstand dieses Kapitels, das mit einer Betrachtung der Eigenschaften und Methoden des DocumentObjekts selbst beginnt. Diese sind interessant, aber sie sind nur der Anfang. Interessanter als das Document-Objekt selbst sind die Objekte, die den Inhalt des Dokuments repräsentieren. HTML-Dokumente können Text, Bilder, Hyperlinks, Formularelemente und so weiter enthalten. JavaScript-Code kann auf die Objekte zugreifen, die die einzelnen Dokumentelemente repräsentieren, und sie manipulieren. Direkt auf die Objekte zugreifen zu können, die den Inhalt eines Dokuments repräsentieren, eröffnet sehr viele Möglichkeiten, aber das ist auch der Punkt, an dem die Sache beginnt, kompliziert zu werden. Ein Document Object Model (Dokumentobjektmodell) oder DOM ist eine API, die definiert, wie auf die Objekte zugegriffen wird, aus denen ein Dokument besteht. Das W3C definiert ein Standard-DOM, das von allen modernen Webbrowsern hinreichend gut unterstützt wird. Unglücklicherweise war das nicht immer der Fall. Die Geschichte der clientseitigen JavaScript-Programmierung ist eigentlich die Geschichte der (manchmal auf inkompatible Weise erfolgenden) Evolution des DOMs. In den Anfangstagen des Webs war Netscape der führende Browserhersteller und definierte die APIs für das clientseitige Scripting. Netscape 2 und 3 unterstützten ein einfaches DOM, das nur Zugriff auf besondere Dokumentelemente wie Links, Grafiken und Formularelemente bot. Dieses Alt-DOM wurde von allen Browser-Herstellern übernommen und als »Level 0 DOM« formell in den W3C-Standard integriert. Das Alt-DOM funktioniert immer noch in allen Browsern, und es ist das, das ich zuerst behandeln werde.
|
331
491-0.book Seite 332 Mittwoch, 4. April 2007 9:55 09
e-bol.net Mit dem Internet Explorer 4 übernahm Microsoft die Kontrolle des Webs. IE 4 hatte ein revolutionäres neues DOM: Es bot Zugriff auf alle Elemente in einem Dokument und ermöglichte es Ihnen, diese auf interessante Weise zu skripten. Es ermöglicht Ihnen sogar, den Text eines Dokuments zu ändern, und lässt die Absätze des Dokuments neu einfließen, wenn das erforderlich ist. Microsofts API ist als das IE 4 DOM bekannt. Es wurde nie standardisiert, und der IE 5 und spätere Versionen übernahmen das W3C DOM, bewahrten aber Unterstützung für das IE 4 DOM. Teile des IE 4 DOMs wurden von anderen Browsern übernommen und werden im Web immer noch verwendet. Ich werde es am Ende des Kapitels erklären, nachdem ich die standardmäßige Alternative behandelt habe. Netscape 4 wählte einen ganz anderen Ansatz für das DOM, der auf dynamisch positionierbaren skriptbaren Elementen basierte, die als Layer bezeichnet wurden. Dieses Netscape 4 DOM war eine Evolutionssackgasse. Es wurde nur in Netscape 4 unterstützt und in den Mozilla- und Firefox-Browsern fallengelassen, die sich aus der Netscape-Codebasis entwickelten. Die Behandlung des Netscape 4 DOMs wurde in dieser Auflage aus dem Buch entfernt. Der Hauptteil dieses Kapitels behandelt den W3C DOM-Standard. Beachten Sie allerdings, dass ich hier nur die Kernteile des Standards vorstelle. Das Scripting von Dokumentinhalten ist der Hauptgrund für clientseitiges JavaScript, und die meisten nachfolgenden Kapitel dieses Buchs sind eigentlich Fortsetzungen dieses Kapitels. Kapitel 16 behandelt den W3C DOM-Standard für die Arbeit mit CSS-Styles und -Stylesheets. Kapitel 17 behandelt den W3C DOM-Standard für das Event-Handling (sowie die alten und IE-spezifischen Techniken, diese Dinge zu erledigen). Kapitel 18 erklärt das DOM für die Interaktion mit HTML-Formularelementen, und Kapitel 22 erklärt, wie man die -Elemente eines HTML-Dokuments skriptet und clientseitigen Webseiten geskriptete Grafiken hinzufügt. Das Level 0 DOM definiert nur eine einzige Document-Klasse, und dieses Kapitel verweist häufig informell als Document-Objekt darauf. Das W3C DOM definiert jedoch eine Document API, die eine allgemeine Dokumentfunktionalität stellt, die auf HTMLund XML-Dokumente anwendbar ist, und definiert daneben eine spezialisierte HTMLDocument API, die HTML-spezifische Eigenschaften und Methoden hinzufügt. Das Referenzmaterial in Part IV dieses Buchs folgt der W3C-Konvention: Wenn Sie nach HTML-spezifischen Document-Features suchen, schauen Sie unter HTMLDocument nach. Die meisten der Features von Level 0 DOM sind HTML-spezifisch und müssen unter HTMLDocument nachgeschlagen werden, auch wenn dieses Kapitel auf sie als Eigenschaften und Methoden von Document verweist.
332 | Kapitel 15: Dokumente skripten
491-0.book Seite 333 Mittwoch, 4. April 2007 9:55 09
e-bol.net
15.1 Dynamischer Dokumentinhalt
var heute = new Date( ); document.write("
Dokumentzugriff um: " + heute.toString( ));
Achten Sie jedoch darauf, dass Sie mit der Methode write( ) nur HTML in das aktuelle Dokument ausgeben können, während das Dokument geparst wird. Das heißt, dass Sie document.write( ) nur aus Toplevel-Code in -Tags aufrufen können, weil diese Skripten als Teil des Parsing-Vorgangs für das Dokument ausgeführt werden. Wenn Sie einen document.write( )-Aufruf in eine Funktionsdefinition packen und diese Funktion dann von einem Event-Handler aus ausrufen, funktioniert das nicht wie erwartet – stattdessen löschen Sie das aktuelle Dokument und das Skript, das es enthält! (Warum das passiert, werden Sie in Kürze sehen.) document.write( ) fügt an der Stelle Text ein HTML-Dokument ein, an der sich das -Tag befindet, das den Aufruf der Methode enthält. Wenn ein -Tag das Attribut defer trägt, darf es überhaupt keine Aufrufe von document.write( ) enthalten. Das Attribut defer sagt dem Webbrowser, dass es sicher ist, die Ausführung des Skripts
so lange aufzuschieben, bis das Dokument vollständig geladen wurde. Und wenn das passiert ist, ist es zu spät, um mit document.write( ) Inhalt in das Dokument einzufügen, während es geparst wird. Mit der Methode write( ) Dokumentinhalt zu generieren, während das Dokument geparst wird, war eine sehr verbreitete JavaScript-Programmiertechnik. Das W3C DOM ermöglicht es Ihnen jetzt (unter Einsatz von Techniken, die Sie später kennenlernen werden), in einen beliebigen Teil des Dokuments Inhalte einzufügen, nachdem es geparst wurde. Trotzdem ist die Verwendung von document.write( ) immer noch sehr verbreitet. Sie können die write( )-Methode (in Verbindung mit den open( )- und close( )-Methoden) des Document-Objekts auch verwenden, um vollständig neue Dokumente in anderen Fenstern oder Frames zu erzeugen. Obwohl Sie aus einem Event-Handler heraus nicht brauchbar in das aktuelle Dokument schreiben können, gibt es keinen Grund, nicht in andere Fenster oder Frames schreiben zu können. Beispielsweise könnten Sie ein Pop-up-Fenster erzeugen und mit Code wie dem folgenden etwas HTML in es schreiben:
15.1 Dynamischer Dokumentinhalt |
333
clientseitiges JavaScript
Beginnen wir die Erforschung des Document-Objekts mit seiner write( )-Methode, die es Ihnen ermöglicht, Inhalt in das Dokument zu schreiben. Diese Methode ist Teil des AltDOMs und existiert seit den frühesten Versionen von JavaScript. document.write( ) kann auf zweierlei Weise verwendet werden. Die erste und einfachste Möglichkeit ist die Verwendung in einem Skript, um HTML in das Dokument auszugeben, das gerade geparst wird. Betrachten Sie den folgenden Code, der write( ) einsetzt, um einem ansonsten statischen HTML-Dokument das aktuelle Datum hinzuzufügen:
491-0.book Seite 334 Mittwoch, 4. April 2007 9:55 09
e-bol.net // Diese Funktion öffnet ein Pop-up-Fenster. Rufen Sie sie aus einem Event-Handler // auf, da das Pop-up ansonsten wahrscheinlich blockiert wird. function hallo( ) { var w = window.open( ); // Ein neues Fenster ohne Inhalt erzeugen var d = w.document; // Sein Document-Objekt abrufen d.open( ); // Ein neues Dokument beginnen (optional) d.write("Hallo Welt!"); // Den Dokumentinhalt ausgeben d.close( ); // Das Dokument beenden }
Um ein neues Dokument zu erzeugen, rufen Sie zunächst die open( )-Methode des Document-Objekts auf. Dann rufen Sie beliebig oft write( ) auf, um den Inhalt des Dokuments zu erzeugen. Abschließend rufen Sie die close( )-Methode des Document-Objekts auf, um anzuzeigen, dass Sie fertig sind. Dieser letzte Schritt ist wichtig. Wenn Sie vergessen, das Dokument zu schließen, beendet der Browser die Animation nicht, die er anzeigt, wenn er ein Dokument lädt. Außerdem kann es sein, dass der Browser das HTML puffert, das Sie geschrieben haben. Es ist nicht erforderlich, dass die gepufferte Ausgabe angezeigt wird, bis Sie das Dokument explizit beenden, indem Sie close( ) aufrufen. Im Unterschied zum close( )-Aufruf, der erforderlich ist, ist der open( )-Aufruf optional. Wenn Sie die Methode write( ) auf einem Dokument aufrufen, das bereits geschlossen wurde, öffnet JavaScript implizit ein neues HTML-Dokument, als hätten Sie die Methode open( ) aufgerufen. Das erklärt, was passiert, wenn Sie document.write( ) aus einem Event-Handler im gleichen Dokument aufrufen: JavaScript öffnet ein neues Dokument. Bei diesem Vorgang wird das aktuelle Dokument (und sein Inhalt einschließlich Skripten und Event-Handlern) aber verworfen. Eine allgemeine Faustregel ist deswegen, dass ein Dokument auf sich selbst nie write( ) aus einem Event-Handler aufrufen soll. Ein paar abschließende Bemerkungen zur write( )-Methode. Erstens wissen viele Leute nicht, dass die Methode write( ) mehrere Argumente akzeptiert. Wenn Sie mehrere Argumente übergeben, werden diese nacheinander ausgegeben – so, als wären sie verkettet worden. Statt document.write("Hallo, "
+ benutzer + " Willkommen bei meinem Blog!");
könnten Sie auch Folgendes schreiben: var begruessung = "Hallo, "; var willkommen = " Willkommen bei meinem Blog!"; document.write(begruessung, benutzer, willkommen);
Der zweite beachtenswerte Punkt zur Methode write( ) ist, dass das Document-Objekt auch eine writeln( )-Methode unterstützt, die mit der write( )-Methode in jeder Hinsicht identisch ist, allerdings nach Ausgabe der Argumente einen Zeilenumbruch anhängt. Das kann beispielsweise hilfreich sein, wenn man in einem -Element vorformatierten Text ausgibt. Bei HTMLDocument in Teil IV finden Sie vollständige Informationen zu den Methoden write( ), writeln( ), open( ) und close( ).
334 | Kapitel 15: Dokumente skripten
491-0.book Seite 335 Mittwoch, 4. April 2007 9:55 09
e-bol.net
15.2 Document-Eigenschaften Nachdem wir uns die Alt-Methoden des Document-Objekts angesehen haben, wenden wir uns jetzt seinen Alt-Eigenschaften zu: bgColor
cookie
Eine besondere Eigenschaft, die es JavaScript-Programmen ermöglicht, HTTPCookies zu lesen und zu schreiben. Diese Eigenschaft ist Gegenstand eines eigenen Kapitels, Kapitel 19. domain
Eine Eigenschaft, die es sich gegenseitig vertrauenden Webservern in der gleichen Internet-Domain ermöglicht, gemeinsam die Same Origin Policy-Sicherheitseinschränkung für Interaktionen zwischen ihren Webseiten zu lockern (siehe Abschnitt 13.8.2). lastModified
Ein String, der das Veränderungsdatum des Dokuments enthält. location
Ein veraltetes Synonym für die Eigenschaft URL. referrer
Die URL des Dokuments, das einen eventuellen Link enthielt, über den der Browser zum aktuellen Dokument gelangt ist. title
Der Text zwischen den - und -Tags dieses Dokuments. URL
Ein String, der die URL angibt, von der das Dokument geladen wurde. Der Wert dieser Eigenschaft entspricht dem Wert der location.href-Eigenschaft des WindowObjekts, es sei denn, es fand eine Serverumleitung statt. Einige dieser Eigenschaften bieten Informationen zum Dokument als Ganzem. Sie können Code wie den folgenden an das Ende jeder Ihrer Webseiten setzen, um eine nützliche automatische Fußzeile zu erzeugen, die es Benutzern ermöglicht zu beurteilen, wie aktuell (oder veraltet) ein Dokument ist, wenn es gedruckt wird: Dokument: document.write(document.title); URL: document.write(document.URL); Letzte Aktualisierung: document.write(document.lastModified);
referrer ist eine weitere interessante Eigenschaft: Sie enthält die URL des Dokuments,
von dem der Benutzer zum aktuellen Dokument gelangt ist. Sie können diese Eigenschaft
15.2 Document-Eigenschaften |
335
clientseitiges JavaScript
Die Hintergrundfarbe des Dokuments. Diese Eigenschaft entspricht dem (veralteten) bgcolor-Attribut des -Tags.
491-0.book Seite 336 Mittwoch, 4. April 2007 9:55 09
e-bol.net nutzen, um tiefe Links in Ihre Site zu verhindern. Wenn Sie wollen, dass all Ihre Besucher über Ihre Homepage ankommen, können Sie sie umleiten, indem Sie an den Anfang aller Seiten außer der Homepage folgenden Code stellen: // Bei einer Verlinkung durch eine externe Seite erst zur Homepage gehen if (document.referrer == "" || document.referrer.indexOf("meinesite.com") == -1) window.location = "http://home.meinesite.com";
Sie dürfen diesen Trick natürlich nicht als eine Sicherheitsmaßnahme betrachten. Offensichtlicherweise funktioniert er bei Benutzern nicht, die in ihren Webbrowsern JavaScript deaktiviert haben. Eine letzte interessante Document-Eigenschaft ist bgColor. Diese Eigenschaft entspricht einem HTML-Attribut, dessen Verwendung als veraltet gilt, hier aus historischen Gründen aber erwähnt wird. Die Änderung der Hintergrundfarbe eines Dokuments war eine der ersten Anwendungen von clientseitigem JavaScript. Selbst sehr, sehr alte Webbrowser ändern die Hintergrundfarbe eines Dokuments, wenn Sie document.bgColor auf einen HTML-Farbstring wie »pink« oder »#FFAAAA« setzen. Bei HTMLDocument in Teil IV finden Sie vollständige Informationen zu den Alt-Eigenschaften des Document-Objekts. Das Document-Objekt hat noch weitere wichtige Eigenschaften, deren Werte Arrays mit Dokumentobjekten sind. Diese Document-Sammlungen sind Gegenstand des nächsten Abschnitts.
15.3 Alt-DOM: Dokumentobjekt-Sammlungen Die Liste der Eigenschaften des Document-Objekts im vorangehenden Abschnitt hat eine wichtige Kategorie von Eigenschaften ausgespart: Dokumentobjekt-Sammlungen. Die Eigenschaften mit Array-Werten sind das Herz des Alt-DOMs. Das sind die Eigenschaften, die Ihnen Zugriff auf besondere Elemente im Dokument geben: anchors[]
Ein Array mit Anchor-Objekten, die die Anker in einem Dokument repräsentieren. (Ein Anker ist eine benannte Position im Dokument. Sie wird mit einem -Tag erzeugt, das ein name-Attribut anstelle eines href-Attributs hat.) Die name-Eigenschaft eines Anchor-Objekts enthält den Wert des name-Attributs. In Teil IV finden Sie vollständige Informationen zum Anchor-Objekt. applets[]
Ein Array mit Applet-Objekten, die die Java-Applets im Dokument repräsentieren. Applets werden in Kapitel 23 betrachtet.
336 | Kapitel 15: Dokumente skripten
491-0.book Seite 337 Mittwoch, 4. April 2007 9:55 09
e-bol.net forms[]
images[]
Ein Array mit Image-Objekten, die die -Elemente im Dokument repräsentieren. Die src-Eigenschaft eines Images kann gelesen und geschrieben werden. Wird dieser Eigenschaft eine URL zugewiesen, veranlasst das den Browser, diese neue Grafik zu lesen und anzuzeigen (in älteren Browsern muss die neue Grafik die gleiche Größe haben wie die alte). Das Scripting der src-Eigenschaft eines Image-Objekts ermöglicht Rollover-Effekte und einfache Grafiken. Sie werden in Kapitel 22 behandelt. links[]
Ein Array mit Link-Objekten, die die Hyperlinks im Dokument repräsentieren. Hyperlinks werden in HTML mit -Tags und gelegentlich mit -Tags in clientseitigen Imagemaps erzeugt. Die href-Eigenschaft eines Link-Objekts entspricht dem href-Attribut des -Tags: Sie enthält die URL des Links. Link-Objekte machen über verschiedene Eigenschaften wie protocol, hostname und pathname auch die verschiedenen Teile einer URL verfügbar. In dieser Hinsicht entsprechen LinkObjekte dem Location-Objekt, das in Kapitel 14 behandelt wurde. Ein Link-Objekt löst einen onmouseover-Event-Handler aus, wenn der Mauszeiger über ihm schwebt, und einen onmouseout-Handler, wenn sich der Mauszeiger von ihm wegbewegt. Es löst einen onclick-Handler aus, wenn über einem Link die Maus geklickt wird. Wenn der Event-Handler false zurückliefert, folgt der Browser dem Link nicht. Vollständige Informationen zu Link-Objekten finden Sie in Teil IV. Wie ihre Namen anzeigen, sind diese Eigenschaften Sammlungen aller Links, Grafiken, Formulare usw., die in einem Dokument erscheinen. Ihre Elemente stehen in der gleichen Reihenfolge wie im Quellcode des Dokuments. document.forms[0] verweist zum Beispiel auf das erste -Element in einem Dokument und document.images[4] auf das fünfte -Element. Die Objekte, die in diesen Alt-DOM-Sammlungen enthalten sind, können geskriptet werden. Aber es ist wichtig, dass man versteht, dass keines von ihnen es ermöglicht, die Struktur des Dokuments zu ändern. Sie können Linkziele untersuchen und ändern, die Werte von Formularelementen lesen und schreiben und sogar eine Grafik gegen eine andere austauschen, aber den Text des Dokuments können Sie nicht ändern. Ältere Browser wie Netscape 2, 3 und 4 und IE 3 waren nicht dazu in der Lage, ein Dokument neu einfließen zu lassen (oder neu aufzubauen), nachdem es einmal geparst und ange-
15.3 Alt-DOM: Dokumentobjekt-Sammlungen |
337
clientseitiges JavaScript
Ein Array mit Form-Objekten, die die -Elemente im Dokument repräsentieren. Jedes Form-Objekt hat eine eigene Sammlungseigenschaft namens elements[], die Objekte enthält, die die Formularelemente repräsentieren, die im Formular enthalten sind. Form-Objekte lösen einen onsubmit-Event-Handler aus, bevor das Formular abgeschickt wird. Dieser Handler kann eine clientseitige Formularvalidierung durchführen: Liefert er false zurück, schickt der Browser das Formular nicht ab. Die form[]-Sammlung ist mit Sicherheit die wichtigste des Alt-DOMs, und Formulare und Formularelemente sind Gegenstand von Kapitel 18.
491-0.book Seite 338 Mittwoch, 4. April 2007 9:55 09
e-bol.net zeigt wurde. Aus diesem Grund ließ (und lässt) das Alt-DOM keine Dokumentänderungen zu, die einen Neuaufbau des Dokuments erforderlich machen. Beispielsweise schließt das Alt-DOM eine API für das Hinzufügen neuer -Elemente zu einem -Element ein. Das kann es, weil HTML-Formulare -Elemente als Aufklappmenüs anzeigen und sich der Aufbau des restlichen Formulars nicht ändert, wenn solchen Menüs neue Elemente hinzugefügt werden. Es gibt im Alt-DOM aber keine API, die es ermöglicht, einem Formular einen neuen Radiobutton oder einer Tabelle eine neue Zeile hinzuzufügen, weil derartige Änderungen einen Neuaufbau des Dokuments erforderlich machen würden.
15.3.1 Dokumentobjekten Namen geben Das Problem mit numerisch indizierten Dokumentobjekt-Sammlungen ist, dass ihre positionsbasierten Indizes etwas zerbrechlich sind: Kleine Dokumentänderungen, die die Ordnung der Elemente im Dokument ändern, können Code zerbrechen, der sich auf ihre Ordnung stützt. Eine robustere Lösung ist es, wichtigen Dokumentelementen Namen zuzuweisen und auf diese Elemente über den Namen zu verweisen. Im Alt-DOM können Sie das über die name-Attribute von Formularen, Formularelementen, Grafiken, Applets und Links machen. Wenn das Attribut name vorhanden ist, wird sein Wert verwendet, um das entsprechende Objekt über den Namen zu veröffentlichen. Nehmen Sie beispielsweise an, ein HTMLDokument enthält das folgende Formular:
Wenn wir hier annehmen, dass das das erste im Dokument ist, kann Ihr JavaScript-Code auf das resultierende Form-Objekt mit jedem der drei folgenden Ausdrücke verweisen: document.forms[0] document.forms.f1 document.forms["f1"]
// Auf das Formular über die Position im Dokument verweisen // Auf das Formular über den Namen als Eigenschaft verweisen // Auf das Formular über den Namen als Array-Index verweisen
Tatsächlich ist es sogar so, dass ein Form-, Image- oder Applet-Objekt (aber nicht Linkoder Anchor-Objekt) als benannte Eigenschaft des Dokuments selbst verfügbar ist, wenn die name-Eigenschaft des entsprechenden -, - oder -Objekts gesetzt wird. Sie können auf das Formular also auch so verweisen: document.f1
Den Elementen in einem Formular können ebenfalls Namen gegeben werden. Wenn Sie das name-Attribut eines Formularelements setzen, wird das Objekt, das es repräsentiert, als Eigenschaft des Form-Objekts selbst verfügbar gemacht. Nehmen Sie an, Sie haben ein Formular, das so aussieht:
338 | Kapitel 15: Dokumente skripten
491-0.book Seite 339 Mittwoch, 4. April 2007 9:55 09
e-bol.net ... ...
document.lieferung.plz
Eine abschließende Bemerkung zur Bennenung von Dokumentelementen ist unter dem Alt-DOM erforderlich: Was passiert, wenn zwei Dokumentelemente name-Attribute mit dem gleichen Wert haben? Wenn ein - und -Tab beispielsweise beide den name-Wert »n« haben, wird die Eigenschaft document.n zu einem Array, das Referenzen auf beide Elemente enthält. Üblicherweise sollten Sie sich Mühe geben sicherzustellen, dass Ihre name-Attribute eindeutig sind, damit diese Situation nicht aufkommen kann. Sie ist in einem Fall aber verbreitet. Bei HTML-Formularen verlangt die Konvention, dass verwandte Gruppen von Radiobuttons und Checkboxes den gleichen Namen haben. Wenn Sie das tun, wird dieser Name zu einer Eigenschaft des Form-Objekts, das diese Elemente enthält, und der Wert dieser Eigenschaft ist ein Array, das Referenzen auf die verschiedenen Radiobuttonoder Checkbox-Objekte enthält. Mehr dazu werden Sie in Kapitel 18 lernen.
15.3.2 Event-Handler auf Document-Objekten Um interaktiv zu sein, müssen ein HTML-Dokument und die Elemente in ihm auf Benutzerereignisse reagieren. In Kapitel 13 haben Sie schon etwas zu Event-Handlern und Events gelernt, und Sie haben eine Reihe von Beispielen gesehen, die einfache EventHandler verwenden. In diesem Kapitel gibt es viele weitere Beispiele von Event-Handlern, weil sie die Verknüpfung zwischen Dokumentelementen und JavaScript-Code sind. Eine vollständige Diskussion von Events und Event-Handlern hebe ich mir bis Kapitel 17 auf. Denken Sie jetzt nur daran, dass Event-Handler durch Attribute von HTML-Elementen wie onclick und onmouseover definiert werden. Die Werte dieser Attribute sollten Strings mit JavaScript-Code sein. Dieser Code wird ausgeführt, wenn das angegebene Event auf dem HTML-Element auftritt. Dokumentobjekte, auf die über Sammlungen wie document.links zugegriffen wird, haben Eigenschaften, die den Attributen des HTML-Tags entsprechen. Ein Link-Objekt hat beispielsweise eine href-Eigenschaft, die das href-Attribut des -Tag widerspiegelt. Das gilt auch für Event-Handler. Sie können einen onclick-Event-Handler für einen Hyperlink definieren, indem Sie das onclick-Attribut auf dem -Tag setzen oder indem Sie die onclick-Eigenschaft des Link-Objekts definieren. Betrachten Sie als weiteres Beispiel das onsubmit-Attribut des -Elements. In JavaScript hat ein Form-Objekt eine entsprechende onsubmit-Eigenschaft. (Denken Sie daran, dass HTML keine Groß-/Kleinschrei-
15.3 Alt-DOM: Dokumentobjekt-Sammlungen |
339
clientseitiges JavaScript
Auf das Texteingabefeld-Element können Sie dann mit dieser intuitiven Syntax verweisen:
491-0.book Seite 340 Mittwoch, 4. April 2007 9:55 09
e-bol.net bung berücksichtigt und Attribute in Großbuchstaben, Kleinbuchstaben oder einer Mischung von beidem geschrieben werden können. In JavaScript müssen alle EventHandler-Eigenschaften in Kleinbuchstaben geschrieben werden.) In HTML werden Event-Handler definiert, indem einem Event-Handler-Attribut ein String mit JavaScript-Code zugewiesen wird. Aber in JavaScript werden sie definiert, indem einer Event-Handler-Eigenschaft eine Funktion zugewiesen wird. Betrachten Sie das folgende und seinen onsubmit-Event-Handler: ...
Anstatt einen einfachen String mit JavaScript-Code zu verwenden, der eine Funktion aufruft und ihr Ergebnis zurückliefert, weisen Sie in JavaScript die Funktion direkt folgendermaßen der Event-Handler-Eigenschaft zu: document.meinformular.onsubmit = validiereFormular;
Beachten Sie, dass auf den Funktionsnamen keine Klammern folgen. Das liegt daran, dass Sie die Funktion hier nicht aufrufen wollen. Sie wollen hier nur eine Referenz darauf zuweisen. Eine vollständige Betrachtung von Event-Handlern finden Sie in Kapitel 17.
15.3.3 Alt-DOM-Beispiele Beispiel 15-1 zeigt eine listeAnkerAuf( )-Funktion, die ein neues Fenster öffnet und document.write( ) einsetzt, um eine Liste mit allen Ankern im Ausgangsdokument auszugeben. Jeder Eintrag in der Liste ist ein Link mit einem Event-Handler, der bewirkt, dass das Fenster zum Ort des angegebenen Ankers scrollt. Der Code in diesem Beispiel ist besonders nützlich, wenn Sie Ihre HTML-Dokumente so schreiben, dass alle Abschnittsüberschriften in Anker wie diesen eingeschlossen sind: Das Anchor-Objekt
Beachten Sie, dass die Funktion listeAnkerAuf( ) die Methode Window.open( ) verwendet. Wie in Kapitel 14 gezeigt wurde, blockieren Browser üblicherweise Pop-up-Fenster, es sei denn, sie werden als Antwort auf eine Benutzeraktion geöffnet. Rufen Sie listeAnkerAuf( ) deswegen auf, wenn der Benutzer auf einen Link oder einen Button klickt. Aber tun Sie es nicht automatisch, wenn Ihre Webseite geladen wird. Beispiel 15-1: Alle Anker auflisten /* * * * * * *
listeAnkerAuf.js: Ein einfaches Inhaltsverzeichnis mit document.anchors[] erstellen. Der Funktion listeAnkerAuf( ) wird als Argument ein Dokument übergeben, und sie öffnet ein neues Fenster, das als "Navigationsfenster" für dieses Dokument dient. Das neue Fenster zeigt eine Liste aller Anker des Dokuments an. Klicken Sie auf einen Anker in der Liste, scrollt das Dokument zu diesem Anker.
340 | Kapitel 15: Dokumente skripten
491-0.book Seite 341 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 15-1: Alle Anker auflisten (Fortsetzung)
clientseitiges JavaScript
*/ function listeAnkerAuf(d) { // Ein neues Fenster öffnen. var neuesfenster = window.open("", "navfenster", "menubar=yes,scrollbars=yes,resizable=yes," + "width=500,height=300"); // Ihm einen Titel geben. neuesfenster.document.write("Navigationsfenster: " + d.title + ""); // Alle Anker auflisten. for(var i = 0; i < d.anchors.length; i++) { // Für jedes Anchor-Objekt den anzuzeigenden Titel ermitteln. // Erst versuchen, den Text zwischen und über eine browserunabhängige // Eigenschaft abzurufen. Wird so kein Titel erhalten, wird stattdessen der Name // verwendet. var a = d.anchors[i]; var text = null; if (a.text) text = a.text; // Netscape 4 else if (a.innerText) text = a.innerText; // IE 4+ if ((text == null) || (text == '')) text = a.name; // Default // Jetzt diesen Text als Hyperlink ausgeben. Die href-Eigenschaft des Links // wird nie verwendet: Der onclick-Handler erledigt die Arbeit, indem er die // location.hash-Eigenschaft das Ausgangsfensters so setzt, dass dieses // Fenster den angegebenen Anker anzeigt. Siehe Window.opener, // Window.location und Location.hash und Link.onclick. neuesfenster.document.write(''); neuesfenster.document.write(text); neuesfenster.document.write(''); } neuesfenster.document.close( );
// Vergessen Sie nie, das Dokument zu schließen!
}
15.4 Überblick über das W3C DOM Nachdem wir uns das einfache Alt-DOM angesehen haben, können wir uns jetzt dem mächtigeren und standardisierten W3C DOM zuwenden, das es erweitert und ersetzt. Die API des W3C DOMs ist nicht sonderlich kompliziert, aber bevor wir uns ansehen, wie man mit dem DOM programmiert, sollten wir einige Punkte erwähnen, die Sie in Bezug auf die DOM-Architektur verstehen müssen.
15.4 Überblick über das W3C DOM |
341
491-0.book Seite 342 Mittwoch, 4. April 2007 9:55 09
e-bol.net
15.4.1 Dokumente als Bäume darstellen HTML-Dokumente haben eine hierarchische Struktur eingebetteter Tags, die im DOM als ein Baum von Objekten dargestellt werden. Die Baumdarstellung eines HTML-Dokuments enthält Knoten, die HTML-Tags oder -Elemente wie und
repräsentieren, und Knoten, die Textstrings repräsentieren. Ein HTML-Dokument kann auch Knoten enthalten, die HTML-Kommentare repräsentieren.1 Betrachten Sie folgendes einfaches HTML-Dokument: Beispieldokument Ein HTML-Dokument
Dies ist ein einfaches Dokument.
Die DOM-Darstellung dieses Dokuments entspricht dem Baum, der in Abbildung 15-1 gezeigt wird.
Abbildung 15-1: Die Baumdarstellung eines HTML-Dokuments
1 Das DOM kann auch verwendet werden, um XML-Dokumente darzustellen, die eine komplexere Syntax als HTML-Dokumente haben, und die Baumdarstellung eines solchen Dokuments kann Knoten enthalten, die XML-Entity-Referenzen, Verarbeitungsanweisungen, CDATA-Abschnitte und so weiter repräsentieren. Mehr zur Verwendung des DOMs mit XML finden Sie in Kapitel 21.
342 | Kapitel 15: Dokumente skripten
491-0.book Seite 343 Mittwoch, 4. April 2007 9:55 09
e-bol.net
15.4.2 Knoten Die DOM-Baumstruktur, die in Abbildung 15-1 illustriert wird, wird als ein Baum unterschiedlicher Typen von Node-Objekten dargestellt. Die Node-Schnittstelle2 definiert Eigenschaften und Methoden für die Durchquerung und Manipulation des Baums. Die childNodes-Eigenschaft eines Node-Objekts liefert die Liste der Kindknoten des Knotens zurück, und die Eigenschaften firstChild, lastChild, nextSibling, previousSibling und parentNode bieten eine Möglichkeit, den Knotenbaum zu durchqueren. Methoden wie appendChild( ), removeChild( ), replaceChild( ) und insertBefore( ) ermöglichen es Ihnen, dem Dokumentbaum Knoten hinzuzufügen oder Knoten aus dem Dokumentbaum zu entfernen. Beispiele für die Verwendung dieser Eigenschaften und Methoden sehen Sie später in diesem Kapitel.
15.4.2.1 Typen von Knoten Verschiedene Typen von Knoten im Dokumentbaum werden durch spezifische Subinterfaces von Node repräsentiert. Jedes Node-Objekt hat eine nodeType-Eigenschaft, die angibt, um was für eine Art von Knoten es sich handelt. Wenn die nodeType-Eigenschaft eines Knotens der Konstanten Node.ELEMENT_NODE entspricht, wissen Sie beispielsweise, dass das Node-Objekt auch ein Element-Objekt ist, und können auf ihm alle Methoden und Eigenschaften verwenden, die das Interface Element definiert. Tabelle 15-1 führt alle Knotentypen auf, auf die man häufiger in HTML-Dokumenten stößt, und gibt für jeden den nodeType-Wert an. Tabelle 15-1: Häufige Knotentypen Interface
nodeType-Konstante
nodeType-Wert
Element
Node.ELEMENT_NODE
1
Text
Node.TEXT_NODE
3
Document
Node.DOCUMENT_NODE
9
2 Der DOM-Standard definiert Interfaces, keine Klassen. Wenn Sie mit dem Begriff Interface in der objektorientierten Programmierung noch nicht vertraut sind, stellen Sie sich das als eine Art abstrakte Klasse vor. Später in diesem DOM-Überblick werde ich diesen Unterschied ausführlicher beschreiben.
15.4 Überblick über das W3C DOM |
343
clientseitiges JavaScript
Wenn Sie mit der Baumstruktur in der Computer-Programmierung noch nicht vertraut sind, ist es hilfreich zu wissen, dass sie ihre Terminologie von Stammbäumen ausleiht. Der Knoten direkt über einem Knoten ist der Elternknoten dieses Knotens. Die Knoten auf einer Stufe direkt unter einem anderen Knoten sind die Kindknoten dieses Knotens. Knoten auf der gleichen Ebene und mit dem gleichen Elternknoten sind Geschwister. Die Menge der Knoten, die sich auf irgendeiner Ebene unterhalb eines anderen Knotens befinden, sind die Nachfahren dieses Knotens. Und der Elternknoten, die Großelternknoten und alle anderen Knoten über einem Knoten sind die Vorfahren dieses Knotens.
491-0.book Seite 344 Mittwoch, 4. April 2007 9:55 09
Das Node-Objekt an der Wurzel des DOM-Baums ist ein Document-Objekt. Die documentElement-Eigenschaft dieses Objekts verweist auf ein Element-Objekt, das das Wurzelelement des Dokuments repräsentiert. Bei HTML-Dokumenten ist das das Element, das entweder explizit oder implizit im Dokument enthalten ist. (Der Document-Knoten kann neben dem Wurzelelement noch weitere Kinder wie Comment-Knoten enthalten.) In HTML-Dokumenten interessieren Sie sich üblicherweise mehr für das -Element als für das -Element. Als Abkürzung können Sie document.body verwenden, um auf dieses Element zu verweisen. In einem DOM-Baum gibt es nur ein Document-Objekt. Die meisten Knoten im Baum sind Element-Objekte, die durch Tags wie und repräsentiert werden, und Text-Objekte, die Strings mit Text repräsentieren. Wenn der Dokument-Parser Kommentare bewahrt, werden diese Kommentare im DOM-Baum durch Comment-Objekte repräsentiert. Abbildung 15-2 zeigt eine partielle Klassenhierarchie für diese und andere DOM-Kern-Interfaces. HTMLHeadElement Document
HTMLDocument Text
CharacterData Comment Node
Element Attr
HTMLElement
HTMLBodyElement HTMLTitleElement HTMLParagraphElement HTMLInputElement HTMLTableElement . . . etc.
Abbildung 15-2: Eine partielle Klassenhierarchie der Core DOM API
15.4.2.2 Attribute Die Attribute eines Elements (wie die src- und width-Attribute eines -Tags) können mit den Methoden getAttribute( ), setAttribute( ) und removeAttribute( ) des Element-
344 | Kapitel 15: Dokumente skripten
491-0.book Seite 345 Mittwoch, 4. April 2007 9:55 09
e-bol.net Interfaces abgefragt, gesetzt und entfernt werden. Wie später gezeigt wird, sind die Standard-Attribute von HTML auch als Eigenschaften der Element-Knoten verfügbar, die diese Tags repräsentieren.
15.4.3 Die DOM HTML API Der DOM-Standard wurde gleichermaßen für die Verwendung mit XML- und HTMLDokumenten entwickelt. Die Core DOM API – die Interfaces Node, Element, Document und weitere Interfaces – ist relativ allgemein und auf beide Typen von Elementen anwendbar. Der DOM-Standard schließt auch Interfaces ein, die spezifisch für HTMLDokumente sind. Wie Sie in Abbildung 15-2 sehen können, ist HTMLDocument ein HTML-spezifisches Subinterface von Document und HTMLElement ein HTML-spezifisches Subinterface von Element. Weiterhin definiert das DOM tag-spezifische Interfaces für viele HTML-Elemente. Die tag-spezifischen Interfaces wie HTMLBodyElement und HTMLTitleElement definieren üblicherweise einen Satz von Eigenschaften, die die Attribute des HTML-Tags widerspiegeln. Das HTMLDocument-Interface definiert verschiedene Dokumenteigenschaften und -methoden, die von Browsern vor der W3C-Standardisierung unterstützt wurden. Dazu zählen die location-Eigenschaft, das forms[]-Array und die write( )-Methode, die weiter oben in diesem Kapitel beschrieben wurden. Das HTMLElement-Interface definiert die Eigenschaften id, style, title, lang, dir und className. Diese Eigenschaften ermöglichen einen bequemen Zugriff auf die Werte der Attribute id, style, title, lang, dir und class, die in HTML-Tags zulässig sind. (»class« ist in JavaScript ein reserviertes Wort; das HTML-Attribut class wird in JavaScript also zur Eigenschaft className.) Einige, in Tabelle 15-2 aufgeführte HTML-Tags akzeptieren keine anderen Attribute als diese sechs und werden durch das Interface HTMLElement deswegen vollständig dargestellt.
15.4 Überblick über das W3C DOM |
345
clientseitiges JavaScript
Ein anderer, etwas unbequemerer Weg, mit Attributen zu arbeiten, ist die Methode getAttributeNode( ), die ein Attr-Objekt zurückliefert, das ein Attribut und seinen Wert repräsentiert. (Ein Grund dafür, diese etwas unbequemere Technik zu verwenden, besteht darin, dass das Attr-Interface eine specified-Eigenschaft definiert, mit der Sie ermitteln können, ob das Attribut literal im Dokument angegeben wurde oder ob sein Wert ein Default-Wert ist.) Das Attr-Interface erscheint in Abbildung 15-2 und ist ein Knotentyp. Beachten Sie allerdings, dass Attr-Objekte nicht im childNodes[]-Array eines Elements erscheinen und nicht auf dieselbe Weise direkt Teil des Dokumentbaums sind, wie es Element- und Text-Knoten sind. Die DOM-Spezifikation erlaubt, dass auf AttrKnoten über das attributes[]-Array des Node-Interfaces zugegriffen wird, aber der Internet Explorer definiert ein anderes und inkompatibles attributes[]-Array, das es unmöglich macht, dieses Feature portabel zu verwenden.
491-0.book Seite 346 Mittwoch, 4. April 2007 9:55 09
e-bol.net Tabelle 15-2: Einfache HTML-Tags
<strong>
Alle anderen HTML-Tags haben eigene Interfaces, die vom HTML-Teil der DOM-Spezifikation definiert werden. Für viele HTML-Tags definieren diese Interfaces nur eine Menge von Eigenschaften, die ihre HTML-Attribute widerspiegeln. Beispielsweise gibt es für das
-Tag ein entsprechendes HTMLUListElement-Interface und für das Tag ein entsprechendes HTMLBodyElement-Interface. Weil diese Interfaces einfach nur Eigenschaften definieren, die Teil des HTML-Standards sind, werden sie in diesem Buch nicht ausführlich dokumentiert. Sie können sicher voraussetzen, dass das HTMLElement-Objekt, das ein bestimmtes HTML-Tag repräsentiert, Eigenschaften für jedes Standard-Attribut dieses Tags besitzt (aber beachten Sie die Namenskonventionen, die im folgenden Abschnitt beschrieben werden). Beim Eintrag HTMLElement in Teil IV finden Sie eine Tabelle der HTML-Tags und die ihnen entsprechenden JavaScript-Eigenschaften. Beachten Sie, dass der DOM-Standard die Eigenschaften für HTML-Attribute als Hilfsmittel für Skriptautoren definiert. Der allgemeine Weg, Attributwerte abzufragen und zu setzen, sind die getAttribute( )- und setAttribute( )-Methoden des Element-Objekts, und Sie müssen diese Methoden verwenden, wenn Sie mit Attributen arbeiten, die nicht Teil des HTML-Standards sind. Einige der Interfaces, die vom HTML DOM spezifiziert werden, definieren Eigenschaften oder Methoden, die nicht einfach HTML-Attributwerte widerspiegeln. Beispielsweise definiert das Interface HTMLInputElement die Methoden focus( ) und blur( ) und eine form-Eigenschaft, und das Interface HTMLFormElement definiert die Methoden submit( ) und reset( ) und eine length-Eigenschaft. Wenn die JavaScript-Darstellung eines HTML-Elements Eigenschaften und Methoden einschließt, die mehr tun, als einfach nur HTML-Attribute widerzuspiegeln, werden diese Elemente in Teil IV dokumentiert. Beachten Sie allerdings, dass der Referenzabschnitt nicht die umfangreichen Interface-Namen verwendet, die vom DOM definiert werden. Stattdessen verweist er auf sie der Einfachheit (und der Rückwärtskompatibilität mit der früheren Verwendung) halber über einfachere Namen. Schlagen Sie beispielsweise in den Referenzeinträgen für Anchor, Image, Input, Form, Link, Option, Select, Table und Textarea nach.
346 | Kapitel 15: Dokumente skripten
491-0.book Seite 347 Mittwoch, 4. April 2007 9:55 09
e-bol.net 15.4.3.1 HTML-Namenskonventionen
Wenn ein HTML-Attributname mit einem JavaScript-Schlüsselwort in Konflikt tritt, wird ihm der String »html« vorangestellt, um einen Konflikt zu vermeiden. Das for-Attribut des -Tags wird also zur htmlFor-Eigenschaft von HTMLLabelElement. Eine Ausnahme zu dieser Regel ist das class-Attribut (das für jedes HTML-Element angegeben werden kann). Es wird zur className-Eigenschaft von HTMLElement.3
15.4.4 DOM Level und Features Es gibt zwei Versionen oder »Level« des DOM-Standards. DOM Level 1 wurde im Oktober 1998 standardisiert. Es definiert die Core DOM-Interfaces wie Node, Element, Attr und Document und daneben verschiedene HTML-spezifische Interfaces. DOM Level 2 wurde im November 2000 standardisiert. Neben einigen Aktualisierungen der KernInterfaces wurde diese neue Version des DOMs umfassend erweitert, um Standard-APIs für die Arbeit mit Dokument-Events und CSS-Stylesheets zu definieren und zusätzliche Werkzeuge für die Arbeit mit Bereichen von Dokumenten bereitzustellen. Mit Level 2 wurde der DOM-Standard »modularisiert.« Das Core-Modul, das die grundlegende Baumstruktur eines Dokuments mit (unter anderem) den Interfaces Document, Node, Element und Text definiert, ist das einzige erforderliche Modul. Alle anderen Module sind optional und können, je nach Anforderungen der Implementierung unterstützt werden oder nicht. Die DOM-Implementierung eines Webbrowsers würde offensichtlicherweise das HTML-Modul unterstützen, weil Webdokumente in HTML geschrieben sind. Browser, die CSS-Stylesheets unterstützen, unterstützen überlicherweise auch die StyleSheets- und CSS-Module, weil (wie in Kapitel 16 gezeigt wird) CSS-Styles in der Dynamic HTML-Programmierung eine entscheidende Rolle spielen. Da fast die gesamte interessante clientseitige JavaScript-Programmierung Event-Handling-Fähigkeiten erfordert, würde man gleichermaßen erwarten, dass alle Webbrowser das Events-Modul der DOM-Spezifikation unterstützen. Leider hat Microsoft das DOM Events-Modul nie für den Internet Explorer implementiert. Events werden deswegen, wie in Kapitel 17 beschrieben, im Alt-DOM, dem W3C DOM und dem IE DOM jeweils unterschiedlich behandelt. 3 Der Begriff className ist irreführend, weil mit dieser Eigenschaft (und dem HTML-Attribut, das sie repräsentiert) nicht nur ein einzelner Klassenname angegeben werden kann, sondern auch eine durch Leerzeichen getrennte Liste mit Klassennamen.
15.4 Überblick über das W3C DOM |
347
clientseitiges JavaScript
Bei der Arbeit mit den HTML-spezifischen Teilen des DOM-Standards sollten Sie mit einigen einfachen Namenskonventionen vertraut sein. Denken Sie zunächst daran, dass HTML Groß-/Kleinschreibung zwar nicht berücksichtigt, JavaScript aber schon. Eigenschaften der HTML-spezifischen Interfaces beginnen mit Kleinbuchstaben. Wenn der Eigenschaftsname aus mehreren Wörtern besteht, wird der erste Buchstabe des zweiten Worts und aller nachfolgenden Wörter großgeschrieben. Das maxlength-Attribut des -Tags wird also zur maxLength-Eigenschaft von HTMLInputElement.
491-0.book Seite 348 Mittwoch, 4. April 2007 9:55 09
e-bol.net Dieses Buch dokumentiert DOM Level 1 und 2. Das entsprechende Referenzmaterial finden Sie in Teil IV. Das W3C ist fortgefahren, den DOM-Standard zu verbessern und zu erweitern und hat Spezifikationen für verschiedene Level 3-Module veröffentlicht, einschließlich einer Level 3-Version des Core-Moduls. Level 3-Features werden in Webbrowsern noch nicht so umfassend unterstützt (obwohl Firefox eine partielle Unterstützung bietet) und werden in dieser Auflage dieses Buchs nicht dokumentiert. Neben Verweisen auf DOM Level 1, 2 und 3 stoßen Sie gelegentlich vielleicht auch auf Verweise auf DOM Level 0. Dieser Begriff verweist auf keinen formellen Standard, sondern verweist informell auf die gemeinsamen Features der HTML-Objektmodelle, die Netscape und der Internet Explorer vor der W3C-Standardisierung implementiert haben. Das heißt, »DOM Level 0« ist ein Synonym für »Alt-DOM.«
15.4.5 DOM-Konformität Als dies geschrieben wurde, boten alle aktuellen Versionen moderner Browser wie Firefox, Safari und Opera gute bis ausgezeichnete Unterstützung des DOM Level 2-Standards. Internet Explorer 6 ist Level 1 DOM-konform und unterstützt Level 2 DOM nicht annähernd so gut. Zusätzlich zu einer unvollständigen Unterstützung von Level 2 Core, bietet er auch überhaupt keine Unterstützung für das Level 2 Events-Modul, das Gegenstand von Kapitel 17 ist. Internet Explorer 5 und 5.5 haben substanzielle Mängel in ihrer Level 1-Konformität, unterstützen aber die wichtigsten DOM Level 1-Methoden gut genug, um die meisten der Beispiele in diesem Kapitel auszuführen. Die Anzahl der verfügbaren Browser ist so groß geworden und die Geschwindigkeit der Veränderungen in diesem Bereich der Standardunterstützung hat so zugenommen, dass dieses Buch nicht einmal mehr versucht, definitive Aussagen dazu zu machen, welche Browser welches bestimmte DOM-Feature unterstützen. Deswegen müssen Sie sich auf andere Informationsquellen verlassen, wenn Sie herausfinden möchten, wie konform die DOM-Implementierung eines bestimmten Webbrowsers ist. Eine Quelle für Konformitätsinformationen ist die Implementierung selbst. In einer konformen Implementierung verweist die implementation-Eigenschaft des DocumentObjekts auf ein DOMImplementation-Objekt, das eine Methode namens hasFeature( ) definiert. Diese Methode können Sie einsetzen (falls sie existiert), um die Implementierung zu fragen, ob sie ein bestimmtes Feature (oder Modul) des DOM-Standards unterstützt. Um zu ermitteln, ob die DOM-Implementierung in einem Webbrowser die grundlegenden DOM Level 1-Interfaces für die Arbeit mit HTML-Dokumenten unterstützt, können Sie beispielsweise den folgenden Code verwenden: if (document.implementation && document.implementation.hasFeature && document.implementation.hasFeature("html", "1.0")) { // Der Browser behauptet, dass er die Level 1 Core- und HTML-Interfaces unterstützt }
348 | Kapitel 15: Dokumente skripten
491-0.book Seite 349 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Tabelle 15-3: Features, die mit hasFeature( ) getestet werden können Feature-Name
Version
Beschreibung
HTML
1.0
Level 1 Core- und HTML-Interfaces
XML
1.0
Level 1 Core- und XML-Interfaces
Core
2.0
Level 2 Core-Interfaces
HTML
2.0
Level 2 HTML-Interfaces
Impliziert
Core
XML
2.0
Level 2 XML-spezifische Interfaces
Core
Views
2.0
AbstractView-Interface
Core
StyleSheets
2.0
Generische Stylesheet-Durchquerung
Core
CSS
2.0
CSS-Styles
Core, Views
CSS2
2.0
CSS2Properties-Interface
CSS
Events
2.0
Event-Handling-Infrastruktur
Core Events, Views
UIEvents
2.0
Benutzerschnittstellen-Events (plus Events und Views)
MouseEvents
2.0
Mouse-Events
UIEvents
HTMLEvents
2.0
HTML-Events
Events
Im Internet Explorer 6 liefert hasFeature( ) nur für das HTML-Feature und die Version 1.0 true zurück. Er meldet keine Konformität zu einem der anderen Features, die in Tabelle 15-3 aufgeführt werden (obwohl er, wie in Kapitel 16 gezeigt wird, die wichtigsten Verwendungen des CSS2-Moduls unterstützt). Dieses Buch dokumentiert die Interfaces, die alle DOM-Module bilden, die in Tabelle 15-3 aufgeführt werden. Die Core- und HTML-Module werden in diesem Kapitel behandelt. Die StyleSheets-, CSS- und CSS2-Module werden in Kapitel 16 behandelt und die verschiedenen Event-Module in Kapitel 17. Teil IV schließt eine vollständige Behandlung aller Module ein. Die Methode hasFeature( ) ist nicht immer absolut zuverlässig. Wie bereits gesagt, meldet der IE 6 Level 1-Konformität zu den HTML-Features, obwohl es bei seiner Standard-
15.4 Überblick über das W3C DOM |
349
clientseitiges JavaScript
Die Methode hasFeature( ) erwartet zwei Argumente: den Namen des zu prüfenden Features und eine Versionsnummer, die beide als String ausgedrückt werden. Sie liefert true, wenn die angegebene Version des angegebenen Features unterstützt wird. Tabelle 15-3 führt die Feature-Name/Versionsnummer-Paare auf, die von den DOM Level 1- und Level 2-Standards definiert werden. Beachten Sie, dass bei den Feature-Namen keine Groß-/Kleinschreibung berücksichtigt wird: Sie können sie in dieser Hinsicht schreiben, wie Sie möchten. Die vierte Spalte der Tabelle gibt an, welche anderen Features für die Unterstützung eines Features erforderlich sind und somit durch den Rückgabewert true impliziert werden. Wenn hasFeature( ) beispielsweise anzeigt, dass das Modul MouseEvents unterstützt wird, impliziert das, dass UIEvents ebenfalls unterstützt wird, und das impliziert seinerseits, dass die Module Events, Views und Core unterstützt werden.
491-0.book Seite 350 Mittwoch, 4. April 2007 9:55 09
e-bol.net konformität einige Probleme gibt. Andererseits meldete Netscape 6.1 Nicht-Konformität zu den Level 2 Core-Features, obwohl er überwiegend konform war. In beiden Fällen benötigen Sie feinstufigere Informationen dazu, was genau konform ist und was nicht. Das sind aber genau die Informationen, die zu umfangreich und unbeständig sind, um sie in diesem Buch abzudrucken. Wenn Sie ein aktiver Webentwickler sind, kennen oder entdecken Sie zweifelslos selbst viele browserspezifische Unterstützungsdetails. Aber auch im Web gibt es Ressourcen, die Sie dabei unterstützen können. Das W3C hat unter http://www.w3c.org/DOM/Test/ eine partielle Test-Suite für bestimmte DOM-Module veröffentlicht. Leider hat es keine Ergebnisse der Anwendung dieser Suite auf gebräuchliche Webbrowser veröffentlicht. Der beste Ort, um Kompatibilitäts- und Konformitätsinformationen zu finden, sind vielleicht einige unabhängige Sites im Web. Eine beachtenswerte Site ist http://www.quirksmode.org von Peter-Paul Koch. Sie enthält die Ergebnisse von intensiven Untersuchungen der Browser-Kompatibilität mit den DOM- und CSS-Standards, die ihr Autor durchgeführt hat. Eine andere Site ist http://webdevout.net/browser_support.php von David Hammond.
15.4.5.1 DOM-Konformität im Internet Explorer Weil der IE der am häufigsten verwendete Webbrowser ist, sind hier einige besondere Hinweise zu seiner Konformität mit den DOM-Spezifikationen angebracht. IE 5 und später unterstützen die Level 1 Core- und HTML-Features gut genug, um die Beispiele in diesem Kapitel auszuführen. Außerdem unterstützen sie die wichtigsten Level 2 CSS-Features gut genug, um die meisten der Beispiele in Kapitel 16 auszuführen. Leider bieten IE 5, 5.5 und 6 keine Unterstützung des DOM Level 2 Events-Moduls, obwohl Microsoft selbst an der Definition dieses Moduls beteiligt war und hinreichend Zeit hatte, es für den IE 6 zu implementieren. Die mangelnde Unterstützung des Standard-Event-Modells durch den IE hemmt die Entwicklung fortgeschrittener clientseitiger Webanwendungen. Obwohl der IE 6 (über seine hasFeature( )-Methode) behauptet, dass er die Core- und HTML-Interfaces des DOM Level 1-Standards unterstützt, ist diese Unterstützung eigentlich unvollständig. Das ungeheuerlichste Problem und das, auf das Sie am wahrscheinlichsten stoßen werden, ist klein, aber nervig: Der IE bietet keine Unterstützung für die Knotentypkonstanten, die vom Node-Interface definiert werden. Sie werden sich erinnern, dass jeder Knoten in einem Dokument eine nodeType-Eigenschaft hat, die angibt, um was für eine Art von Knoten es sich handelt. Die DOM-Spezifikation sagt auch, dass das Node-Interface Konstanten definiert, die jeden definierten Knotentyp repräsentieren. Beispielsweise repräsentiert die Konstante Node.ELEMENT_NODE einen Element-Knoten. In IE (zumindest bis Version 6) existieren diese Konstanten einfach nicht. Die Beispiele in diesem Kapitel wurden so angepasst, dass sie dieses Problem umgehen, indem sie Integer-Literale anstelle der entsprechenden symbolischen Konstanten verwenden. Beispielsweise werden Sie Code wie diesen sehen: if (n.nodeType == 1 /*Node.ELEMENT_NODE*/)
350 | Kapitel 15: Dokumente skripten
// Prüfen, ob n ein Element ist
491-0.book Seite 351 Mittwoch, 4. April 2007 9:55 09
e-bol.net Es ist guter Programmierstil, statt festen Integer-Literalen in Code Konstanten zu verwenden. Wenn Sie das portabel machen möchten, können Sie den folgenden Code in Ihre Programme einschließen, um diese Konstanten zu definieren, wenn sie fehlen sollten:
clientseitiges JavaScript
if (!window.Node) { var Node = { // Wenn es kein Node-Objekt gibt, eines mit ELEMENT_NODE: 1, // den folgenden Eigenschaften und Werten definieren. ATTRIBUTE_NODE: 2, // Beachten Sie, dass das nur HTML-Knotentypen sind. TEXT_NODE: 3, // Für XML-spezifische Knoten müssen Sie hier COMMENT_NODE: 8, // andere Konstanten hinzufügen. DOCUMENT_NODE: 9, DOCUMENT_FRAGMENT_NODE: 11 }; }
15.4.6 Sprachunabhängige DOM-Interfaces Obwohl der DOM-Standard aus dem Wunsch entsprang, eine allgemeine API für die dynamische HTML-Programmierung zur Verfügung zu haben, ist das DOM nicht nur für Webprogrammierer interessant. Tatsächlich wird der Standard zurzeit am intensivsten von serverseitigen Java- und C++-Programmen verwendet, die XML-Dokumente parsen und manipulieren. Aufgrund seiner vielen Verwendungsmöglichkeiten wurde der DOM-Standard sprachunabhängig definiert. Dieses Buch beschreibt nur die JavaScript-Bindungen der DOM API, aber Sie sollten sich einiger weiterer Punkte bewusst sein. Erstens sollten Sie beachten, dass die Objekteigenschaften in den JavaScript-Bindungen in anderen Sprachen üblicherweise auf Paare von Getter/Setter-Methoden abgebildet sind. Wenn ein Java-Programmierer Sie nach der getFirstChild( )-Methode des Node-Interfaces fragt, müssen Sie deswegen wissen, dass die JavaScript-Bindung der Node API keine getFirstChild( )Methode definiert. Stattdessen definiert sie einfach eine firstChild-Eigenschaft. Das Lesen dieser Eigenschaft ist das JavaScript-Äquivalent zum getFirstChild( )-Aufruf in Java. Ein weiteres wichtiges Feature der JavaScript-Bindung der DOM API ist, dass sich bestimmte DOM-Objekte wie JavaScript-Arrays verhalten. Wenn ein Interface eine Methode namens item( ) definiert, verhalten sich Objekte, die dieses Interface implementieren, wie schreibgeschützte numerische Arrays. Nehmen Sie beispielsweise an, Sie haben ein NodeList-Objekt erhalten, indem Sie die childNodes-Eigenschaft eines Knotens gelesen haben. Sie können die einzelnen Node-Objekte in der Liste erhalten, indem Sie die gewünschte Knotennummer an die Methode item( ) übergeben oder, noch einfacher, indem Sie das NodeList-Objekt einfach als ein Array behandeln und es direkt indizieren. Der folgende Code illustriert diese beiden Optionen: var var var var
n = document.documentElement; children = n.childNodes; head = children.item(0); body = children[1];
// // // //
Dies Dies Hier Aber
ist ein Node-Objekt. ist ein NodeList-Objekt. ist ein Weg, eine NodeList zu verwenden. dieser Weg ist einfacher!
15.4 Überblick über das W3C DOM |
351
491-0.book Seite 352 Mittwoch, 4. April 2007 9:55 09
e-bol.net Wenn ein DOM-Objekt eine namedItem( )-Methode besitzt, hat es quasi die gleichen Auswirkungen, wenn Sie dieser Methode einen String übergeben oder wenn Sie den String als Array-Index für das Objekt verwenden. Beispielsweise sind die folgenden Codezeilen äquivalente Möglichkeiten, auf ein Formularelement zuzugreifen: var f = document.forms.namedItem("meinformular"); var g = document.forms["meinformular"]; var h = document.forms.meinformular;
Obwohl Sie die Array-Notation verwenden können, um auf ein Element einer NodeList zuzugreifen, ist es wichtig, dass Sie daran denken, dass NodeList einfach ein Array-artiges Objekt ist (siehe Abschnitt 7.7) und kein echtes Array. Eine NodeList hat beispielsweise keine sort( )-Methode. Weil der DOM-Standard auf unterschiedliche Weise verwendet werden kann, haben die Architekten des Standards darauf geachtet, dass die DOM API auf eine Weise definiert ist, dass sie nicht die Möglichkeiten anderer einschränkt, die API ihren eigenen Vorstellungen entsprechend zu implementieren. Insbesondere definiert der DOM-Standard Interfaces anstelle von Klassen. In der objektorientierten Programmierung ist eine Klasse ein festgelegter Datentyp, der genau so implementiert werden muss, wie er vorgegeben wurde. Ein Interface ist andererseits eine Sammlung von Methoden und Eigenschaften, die gemeinsam implementiert werden müssen. Also kann eine Implementierung des DOM nach eigenem Geschmack Klassen definieren. Aber diese Klassen müssen die Methoden und Eigenschaften der verschiedenen DOM-Interfaces definieren. Diese Architektur hat eine Reihe wichtiger Implikationen. Erstens müssen die Klassennamen, die in einer Implementierung verwendet werden, nicht direkt mit den InterfaceNamen übereinstimmen, die im DOM-Standard verwendet werden. Zweitens kann eine Klasse mehrere Interfaces implementieren. Betrachten Sie beispielsweise das DocumentObjekt. Dieses Objekt ist eine Instanz einer Klasse, die von der Webbrowser-Implementierung definiert wird. Wir wissen nicht genau, welche Klasse das ist, aber wir wissen, dass sie das DOM Document-Interface implementiert – das heißt, alle Methoden und Eigenschaften, die von Document definiert werden, sind für uns über das DocumentObjekt verfügbar. Da Webbrowser mit HTML-Dokumenten arbeiten, wissen wir auch, dass das Document-Objekt das HTMLDocument-Interface implementiert und dass uns auch alle Methoden und Eigenschaften zur Verfügung stehen, die von diesem Interface definiert werden. Da Webbrowser außerdem CSS unterstützen, implementiert das Document-Objekt auch noch die DOM-Interfaces DocumentStyle und DocumentCSS. Und wenn der Webbrowser die DOM Events- und Views-Module unterstützt, implementiert Document ebenfalls die Interfaces DocumentEvent und DocumentView. Im Allgemeinen konzentriert sich Teil IV auf die Objekte, mit denen clientseitige JavaScript-Programmierer tatsächlich arbeiten, anstatt auf die abstrakteren Interfaces, die die API für diese Objekte vorgeben. Deswegen finden Sie im Referenzabschnitt Einträge für Document und HTMLDocument, aber nicht für die kleineren Zusatz-Interfaces wie
352 | Kapitel 15: Dokumente skripten
491-0.book Seite 353 Mittwoch, 4. April 2007 9:55 09
e-bol.net DocumentCSS und DocumentView. Die von diesen Interfaces definierten Methoden werden einfach in den Eintrag für das Document-Objekt integriert.
var t = new Text("Dies ist ein Textknoten");
// Den Konstruktor gibt es nicht!
Da er keine Konstruktoren definieren kann, definiert der DOM-Standard stattdessen im Document-Interface eine Reihe nützlicher Factory-Methoden. Um einen neuen Textknoten für ein Dokument zu erstellen, würden Sie deswegen Folgendes schreiben: var t = document.createTextNode("Dies ein neue Textknoten");
Die vom DOM definierten Factory-Methoden haben Namen, die mit dem Wort »create« beginnen. Zusätzlich zu den von Document definierten Factory-Methoden werden noch einige weitere von DOMImplementation definiert und sind über document.implementation verfügbar.
15.5 Ein Dokument durchqueren Mit dem vorangehenden Überblick über das W3C DOM im Gepäck sind Sie jetzt in der Lage, mit der Verwendung der DOM API zu beginnen. Dieser Abschnitt und die auf ihn folgenden Abschnitte zeigen, wie man DOM-Bäume durchquert, in einem Dokument bestimmte Elemente findet, den Dokumentinhalt verändert und einem Dokument neuen Inhalt hinzufügt. Wie bereits erwähnt, repräsentiert das DOM ein HTML-Dokument als einen Baum von Node-Objekten. Bei jeder Baumstruktur ist die Durchquerung des Baums und eine Untersuchung der einzelnen Knoten eine der häufigsten Aufgaben. Beispiel 15-2 zeigt eine Möglichkeit, das zu tun. Es ist eine JavaScript-Funktion, die rekursiv einen Knoten und all seine Kinder untersucht und die Anzahl der HTML-Tags (d.h. Element-Knoten) zählt, auf die sie bei der Durchquerung stößt. Beachten Sie die Verwendung der childNodes-Eigenschaft eines Knotens. Der Wert dieser Eigenschaft ist ein NodeList-Objekt, das sich (in JavaScript) wie ein Array von Node-Objekten verhält. Die Funktion kann also alle Kinder eines gegebenen Knotens aufzählen, indem sie eine Schleife über die Elemente des childNodes[]-Arrays durchläuft. Durch Rekursion zählt die Funktion nicht nur die Kinder eines gegebenen Knotens auf, sondern alle Knoten im Knotenbaum. Beachten Sie, dass diese Funktion auch zeigt, wie man die Eigenschaft nodeType einsetzt, um den Typ der einzelnen Knoten zu ermitteln.
15.5 Ein Dokument durchqueren |
353
clientseitiges JavaScript
Eine andere wichtige Sache, die Sie verstehen müssen, ist, dass der DOM-Standard, weil er statt Klassen Interfaces definiert, keine Konstruktormethoden definiert. Wenn Sie ein neues Text-Objekt erzeugen möchten, um es in ein Dokument einzufügen, können Sie beispielsweise nicht Folgendes schreiben:
491-0.book Seite 354 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 15-2: Die Knoten eines Dokuments durchqueren // Dieser Funktion wird ein DOM-Node-Objekt übergeben, und sie prüft, ob dieser Knoten ein // HTML-Tag repräsentiert – d.h., ob der Knoten ein Element-Objekt ist. Sie ruft sich selbst // rekursiv auf allen Kindern des Knotens auf und prüft diese auf die gleiche Weise. // Sie liefert die Gesamtzahl von Element-Objekten zurück, auf die sie stößt. // Wenn Sie diese Funktion aufrufen, indem Sie ihr das Document-Objekt übergeben, // durchquert sie den vollständigen DOM-Baum. function zaehleTags(n) { // n ist ein Node-Objekt var anz_tags = 0; // Den Tag-Zähler initialisieren if (n.nodeType == 1 /*Node.ELEMENT_NODE*/) // Prüfen, ob n ein Element ist anz_tags++; // Gegebenenfalls den Zähler erhöhen var kinder = n.childNodes; // Jetzt alle Kinder abrufen for(var i=0; i < kinder.length; i++) { // Die Kinder durchlaufen anz_tags += zaehleTags(kinder[i]); // Rekursion auf allen Kindern } return anz_tags; // Gesamtzahl zurückliefern } Dies ist ein Beispiel für ein Dokument.
Ein weiterer Punkt, der zu Beispiel 15-2 zu beachten ist, besteht darin, dass die Funktion zaehleTags( ), die es definiert, aus dem onload-Event-Handler aufgerufen wird, damit sie nicht aufgerufen wird, bevor das Dokument vollständig geladen wurde. Das ist eine allgemeine Anforderung bei der Arbeit mit dem DOM: Sie können den Dokumentbaum nicht durchqueren oder manipulieren, bevor das Dokument vollständig geladen wurde. (In Abschnitt 13.5.7 finden Sie weitere Informationen zu dieser Anforderung. Sehen Sie sich auch Beispiel 17-7 an, das eine Hilfsfunktion bietet, die es mehreren Modulen ermöglicht, onload-Event-Handler zu registrieren.) Zusätzlich zu der Eigenschaft childNodes definiert das Interface Node ein paar weitere nützliche Eigenschaften. firstChild und lastChild verweisen auf das erste und das letzte Kind eines Knotens, und nextSibling und previousSibling verweisen auf benachbarte Geschwister eines Knotens. (Zwei Knoten sind Geschwister, wenn sie den gleichen Elternknoten haben.) Diese Eigenschaften bieten eine weitere Möglichkeit, die Kinder eines Knotens zu durchlaufen, die in Beispiel 15-3 vorgeführt wird. Dieses Beispiel definiert eine Funktion namens getText( ), die alle Text-Knoten bei oder unter einem angegebenen Knoten findet. Es zieht den Textinhalt der Knoten heraus, verknüpft sie und liefert sie als einen JavaScript-String zurück. In der DOM-Programmierung besteht überraschend häufig Bedarf nach einer Hilfsfunktion wie dieser.
354 | Kapitel 15: Dokumente skripten
491-0.book Seite 355 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 15-3: Den gesamten Text unterhalb eines DOM-Knotens erhalten
clientseitiges JavaScript
/** * getText(n): Alle Text-Knoten bei oder unter dem Knoten n finden, * ihren Inhalt aneinanderknüpfen und als String zurückliefern. */ function getText(n) { // Wiederholte Stringverkettungen können ineffizient sein. Wir sammeln // deswegen die Werte aller Textknoten in einem Array und verketten die // Elemente dieses Arrays dann auf einmal. var strings = []; getStrings(n, strings); return strings.join(""); // Diese rekursive Funktion findet alle Textknoten und hängt ihren // Text an das Array an. function getStrings(n, strings) { if (n.nodeType == 3 /* Node.TEXT_NODE */) strings.push(n.data); else if (n.nodeType == 1 /* Node.ELEMENT_NODE */) { // Achten Sie auf die Iteration mit firstChild/nextSibling for(var m = n.firstChild; m != null; m = m.nextSibling) { getStrings(m, strings); } } } }
15.6 Elemente in einem Dokument finden Die Fähigkeit, alle Knoten in einem Dokument durchqueren zu können, bietet Ihnen die Möglichkeit, bestimmte Knoten zu finden. Wenn man mit der DOM API programmiert, braucht man häufig einen bestimmten Knoten aus dem Dokument oder eine Liste von Knoten bestimmter Typen im Dokument. Glücklicherweise bietet die DOM API Funktionen, die das einfach machen. Das Document-Objekt ist die Wurzel jedes DOM-Baums, repräsentiert aber kein HTMLElement in diesem Baum. Die Eigenschaft document.documentElement verweist auf das -Tag, das als Wurzelelement des Dokuments dient. Und die Eigenschaft document. body verweist auf das -Tag, das häufiger nützlich ist als sein -Elternknoten. Die body-Eigenschaft des HTMLDocument-Objekts ist eine praktische Sondereigenschaft. Gäbe es sie nicht, könnten Sie dennoch folgendermaßen auf das -Tag verweisen: document.getElementsByTagName("body")[0]
Dieser Ausdruck ruft die getElementsByTagName( )-Methode des Document-Objekts auf und wählt das erste Element des zurückgelieferten Arrays aus. Der Aufruf von getElementsByTagName( ) liefert ein Array aller -Elemente im Dokument. Da HTML-
15.6 Elemente in einem Dokument finden |
355
491-0.book Seite 356 Mittwoch, 4. April 2007 9:55 09
e-bol.net Dokumente nur ein -Element haben können, interessieren Sie sich nur für das erste Element des zurückgelieferten Arrays.4 Sie können getElementsByTagName( ) verwenden, um eine Liste eines beliebigen Typs von HTML-Element zu erhalten. Beispielsweise können Sie Folgendes tun, um alle Tabellen in einem Dokument zu finden: var tabellen = document.getElementsByTagName("table"); alert("Dieses Dokument enthält " + tabellen.length + " Tabellen");
Beachten Sie, dass die Strings, die getElementsByTagName( ) übergeben werden, da HTMLTags keine Groß-/Kleinschreibung berücksichtigen, ebenfalls keine Groß-/Kleinschreibung berücksichtigen. Das heißt, dass der vorangehende Code
-Tags auch dann findet, wenn sie als
geschrieben sind. getElementsByTagName( ) liefert Elemente in der Reihenfolge zurück, in der sie im Dokument erscheinen. Und wenn Sie getElementsByTagName( ) den besonderen String »*« übergeben, liefert die Methode eine Liste aller Elemente im Dokument zurück und bewahrt dabei die Reihenfolge, in der sie im Dokument erscheinen. (Diese besondere Verwendung wird von IE 5 und IE 5.5 nicht unterstützt. Siehe stattdessen das IE-spezifische HTMLDocument.all[]-Array in Teil IV.) Gelegentlich möchten Sie keine Liste von Elementen, sondern möchten auf einem bestimmten Element eines Dokuments operieren. Wenn Sie viel über die Struktur eines Dokuments wissen, können Sie dazu vielleicht immer noch getElementsByTagName( ) verwenden. Wenn Sie etwas mit dem vierten Absatz eines Dokuments machen möchten, könnten Sie beispielsweise diesen Code verwenden: var meinAbsatz = document.getElementsByTagName("p")[3];
Das ist normalerweise jedoch nicht die beste (und auch nicht effizienteste) Technik, weil sie stark von der Struktur des Dokuments abhängig ist. Würde am Anfang des Dokuments ein neuer Absatz eingefügt, würde das den Code zerstören. Wenn Sie bestimmte Elemente eines Dokuments manipulieren möchten, sollten Sie diesen Elementen stattdessen ein id-Attribut geben, das einen (innerhalb des Dokuments) eindeutigen Namen für das Element angibt. Dann können Sie das gewünschte Element über seine ID nachschlagen. Beispielsweise könnten Sie den besonderen vierten Absatz Ihres Dokuments mit einem Tag wie diesem schreiben:
Den Knoten für diesen Absatz können Sie dann mit JavaScript-Code wie diesem suchen: var meinAbsatz = document.getElementById("besondererAbsatz");
4 Technisch gesehen liefert getElementsByTagName( ) eine NodeList zurück, die wie ein Array-artiges Objekt ist. In diesem Buch verwende ich die Array-Notation, um sie zu indizieren, und werde auf sie deswegen informell als »Array« verweisen.
356 | Kapitel 15: Dokumente skripten
491-0.book Seite 357 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beachten Sie, dass die Methode getElementById( ) nicht wie getElementsByTagName( ) ein Array von Elementen zurückliefert. Weil der Wert jedes id-Attributs einzigartig ist (oder sein sollte), liefert getElementById( ) nur das eine Element mit dem passenden id-Attribut zurück. getElementById( ) ist eine wichtige Methode, und ihr Einsatz ist in der DOM-Program-
// Wenn x ein String ist, wird angenommen, dass es eine Element-ID ist, // und das benannte Element gesucht. Andernfalls wird angenommen, dass // x bereits ein Element ist, das dann einfach zurückgeliefert wird. function id(x) { if (typeof x == "string") return document.getElementById(x); return x; }
Wenn Sie eine solche Funktion definiert haben, können Ihre DOM-Manipulationsmethoden so geschrieben werden, dass sie Elemente oder Element-IDs als Argumente akzeptieren. Vor der Verwendung eines solchen Arguments x müssen Sie dann einfach nur einmal x = id(x) schreiben. Ein bekanntes clientseitiges JavaScript-Toolkit5 definiert eine derartige Hilfsmethode und gibt ihr einen sogar noch kürzeren Namen: $( ). getElementById( ) und getElementsByTagName( ) sind beides Methoden des DocumentObjekts. Element-Objekte definieren jedoch ebenfalls eine getElementsByTagName( )Methode. Diese Methode des Element-Objekts verhält sich genauso wie die Methode des Document-Objekts, liefert allerdings nur Elemente zurück, die Nachfahren des Elements sind, auf dem sie aufgerufen wurde. Anstatt das vollständige Dokument nach einem bestimmten Typen zu durchsuchen, sucht sie nur innerhalb des vorgegebenen Elements. Das ermöglicht es beispielsweise, getElementById( ) zu verwenden, um ein bestimmtes Element zu finden, und dann getElementsByTagName( ) zu finden, um alle Nachfahren eines bestimmten Typs in diesem Element zu finden. Zum Beispiel: // Ein bestimmtes Table-Element in einem Dokument finden und seine Zeilen zählen var inhaltsverzeichnis = document.getElementById("TOC"); var zeilen = tableOfContents.getElementsByTagName("tr"); var zeilenanzahl = rows.length;
Beachten Sie schließlich, dass das HTMLDocument-Objekt für HTML-Dokumente auch eine getElementsByName( )-Methode definiert. Diese Methode verhält sich wie getElementById( ), betrachtet aber das name-Attribut von Elementen anstelle des id-Attributs. Und weil beim name-Attribut nicht erwartet wird, dass es in einem Dokument eindeutig ist (beispielsweise haben Radiobuttons in HTML-Formularen üblicherweise gleiche name-Werte), liefert getElementsByName( ) ein Array mit Elementen anstatt eines einzelnen Elements zurück. Zum Beispiel: 5 Die Prototype-Bibliothek von Sam Stephenson, die unter http://prototype.conio.net verfügbar ist.
15.6 Elemente in einem Dokument finden |
357
clientseitiges JavaScript
mierung sehr gebräuchlich. Sie wird so häufig verwendet, dass Sie dafür vielleicht eine Hilfsfunktion mit einem kürzeren Namen definieren möchten. Zum Beispiel:
491-0.book Seite 358 Mittwoch, 4. April 2007 9:55 09
e-bol.net // suchen var link = document.getElementsByName("oben")[0]; // Alle -Elemente finden var auswahl = document.getElementsByName("lieferungsart");
Zusätzlich zur Auswahl von Dokumentelementen über den Tagnamen oder die ID ist es auch oft nützlich, Elemente auszuwählen, die Mitglieder einer Klasse sind. Das HTMLAttribut class und die entsprechende JavaScript-Eigenschaft className weisen einem Element eine oder mehrere benannte (und durch Leerzeichen getrennte) Klassen zu. Diese Klassen sind für die Verwendung mit CSS-Stylesheets (siehe Kapitel 16) gedacht, aber das muss nicht ihr einziger Zweck sein. Nehmen Sie an, Sie schreiben wichtige Hinweise in einem HTML-Dokument folgendermaßen: Dies ist ein Warnhinweis
Sie können dann ein CSS-Stylesheet einsetzen, um die Farben, Abstände, Rahmen und anderen Darstellungsattribute für diese Hinweise anzugeben. Aber was ist, wenn Sie auch JavaScript-Code schreiben wollen, der -Tags finden und bearbeiten kann, die Mitglieder der Klasse »warnung« sind? Beispiel 15-4 bietet eine Lösung. Dieses Beispiel definiert eine getElemente( )-Methode, die es Ihnen ermöglicht, Elemente anhand der Klasse und/oder des Tagnamens auszuwählen. Beachten Sie, dass die Eigenschaft className verzwickt ist, weil ein HTML-Element Mitglied mehrerer Klassen sein kann. getElemente( ) schließt eine eingebettete Methode isMitglied( ) ein, die prüft, ob ein angegebenes HTML-Element Mitglied einer angegebenen Klasse ist. Beispiel 15-4: HTML-Elemente nach Klasse und Tag-Namen auswählen /** * getElemente(klassenname, tagname, wurzel): * Liefert ein Array mit DOM-Elementen zurück, die Mitglied der angegebenen Klasse * sind, den angegebenen Tagnamen haben und Nachfahren der angegebenen Wurzel sind. * * Wird kein klassenname angegeben, werden die Elemente unabhängig von der Klasse * zurückgeliefert. * Wird kein tagname angegeben, werden die Elemente unabhängig vom tagname zurückgeliefert. * Wird keine Wurzel angegeben, wird das document-Objekt verwendet. Wenn die angegebene * Wurzel ein String ist, wird sie als Element-ID verwendet und das Wurzelelement * über getElementsById( ) nachgeschlagen. */ function getElemente(klassenname, tagname, wurzel) { // Wurde keine Wurzel angegeben, wird das vollständige Dokument verwendet. // Wurde ein String angegeben, wird er nachgeschlagen. if (!wurzel) wurzel = document; else if (typeof wurzel == "string") wurzel = document.getElementById(root); // Wurde kein Tagname angegeben, werden alle Tags verwendet. if (!tagname) tagname = "*";
358 | Kapitel 15: Dokumente skripten
491-0.book Seite 359 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 15-4: HTML-Elemente nach Klasse und Tag-Namen auswählen (Fortsetzung) // Alle Nachfahren der angegebenen Wurzel mit dem angegebenen Tagnamen finden. var alle = wurzel.getElementsByTagName(tagname); // Wurde kein klassenname angegeben, werden alle Tags zurückgeliefert if (!klassenname) return alle;
clientseitiges JavaScript
// Andernfalls filtern wir die Elemente über klassenname var elemente = []; // Wir beginnen mit einem leeren Array for(var i = 0; i < alle.length; i++) { var element = alle[i]; if (isMitglied(element, klassenname)) // isMitglied( ) wird unten definiert elemente.push(element); // Klassenmitglieder dem Array hinzufügen } // Beachten Sie, dass wir immer ein Array zurückliefern, auch wenn es leer ist. return elemente; // Ermitteln, ob das angegebene Element Mitglied der angegebenen Klasse ist. // Diese Funktion ist für den häufigen Fall optimiert, dass die Eigenschaft // className nur einen Klassennamen enthält. Aber sie behandelt auch den Fall // einer durch Leerzeichen getrennten Liste von Klassennamen. function isMitglied(element, klassenname) { var klassen = element.className; // Eine Liste der Klassen abrufen if (!klassen) return false; // Keine Klassen definiert if (klassen == klassenname) return true; // Genauer Treffer // Kein genauer Treffer. Wenn es keine Leerzeichen gibt, ist dieses Element // also kein Mitglied der Klasse. var whitespace = /\s+/; if (!whitespace.test(klassen)) return false; // Wenn wir hier hinkommen, ist das Element Mitglied mehrerer Klassen, die // wir deswegen einzeln prüfen müssen. var c = klassen.split(whitespace); // Auf dem Leerraum-Begrenzer aufspalten for(var i = 0; i < c.length; i++) { // Die Klassen durchlaufen if (c[i] == klassenname) return true; // und auf Treffer prüfen } return false;
// Wenn keine der Klassen passt
} }
15.7 Ein Dokument modifizieren Die Durchquerung der Knoten eines Dokuments kann nützlich sein, aber die wahre Macht der Core DOM API liegt in den Features, des es Ihnen ermöglichen, JavaScript einzusetzen, um Dokumente dynamisch zu modifizieren. Die beiden folgenden Beispiele demonstrieren die grundlegenden Techniken der Modifikation von Dokumenten und illustrieren einige der Möglichkeiten.
15.7 Ein Dokument modifizieren |
359
491-0.book Seite 360 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 15-5 schließt eine JavaScript-Funktion namens sortiereKinder( ), ein Beispieldokument und einen HTML-Button ein, der, wenn er angeklickt wird, die Funktion sortiereKinder( ) aufruft und ihr die ID eines
-Tags übergibt. Die Funktion sortiereKinder( ) findet die Kindelemente des angegebenen Knotens, sortiert sie auf Grundlages des Texts, den sie enthalten, und ordnet sie im Dokument (mit Hilfe von appendChild( )) neu, damit sie in alphabetischer Reihenfolge erscheinen. Beispiel 15-5: Die Elemente einer Liste alphabetisch sortieren function sortiereKinder(e) { // Das ist das Element, dessen Kinder wir sortieren werden. if (typeof e == "string") e = document.getElementById(e); // Die Elementkinder (aber nicht die Textknotenkinder) von e in ein echtes Array // übertragen. var kinder = []; for(var x = e.firstChild; x != null; x = x.nextSibling) if (x.nodeType == 1 /* Node.ELEMENT_NODE */) kinder.push(x); // Jetzt das Array auf Grundlage des Textinhalts der Kinder sortieren. // Voraussetzen, dass jedes Kind nur ein einziges Kind hat, das ein Textknoten ist. kinder.sort(function(n, m) { // Das ist die Vergleichsfunktion für das Sortieren var s = n.firstChild.data; // Text des Knotens n var t = m.firstChild.data; // Text des Knotens m if (s < t) return -1; // n kommt vor m else if (s > t) return 1; // n kommt nach m else return 0; // n und m sind gleich }); // Jetzt die Kinder in sortierter Reihenfolge wieder an das Elternelement anhängen. // Wird ein Knoten eingefügt, der bereits Teil des Dokuments ist, wird er automatisch // von seiner aktuellen Position entfernt. Das Wiedereinfügen dieser Knoten // verschiebt sie automatisch von ihrer alten Position. Beachten Sie, dass // alle Textknoten, die wir übersprungen haben, allerdings zurückgelassen werden. for(var i = 0; i < kinder.length; i++) e.appendChild(kinder[i]); }
eins
zwei
drei
vier
Sortiere Liste
Das in Abbildung 15-3 gezeigte Ergebnis von Beispiel 15-5 ist, dass die Elemente der Liste alphabetisch sortiert werden, wenn der Benutzer auf den Button klickt.
360 | Kapitel 15: Dokumente skripten
491-0.book Seite 361 Mittwoch, 4. April 2007 9:55 09
e-bol.net
clientseitiges JavaScript
Abbildung 15-3: Eine Liste vor und nach Sortierung
Beachten Sie, dass Beispiel 15-5 die zu sortierenden Knoten in ein separates Array kopiert hat. Das ermöglicht es, das Array leicht zu sortieren, hat aber auch noch andere Vorteile. Die NodeList-Objekte, die der Wert der Eigenschaft childNodes sind und von getElementsByTagName( ) zurückgeliefert werden, sind »live«: Alle Änderungen am Dokument werden unmittelbar in die NodeList übernommen. Das kann eine Problemursache sein, wenn Sie Knoten in die Liste einfügen oder Knoten aus der Liste entfernen, während Sie die Liste durchlaufen. Es kann deswegen häufig am sichersten sein, eine »Momentaufnahme« der Knoten zu machen, indem Sie die Knoten in ein echtes Array übertragen, bevor Sie sie durchlaufen. Beispiel 15-5 hat die Struktur des Dokuments geändert, indem die Elemente neu geordnet wurden. Beispiel 15-6 ändert den Inhalt eines Dokuments, indem es seinen Text ändert. Dieses Beispiel definiert eine Funktion grossbuchstaben( ), die rekursiv von einem angegebenen Node-Objekt aus absteigt und den Inhalt aller Textknoten, die sie findet, in Großbuchstaben umwandelt. Beispiel 15-6: Ein Dokument in Großbuchstaben umwandeln // Diese Funktion durchsucht einen Node n und seine Nachfahren rekursiv und // wandelt alle Textknotendaten in Großbuchstaben um. function grossbuchstaben(n) { if (n.nodeType == 3 /*Node.TEXT_NODE*/) { // Wenn der Knoten ein Textknoten ist, Text in Großbuchstaben ändern. n.data = n.data.toUpperCase( ); } else { // Wenn der Knoten kein Textknoten ist, die Kinder durchlaufen und die // Funktion rekursiv auf allen Kindern aufrufen.
15.7 Ein Dokument modifizieren |
361
491-0.book Seite 362 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 15-6: Ein Dokument in Großbuchstaben umwandeln (Fortsetzung) var kinder = n.childNodes; for(var i = 0; i < kinder.length; i++) grossbuchstaben(kinder[i]); } }
Beispiel 15-6 setzt einfach die data-Eigenschaft aller Textknoten, auf die es trifft. Es ist auch möglich, in einem Textknoten Text anzuhängen, einzufügen, zu löschen oder zu ersetzen. Dazu dienen die Methoden appendData( ), insertData( ), deleteData( ) und replaceData( ). Diese Methoden werden nicht direkt vom Text-Interface definiert, sondern von Text von CharacterData geerbt. Mehr Informationen zu ihnen können Sie unter CharacterData in Teil IV finden. In Beispiel 15-5 haben Sie die Dokumentelemente neu geordnet, sie aber unter dem gleichen Elternknoten belassen. Beachten Sie allerdings, dass die DOM API es erlaubt, Knoten aus dem Dokumentbaum im Baum frei zu bewegen (jedoch nur im gleichen Dokument). Beispiel 15-7 zeigt dies, indem es eine Funktion namens machFett( ) definiert, die einen angegebenen Knoten durch ein neues Element ersetzt (das mit der createElement( )-Methode des Document-Objekts erzeugt wurde), das ein HTML-Tag repräsentiert und den ursprünglichen Knoten zum Kind des neuen -Knotens macht und ihm damit einen neuen Elternknoten gibt. In einem HTML-Dokument bewirkt das, dass der gesamte Text in diesem Knoten und seinen Nachfahren fett dargestellt wird. Beispiel 15-7: Einem Knoten mit einem -Element einen neuen Elternknoten geben // Diese Funktion erwartet einen Node n, ersetzt ihn im Baum durch einen Elementknoten, // der ein HTML--Tag repräsentiert, und macht den ursprünglichen Knoten dann zu einem // Kind des neuen -Elements. function machFett(n) { if (typeof n == "string") n = document.getElementById(n); // Knoten suchen var b = document.createElement("b"); // Ein neues -Element erzeugen var elternknoten = n.parentNode; // Den Elternknoten des Knotens holen elternknoten.replaceChild(b, n); // Den Knoten durch das -Tag ersetzen b.appendChild(n); // Den Knoten zu einem Kind des -Elements machen }
Das ist Absatz #1.
Das ist Absatz #2.
Fett machen
362 | Kapitel 15: Dokumente skripten
491-0.book Seite 363 Mittwoch, 4. April 2007 9:55 09
e-bol.net
15.7.1 Attribute verändern
var ueberschrift = document.getElementById("ueberschrift"); ueberschrift.setAttribute("align", "center");
// Ein benanntes Element // suchen // align='center' setzen
Die DOM-Elemente, die HTML-Attribute repräsentieren, definieren JavaScript-Eigenschaften, die jedem ihrer Standard-Attribute entsprechen (selbst veralteten wie align). Die gleiche Wirkung können Sie also auch mit diesm Code erreichen: var ueberschrift = document.getElementById("ueberschrift"); ueberschrift.align = "center"; // Die Eigenschaft align setzen.
Wie in Kapitel 16 gezeigt wird, können Sie ein ganzes Universum nützlicher Effekte erreichen, indem Sie die CSS-Style-Eigenschaften von HTML-Elementen auf diese Weise ändern. Wird das gemacht, wird nicht die Struktur oder der Inhalt des Dokuments geändert, sondern stattdessen seine Darstellung.
15.7.2 Mit Dokumentfragmenten arbeiten Ein DocumentFragment ist ein besonderer Typ von Knoten, der nicht in einem Dokument selbst erscheint, sondern als temporärer Container für eine sequenzielle Sammlung von Knoten dient und es ermöglicht, diese Knoten als zusammenhängendes Objekt zu manipulieren. Wenn ein DocumentFragment in ein Dokument eingefügt wird (mit einer der Node-Methoden appendChild( ), insertBefore( ) oder replaceChild( )), ist es nicht das DocumentFragment, das eingefügt wird, sondern alle seine Kinder. Ein DocumentFragment können Sie mit document.createDocumentFragment( ) erzeugen. Mit appendChild( ) oder einer verwandten Node-Methode können Sie einem DocumentFragment Knoten hinzufügen. Und wenn Sie dann bereit sind, diese Knoten dem Dokument hinzuzufügen, fügen Sie ihm das DocumentFragment selbst hinzu. Nachdem Sie das getan haben, ist das Fragment leer und kann erst wieder verwendet werden, wenn ihm neue Kinder hinzugefügt wurden. Beispiel 15-8 zeigt diesen Vorgang. Es definiert eine umkehren( )-Funktion, die ein DocumentFragment als temporären Container verwendet, während sie die Reihenfolge der Kinder eines Node-Objekts umkehrt. Beispiel 15-8: Ein DocumentFragment einsetzen // Die Reihenfolge der Kinder des Node-Objekts n umkehren. function umkehren(n) { // Ein leeres DocumentFragment als temporären Container erzeugen. var f = document.createDocumentFragment( );
15.7 Ein Dokument modifizieren |
363
clientseitiges JavaScript
Neben der Modifikation von Dokumenten durch die Veränderung von Text oder die Umordnung oder Zuweisung zu anderen Elternknoten von Elementen können auch substanzielle Änderungen an einem Dokument durchgeführt werden, indem man einfach Attributwerte auf Dokumentelementen setzt. Eine Möglichkeit, das zu tun, bietet die Methode element.setAttribute( ). Zum Beispiel:
491-0.book Seite 364 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 15-8: Ein DocumentFragment einsetzen (Fortsetzung) // Jetzt die Kinder rückwärts durchlaufen und jedes in das Fragment verschieben. // Das letzte Kind von n wird das erste Kind von f und umgekehrt. Beachten Sie, // dass ein Kind automatisch aus n entfernt wird, wenn es f hinzugefügt wird while(n.lastChild) f.appendChild(n.lastChild); // Schließlich die Kinder von f alle auf einmal zurückschieben. n.appendChild(f); }
15.8 Einem Dokument Inhalt hinzufügen Die Methoden Document.createElement( ) und Document.createTextNode( ) erzeugen neue Element- und Text-Knoten, und die Methoden Node.appendChild( ), Node.insertBefore( ) und Node.replaceChild( ) können verwendet werden, um sie einem Dokument hinzuzufügen. Mit diesen Methoden können Sie einen DOM-Baum beliebiger Dokumentinhalte aufbauen. Beispiel 15-9 ist ein ausführlicheres Beispiel, das eine log( )-Funktion für die Protokollierung von Nachrichten und Objekten definiert. Dieses Beispiel schließt außerdem eine log.debug( )-Hilfsfunktion ein, die eine nützliche Alternative zur Einfügung von alert( )Aufrufen sein kann, wenn man JavaScript-Code debuggen muss. Die »Nachricht«, die an die Funktion log( ) übergeben wird, kann entweder ein String mit Klartext sein oder ein JavaScript-Objekt. Wenn ein String protokolliert wird, wird er einfach angezeigt, wie er ist. Wenn ein Objekt protokolliert wird, wird es als eine Tabelle mit Eigenschaftsnamen und -werten angezeigt. In beiden Fällen erzeugen die Funktionen createElement( ) und createTextNode( ) den neuen Inhalt. Mit einem geeigneten CSS-Stylesheet (das im Beispiel gezeigt wird) erzeugt die log( )Funktion von Beispiel 15-9 Ausgaben wie die, die in Abbildung 15-4 gezeigt werden. Beispiel 15-9 ist lang, aber es ist gut kommentiert und verdient eine sorgfältige Betrachtung. Achten Sie insbesondere auf die Aufrufe von createElement( ), createTextNode( ) und appendChild( ). Die private Funktion log.makeTable( ) zeigt, wie diese Funktionen verwendet werden, um die relativ komplexe Struktur einer HTML-Tabelle zu erzeugen. Beispiel 15-9: Eine Logging-Einrichtung für clientseitiges JavaScript /* * Log.js: Eine unaufdringliche Logging-Einrichtung * * Dieses Modul definiert ein globales Symbol: eine Funktion namens log( ). * Protokollieren Sie eine Nachricht, indem Sie die Funktion mit 2 oder 3 Argumenten aufrufen: * * category: der Typ der Nachricht. Er ist erforderlich, damit Nachrichten * unterschiedlicher Typen ausgewählt aktiviert oder deaktiviert werden können und * damit sie unabhängig gestylt werden können. Siehe unten.
364 | Kapitel 15: Dokumente skripten
491-0.book Seite 365 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 15-9: Eine Logging-Einrichtung für clientseitiges JavaScript (Fortsetzung) message: der zu protokollierende Text. Kann leer sein, wenn ein Objekt angegeben wird object: ein zu protokollierendes Objekt. Dieses Argument ist optional. Wird es übergeben, werden die Eigenschaften des Objekts selbst in Form einer Tabelle protokolliert. Jede Eigenschaft, deren Wert selbst ein Objekt ist, kann rekursiv protokolliert werden.
Hilfsfunktionen: Die Funktionen log.debug( ) und log.warn( ) sind Hilfsfunktionen, die einfach die Funktion log( ) mit den festen Kategorien "debug" und "warning" aufrufen. Es ist trivial, eine Hilfsfunktion zu definieren, die die eingebaute alert()-Methode durch eine Methode ersetzt, die log( ) aufruft. Logging aktivieren Log-Nachrichten werden per Default *nicht* angezeigt. Sie können die Anzeige einer bestimmten Kategorie auf zwei verschiedene Arten aktivieren. Die erste ist, ein oder ein anderes Container-Element mit einer ID der Form "_log" zu erzeugen. Für Nachrichten mit der Kategorie "debug" könnten Sie Folgendes in das Dokument einfügen: In diesem Fall werden alle Nachrichten in der angegebenen Kategorie an diesen Container angehängt, der gestylt werden kann, wie es Ihnen gefällt. Die zweite Möglichkeit, Nachrichten für eine besimmte Kategorie zu aktivieren, ist, eine geeignete Logging-Option zu setzen. Um die Kategorie "debug" zu aktivieren, würden Sie log.options.debugEnabled = true setzen. Wenn Sie das tun, wird ein für die Log-Nachrichten erzeugt. Wenn Sie die Protokollierung von Log-Nachrichten deaktivieren wollen, auch wenn ein geeigneter Container existiert, setzen Sie eine andere Option: log.options.debugDisabled=true. Setzen Sie diese Option wieder auf false, um die Protokollierung von Nachrichten für diese Kategorie wieder zu aktivieren. Log-Nachrichten stylen Zusätzlich zum Styling des Containers können Sie CSS einsetzen, um die Anzeige der einzelnen Log-Meldungen zu stylen. Jede Log-Meldung wird in ein -Tag platziert, und ihr wird eine CSS-Klasse der Form _message gegeben. Debugging-Meldungen hätten die Klasse "debug_message". Log-Optionen Das Logging-Verhalten kann geändert werden, indem Eigenschaften des log.optionsObjekt gesetzt werden, wie die Optionen, die beschrieben wurden, um das Logging für bestimmte Kategorien zu aktivieren oder zu deaktivieren. Es sind ein paar weitere Optionen verfügbar:
15.8 Einem Dokument Inhalt hinzufügen |
365
491-0.book Seite 366 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 15-9: Eine Logging-Einrichtung für clientseitiges JavaScript (Fortsetzung) * log.options.timestamp: Wenn diese Eigenschaft true ist, wird jeder Log-Meldung * das Datum und die Uhrzeit hinzugefügt. * * log.options.maxRecursion: Ein Integer, der die maximale Anzahl von eingebetteten * Tabellen angibt, die beim Logging von Objekten angezeigt werden sollen. Setzen * Sie diese Option auf 0, wenn Sie nie eine Tabelle in einer Tabelle haben wollen. * * log.options.filter: Eine Funktion, die beim Logging eines Objekts Eigenschaften * herausfiltert. Einer Filterfunktion wird der Name und der Wert einer Eigenschaft * übergeben, und sie liefert true, wenn die Eigenschaft in der Objekt-Tabelle * erscheinen soll, und false andernfalls. */ function log(category, message, object) { // Wenn diese Kategorie explizit deaktiviert wird, wird nichts getan. if (log.options[category + "Disabled"]) return; // Den Container finden. var id = category + "_log"; var c = document.getElementById(id); // Wenn es keinen Container gibt, das Logging dieser Kategorie aber aktiviert ist, // wird der Container erzeugt. if (!c && log.options[category + "Enabled"]) { c = document.createElement("div"); c.id = id; c.className = "log"; document.body.appendChild(c); } // Wenn es immer noch keinen Container gibt, wird die Meldung ignoriert. if (!c) return; // Wenn Zeitstempel aktiviert sind, fügen wir den Zeitstempel hinzu. if (log.options.timestamp) message = new Date( ) + ": " + (message?message:""); // Ein -Element für die Aufnahme des Log-Eintrags erzeugen. var entry = document.createElement("div"); entry.className = category + "_message"; if (message) { // Dem Element die Meldung hinzufügen. entry.appendChild(document.createTextNode(message)); } if (object && typeof object == "object") { entry.appendChild(log.makeTable(object, 0)); }
366 | Kapitel 15: Dokumente skripten
491-0.book Seite 367 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 15-9: Eine Logging-Einrichtung für clientseitiges JavaScript (Fortsetzung) // Schließlich den Eintrag dem Logging-Container hinzufügen. c.appendChild(entry); }
clientseitiges JavaScript
// Eine Tabelle für die Anzeige der Eigenschaften des angegebenen Objekts erzeugen. log.makeTable = function(object, level) { // Wurde die maximale Rekursionstiefe erreicht, wird stattdessen ein Textknoten // zurückgeliefert. if (level > log.options.maxRecursion) return document.createTextNode(object.toString( )); // Die Tabelle erzeugen, die zurückgeliefert werden soll. var table = document.createElement("table"); table.border = 1; // Der Tabelle einen Name|Typ|Wert-Header hinzufügen. var header = document.createElement("tr"); var headerName = document.createElement("th"); var headerType = document.createElement("th"); var headerValue = document.createElement("th"); headerName.appendChild(document.createTextNode("Name")); headerType.appendChild(document.createTextNode("Typ")); headerValue.appendChild(document.createTextNode("Wert")); header.appendChild(headerName); header.appendChild(headerType); header.appendChild(headerValue); table.appendChild(header); // Die Eigenschaftsnamen des Objekts abrufen und alphabetisch sortieren. var names = []; for(var name in object) names.push(name); names.sort( ); // Jetzt die Eigenschaften durchlaufen. for(var i = 0; i < names.length; i++) { var name, value, type; name = names[i]; try { value = object[name]; type = typeof value; } catch(e) { // Das sollte nicht passieren, kann in Firefox aber vorkommen. value = ""; type = "unknown"; }; // Diese Eigenschaft überspringen, wenn sie von einem Filter verworfen wird. if (log.options.filter && !log.options.filter(name, value)) continue; // Nie Funktionsquellcode anzeigen: Er braucht zu viel Platz. if (type == "function") value = "{/*Quellcode unterdrückt*/}";
15.8 Einem Dokument Inhalt hinzufügen |
367
491-0.book Seite 368 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 15-9: Eine Logging-Einrichtung für clientseitiges JavaScript (Fortsetzung) // Eine Tabellenzeile für die Anzeige von Name, Typ und Wert für die Eigenschaft // erzeugen. var row = document.createElement("tr"); row.vAlign = "top"; var rowName = document.createElement("td"); var rowType = document.createElement("td"); var rowValue = document.createElement("td"); rowName.appendChild(document.createTextNode(name)); rowType.appendChild(document.createTextNode(type)); // Objekte rekursiv verarbeiten, um sie als Tabellen anzuzeigen. if (type == "object") rowValue.appendChild(log.makeTable(value, level+1)); else rowValue.appendChild(document.createTextNode(value)); // Der Zeile die Zellen hinzufügen und die Zeile der Tabelle. row.appendChild(rowName); row.appendChild(rowType); row.appendChild(rowValue); table.appendChild(row); } // Zum Abschluss die Tabelle zurückliefern. return table; } // Ein leeres Optionsobjekt erzeugen. log.options = {}; // Hilfsversionen der Funktion mit vorgegebenen Kategorien log.debug = function(message, object) { log("debug", message, object); }; log.warn = function(message, object) { log("warning", message, object); }; // Kommentieren Sie die folgende Zeile aus, um alert( )-Dialoge in Log-Meldungen umzuwandeln. // function alert(msg) { log("alert", msg); }
Die Debugging-Meldungen, die in Abbildung 15-4 erscheinen, wurden mit dem folgenden einfachen Code erzeugt: function macheRechteck(x, y, w, h) { // Das ist die zu log.debug("Eintritt in macheRechteck"); // Eine
368 | Kapitel 15: Dokumente skripten
debuggende Funktion Meldung protokollieren
491-0.book Seite 369 Mittwoch, 4. April 2007 9:55 09
e-bol.net
clientseitiges JavaScript
Abbildung 15-4: Ausgabe der log( )-Funktion var r = {x:x, y:y, size: { w:w, h:h }}; log.debug("Neues Rechteck", r); log.debug("Austritt aus macheRechteck"); return r;
// Ein Objekt protokollieren // Eine weitere Meldung protokollieren
} Mache Rechteck
Das Erscheinungsbild der Log-Meldungen in Abbildung 15-4 wurde mit CSS-Styles erzeugt, die mit einem -Tag in den Code importiert wurden. Die Styles, die zur Erzeugung der Abbildung verwendet wurden, sind folgende: #debug_log { /* Styles für den background-color: #aaa; border: solid black 2px; overflow: auto; width: 75%; height: 300px; }
Container mit den Debug-Meldungen */ /* grauer Hintergrund */ /* schwarzer Rahmen */ /* Bildlaufleisten */ /* nicht so breit wie das vollständige Fenster */ /* nicht zu viel vertikalen Raum einnehmen */
15.8 Einem Dokument Inhalt hinzufügen |
369
491-0.book Seite 370 Mittwoch, 4. April 2007 9:55 09
e-bol.net #debug_log:before { /* Unserem Logging-Bereich einen Titel geben */ content: "Debugging-Meldungen"; display: block; text-align: center; font: bold 18pt sans-serif ; } .debug_message { /* Zwischen den Debug-Meldungen eine dünne schwarze Linie ausgeben */ border-bottom: solid black 1px; }
Mehr zu CSS werden Sie in Kapitel 16 lernen. Es ist nicht wichtig, dass Sie hier die CSSDetails verstehen. Das CSS wurde hier eingeschlossen, damit Sie sehen können, wie mit dem dynamisch generierten Inhalt, der von der Funktion log( ) erzeugt wurde, Styles verknüpft werden können.
15.8.1 Hilfsmethoden zur Erstellung von Knoten Beim Lesen von Beispiel 15-9 ist Ihnen vielleicht aufgefallen, dass die API zur Erstellung von Dokumentinhalten ziemlich ausufernd ist: Erst erzeugen Sie ein Element, dann setzen Sie seine Attribute, und dann erzeugen Sie einen Textknoten und fügen ihn dem Element hinzu. Als Nächstes fügen Sie das Element seinem Elternelement hinzu. Und so weiter. Allein die Erstellung eines
-Elements, das Setzen eines Attributs und die Hinzufügung einer Kopfzeile hat in Beispiel 15-9 13 Codezeilen in Anspruch genommen. Beispiel 15-10 definiert eine Hilfsfunktion zur Element-Erstellung, die diese Art repetitiver DOM-Programmierung vereinfacht. Beispiel 15-10 definiert eine einzige Funktion namens make( ). make( ) erzeugt ein Element mit dem angegebenen Tag-Namen, setzt auf ihm Attribute und fügt ihm Kinder hinzu. Attribute werden als Eigenschaften eines Objekts angegeben und Kinder werden in einem Array übergeben. Die Elemente dieses Arrays können Strings sein, die in Textknoten umgewandelt werden, oder andere Element-Objekte, die üblicherweise mit eingebetteten make( )-Aufrufen erzeugt werden. make( ) hatt eine flexible Aufrufsyntax, die zwei Kurzformen ermöglicht. Erstens kann das
Attribut-Argument weggelassen werden, wenn keine Attribute angegeben werden, und an seiner Stelle das Kindelemente-Argument übergeben werden. Wenn es nur ein Kindelement gibt, kann dieses zweitens direkt übergeben werden und muss nicht in ein Array mit nur einem Element gepackt werden. Der einzige Nachteil ist, dass diese beiden Kurzformen nicht kombiniert werden können, es sei denn, das einzige Kind ist ein Textknoten, der als String übergeben wird. Unter Verwendung von make( ) können die 13 Zeilen Code zur Erstellung einer
und ihrer Kopfzeile aus Beispiel 15-9 zu Folgendem verkürzt werden: var table = make("table", {border:1}, make("tr", [make("th", "Name"), make("th", "Typ"), make("th", "Wert")]));
370 | Kapitel 15: Dokumente skripten
491-0.book Seite 371 Mittwoch, 4. April 2007 9:55 09
e-bol.net Aber das geht noch besser. In Beispiel 15-10 folgt auf die Funktion make( ) eine weitere Funktion namens maker( ). Übergeben Sie maker( ) einen Tag-Namen, liefert die Funktion eine eingebettete Funktion zurück, die make( ) unter Vorgabe des von Ihnen angegebenen Tag-Namens aufruft. Wenn Sie viele Tabellen erstellen möchten, können Sie folgendermaßen Funktionen für häufig verwendete Tabellen-Tags definieren: Sind diese Erstellungsfunktionen definiert, reduziert sich der Code für die Tabellen- und die Kopfzeilenerstellung auf eine einzige Zeile: var meineTabelle = table({border:1}, tr([th("Name"), th("Typ"), th("Wert")]));
Beispiel 15-10: Hilfsfunktion zur Elementerstellung /** * make(tagname, attributes, children): * Erzeugt ein HTML-Element mit dem angegebenen Tag-Namen, Attributen und Kindern. * * Das Argument attributes ist ein JavaScript-Objekt: Die Namen und Werte seiner * Eigenschaften werden als die Namen und Werte der zu setzenden Attribute behandelt. * Wenn attributes null ist und children ein Array oder ein String ist, kann attributes * vollständig weggelassen werden und children als zweites Argument übergeben werden. * * Das Argument children ist normalerweise ein Array mit Kindelementen, die dem erzeugten * Element hinzugefügt werden sollen. Wenn es keine Kinder gibt, kann dieses Argument * weggelassen werden. Wenn es nur ein Kind gibt, kann es direkt übergeben werden und * muss nicht in ein Array eingeschlossen werden. (Aber wenn das Kind kein String * ist und keine Attribute angegeben werden, muss ein Array verwendet werden.) * * Beispiel: make("p", ["Dies ist ein ", make("b", "fettes"), " Wort."]); * * Inspiriert von der Bibliothek MochiKit (http://mochikit.com) von Bob Ippolito */ function make(tagname, attributes, children) { // Wenn bei einem Aufruf mit zwei Argumenten das Argument attributes ein Array oder // ein String ist, sollte es eigentlich das Argument children sein. if (arguments.length == 2 && (attributes instanceof Array || typeof attributes == "string")) { children = attributes; attributes = null; } // Das Element erzeugen. var e = document.createElement(tagname); // Die Attribute setzen. if (attributes) { for(var name in attributes) e.setAttribute(name, attributes[name]); }
15.8 Einem Dokument Inhalt hinzufügen |
371
clientseitiges JavaScript
var table = maker("table"), tr = maker("tr"), th = maker("th");
491-0.book Seite 372 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 15-10: Hilfsfunktion zur Elementerstellung (Fortsetzung) // Kinder hinzufügen, wenn welche angegeben wurden. if (children != null) { if (children instanceof Array) { // Wenn es tatsächlich ein Array ist for(var i = 0; i < children.length; i++) { // die Kinder durchlaufen. var child = children[i]; if (typeof child == "string") // Textknoten verarbeiten child = document.createTextNode(child); e.appendChild(child); // Annehmen, dass alles andere ein Node ist } } else if (typeof children == "string") // Ein einzelnes Textkind verarbeiten e.appendChild(document.createTextNode(children)); else e.appendChild(children); // Alle anderen einzelnen Kinder verarbeiten } // Schließlich das Element zurückliefern. return e; } /** * maker(tagname): Liefert eine Funktion zurück, die make( ) für das angegebene Tag aufruft. * Beispiel: var table = maker("table"), tr = maker("tr"), td = maker("td"); */ function maker(tag) { return function(attrs, children) { if (arguments.length == 1) return make(tag, attrs); else return make(tag, attrs, children); } }
15.8.2 Die innerHTML-Eigenschaft Auch wenn sie vom W3C nie als ein offizieller Teil des DOMs sanktioniert wurde, ist die innerHTML-Eigenschaft von HTMLElement-Knoten eine wichtige und mächtige Eigenschaft. Wenn Sie den Wert dieser Eigenschaft für ein HTML-Element abfragen, erhalten Sie einen String mit HTML-Text, der die Kinder dieses Elements repräsentiert. Wenn Sie diese Eigenschaft setzen, ruft der Browser seinen HTML-Parser auf, um Ihren String zu parsen und die Kinder des Elements durch das zu ersetzen, was der Browser zurückliefert. Ein HTML-Dokument als einen String mit HTML-Text zu beschreiben, ist in der Regel bequemer und kompakter, als eine Beschreibung über eine Folge von createElement( ) und appendChild( ) aufzurufen. Betrachten Sie noch einmal den Code aus Beispiel 15-9, der ein neues
-Element erzeugt und ihm eine Kopfzeile hinzugefügt hat. Wenn Sie innerHTML verwenden, können Sie diesen ziemlich ausufernden Code folgendermaßen neu schreiben:
372 | Kapitel 15: Dokumente skripten
491-0.book Seite 373 Mittwoch, 4. April 2007 9:55 09
e-bol.net var table = document.createElement("table"); // Das
-Element erzeugen table.border = 1; // Ein Attribut setzen // Der Tabelle die Name|Typ|Wert-Kopfzeile hinzufügen. table.innerHTML = "
Name
Typ
Wert
";
innerHTML wurde von Microsoft im IE 4 eingeführt. Es ist die wichtigste und am häufigsten verwendete Eigenschaft aus einem Quartett miteinander verwandter Eigenschaften. Die anderen drei Eigenschaften, outerHTML, innerText und outerText, werden von Firefox und verwandten Browsern nicht unterstützt. Sie werden am Ende dieses Kapitels in Abschnitt 15.11 beschrieben.
15.9 Beispiel: Ein dynamisch erzeugtes Inhaltsverzeichnis Die vorangehenden Abschnitte haben Ihnen gezeigt, wie Sie die Core DOM API einsetzen können, um ein Dokument zu durchqueren, Elemente aus einem Dokument auszuwählen und Dokumentinhalte zu ändern und hinzuzufügen. Beispiel 15-11 bringt all diese Teile zusammen, um automatisch ein Inhaltsverzeichnis für ein HTML-Dokument zu erstellen. Das Beispiel definiert eine einzige Funktion namens maketoc( ) und registriert einen onload-Event-Handler, damit die Funktion automatisch ausgeführt wird, wenn das Laden des Dokuments abgeschlossen ist. Wenn maketoc( ) ausgeführt wird, durchquert sie das Dokument und sucht nach den Tags , , , , und
Beispiel 15-11: Inhaltsverzeichnisse automatisch generieren /** * TOC.js: Ein Inhaltsverzeichnis für ein Dokument erzeugen. * * Dieses Modul definiert die Funktion maketoc( ) und registriert einen onload* Event-Handler, damit die Funktion automatisch aufgerufen wird, wenn das Laden des * Dokuments abgeschlossen ist. Wenn maketoc( ) läuft, sucht die Funktion erst nach * einem Dokument-Element mit der ID "toc". Wenn es kein derartiges Element gibt, macht * maketoc( ) nichts. Wenn es ein derartiges Element gibt, durchquert maketoc( ) das * Dokument, um alle - bis -Tags zu suchen, und erzeugt ein Inhaltsverzeichnis, * das es an das "toc"-Element anhängt. maketoc( ) fügt jeder Abschnittsüberschrift * eine Abschnittsnummer hinzu und fügt vor jeder Überschrift einen Link zurück zum * Inhaltsverzeichnis ein. maketoc( ) generiert Links und Anker mit Namen, die mit * "TOC" beginnen. Sie sollten dieses Präfix in Ihrem HTML also vermeiden. * * Die Einträge im generierten TOC können mit CSS gestylt werden. Alle Einträge * haben die Klasse "TOCEntry". Einträge haben außerdem eine Klasse, die der Ebene * der Abschnittsüberschrift entspricht. -Tags generieren Einträge mit der Klasse * "TOCLevel1". -Tags generieren Einträge mit der Klasse "TOCLevel2" und so weiter. * Abschnittsnummern, die in Überschriften eingefügt werden, haben die Klasse "TOCSectNum", * und die generierten Links zurück zum TOC haben die Klasse "TOCBackLink". * * Standardmäßig lauten die generierten Links zurück zum TOC "Inhalt". * Überschreiben Sie diesen Default (z.B. für Internationalisierungszwecke), indem Sie * die Eigenschaft maketoc.backlinkText auf den gewünschten Text setzen. **/ function maketoc( ) { // Den Container suchen. Wenn es keinen gibt, still zurückkehren. var container = document.getElementById('toc'); if (!container) return; // Das Dokument durchqueren und alle ...-Tags einem Array hinzufügen var sections = []; findSections(document, sections); // Vor dem Container-Element einen Anker einfügen, damit wir darauf linken können. var anchor = document.createElement("a"); // Ein -Knoten erzeugen anchor.name = "TOCtop"; // Ihm einen Namen geben anchor.id = "TOCtop"; // Und eine id (der IE braucht das) container.parentNode.insertBefore(anchor, container); // Vor dem toc einfügen
15.9 Beispiel: Ein dynamisch erzeugtes Inhaltsverzeichnis |
375
clientseitiges JavaScript
Der Code für das Modul TOC.js folgt. Beispiel 15-11 ist lang, aber es ist gut dokumentiert und verwendet Techniken, die bereits gezeigt wurden. Es lohnt sich, ein praktisches Beispiel für die Macht des W3C DOMs zu untersuchen.
491-0.book Seite 376 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 15-11: Inhaltsverzeichnisse automatisch generieren (Fortsetzung) // Ein Array initialisieren, das die Abschnittsnummern nachhält var sectionNumbers = [0,0,0,0,0,0]; // Jetzt alle Abschnittsüberschriftselemente durchlaufen, die gefunden wurden. for(var s = 0; s < sections.length; s++) { var section = sections[s]; // Ermitteln, welche Überschriftsebene es ist. var level = parseInt(section.tagName.charAt(1)); if (isNaN(level) || level < 1 || level > 6) continue; // Die Abschnittsnummer für diese Überschriftsebene inkrementieren. // Und alle kleineren Ebenennummern auf null zurücksetzen sectionNumbers[level-1]++; for(var i = level; i < 6; i++) sectionNumbers[i] = 0; // Jetzt die Abschnittsnummern für alle Überschriftsebenen kombinieren, // um Abschnittsnummern wie 2.3.1 zu erzeugen. var sectionNumber = ""; for(i = 0; i < level; i++) { sectionNumber += sectionNumbers[i]; if (i < level-1) sectionNumber += "."; } // Der Abschnittsüberschrift die Abschnittsnummer und ein Leerzeichen hinzufügen. // Wir platzieren die Nummer in ein , damit wir sie stylen können. var frag = document.createDocumentFragment( ); // Zur Aufnahme des Span und des // Leerzeichens var span = document.createElement("span"); // Span zur Aufnahme der Nummer span.className = "TOCSectNum"; // Das Span stylebar machen span.appendChild(document.createTextNode(sectionNumber)); // sect# hinzufügen frag.appendChild(span); // Das Span dem Fragment hinzufügen frag.appendChild(document.createTextNode(" ")); // Dann ein Leerzeichen hinzufügen section.insertBefore(frag, section.firstChild); // Beides der Überschrift hinzufügen // Einen Anker zur Markierung des Anfangs des Abschnitts erzeugen. var anchor = document.createElement("a"); anchor.name = "TOC"+sectionNumber; // Dem Anker für das Linken einen Namen geben anchor.id = "TOC"+sectionNumber; // Im IE brauchen generierte Anker eine id // Den Anker in einen Link zurück zum Inhalt einhüllen. var link = document.createElement("a"); link.href = "#TOCtop"; link.className = "TOCBackLink"; link.appendChild(document.createTextNode(maketoc.backlinkText)); anchor.appendChild(link); // Anker und Link unmittelbar vor der Abschnittsüberschrift einfügen. section.parentNode.insertBefore(anchor, section);
376 | Kapitel 15: Dokumente skripten
491-0.book Seite 377 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 15-11: Inhaltsverzeichnisse automatisch generieren (Fortsetzung) // Jetzt einen Link auf diesen Abschnitt erzeugen. var link = document.createElement("a"); link.href = "#TOC" + sectionNumber; // Das Link-Ziel setzen link.innerHTML = section.innerHTML; // Den Link auf die Überschrift setzen
clientseitiges JavaScript
// Den Link in ein div platzieren, das auf Basis der Ebene gestylt werden kann. var entry = document.createElement("div"); entry.className = "TOCEntry TOCLevel" + level; // Für das CSS-Styling entry.appendChild(link); // Und dann das Div dem TOC-Container hinzufügen. container.appendChild(entry); } // Diese Methode durchquert rekursiv den Baum mit der Wurzel n, sucht nach // den Tags bis und hängt sie an das Array sections an. function findSections(n, sects) { // Alle Kinder von n durchlaufen. for(var m = n.firstChild; m != null; m = m.nextSibling) { // Alle Knoten überspringen, die keine Elemente sind. if (m.nodeType != 1 /* Node.Element_NODE */) continue; // Das Container-Element überspringen, da es eine eigene Überschrift haben kann. if (m == container) continue; // Als Optimierung
-Tags überspringen, da in Absätzen keine Überschriften // erscheinen sollen. (Wir könnten auch Listen -Tags usw. überspringen, // aber
ist das am häufigsten vorkommende.) if (m.tagName == "P") continue; // Optimierung // Wird der Kindknoten nicht übersprungen, wird geprüft, ob er eine // Überschrift ist. Ist das der Fall, wird er dem Array hinzugefügt. // Andernfalls wird in ihn hinabgestiegen. Beachten Sie, dass das DOM // interface-basiert ist und nicht klassenbasiert. Wir können also nicht // einfach Folgendes prüfen (m instanceof HTMLHeadingElement). if (m.tagName.length==2 && m.tagName.charAt(0)=="H") sects.push(m); else findSections(m, sects); } } } // Das ist der Default-Text für die Links zurück zum Inhalt. maketoc.backlinkText = "Inhalt"; // maketoc( ) registieren, damit die Funktion automatisch ausgeführt wird, wenn // das Laden des Dokuments abgeschlossen ist. if (window.addEventListener) window.addEventListener("load", maketoc, false); else if (window.attachEvent) window.attachEvent("onload", maketoc);
15.9 Beispiel: Ein dynamisch erzeugtes Inhaltsverzeichnis |
377
491-0.book Seite 378 Mittwoch, 4. April 2007 9:55 09
e-bol.net
15.10 Ausgewählten Text abfragen Manchmal ist es nützlich, wenn man ermitteln kann, welchen Text der Benutzer in einem Dokument ausgewählt hat. Das ist ein Bereich, in dem wenige Standardisierungen zur Verfügung stehen, aber es ist in allen modernen Browsern möglich, den ausgewählten Text abzufragen. Beispiel 15-12 zeigt, wie das geht. Beispiel 15-12: Den aktuell ausgewählten Text abfragen function getSelectedText( ) { if (window.getSelection) { // Diese Technik wird am ehesten standardisiert werden. // getSelection( ) ruft ein Selection-Objekt ab, das wir nicht dokumentieren. return window.getSelection( ).toString( ); } else if (document.getSelection) { // Das ist eine ältere Technik, die einen String zurückliefert return document.getSelection( ); } else if (document.selection) { // Das ist eine IE-spezifische Technik. // Wir dokumentieren die IE-Eigenschaft selection oder TextRange-Objekte nicht. return document.selection.createRange( ).text; } }
Dem Code in diesem Beispiel müssen Sie in gewissem Maße einfach vertrauen. Die in diesem Beispiel verwendeten Selection- und TextRange-Objekte werden in diesem Buch nicht dokumentiert. Als dies geschrieben wurde, waren ihre APIs einfach zu komplex und zu wenig standardisiert, um sie hier zu behandeln. Aber da die Abfrage des ausgewählten Texts eine häufige und recht einfache Operation ist, ist es nützlich, sie hier zu illustrieren. Sie können sie einsetzen, um Bookmarklets zu erzeugen (siehe Abschnitt 13.4.1), die auf dem ausgewählten Text operieren, indem sie ein Wort in einer Suchmaschen oder auf einer Referenz-Site nachschlagen. Der folgende HTML-Link schlägt beispielsweise den aktuellen Text in Wikipedia nach. Wird für ihn ein Lesezeichen erzeugt, werden der Link und die darin enthaltene JavaScript-URL zu einem Bookmarklet: Ausgewählten Text in Wikipedia nachschlagen
Es gibt in Beispiel 15-12 eine kleinere Inkompatibilität. Die getSelection( )-Methoden der Window- und Document-Objekte liefern den ausgewählten Text nicht zurück, wenn
378 | Kapitel 15: Dokumente skripten
491-0.book Seite 379 Mittwoch, 4. April 2007 9:55 09
e-bol.net er sich in einem - oder -Formularelement befindet: Sie liefern nur ausgewählten Text aus dem Dokument selbst zurück. Die IE-Eigenschaft document.selection liefert jedoch ausgewählten Text von allen Stellen des Dokuments zurück.
function getTextFieldSelection(e) { if (e.selectionStart != undefined && e.selectionEnd != undefined) { var start = e.selectionStart; var end = e.selectionEnd; return e.value.substring(start, end); } else return ""; // In diesem Browser nicht unterstützt }
15.11 Das IE 4 DOM Obwohl der IE 4 das W3C DOM nicht implementiert, unterstützt er eine API, die viele Fähigkeiten bietet, die denen des Kern-W3C DOMs entsprechen. IE 5 und höher unterstützen das IE 4 DOM, und einige andere Browser bieten zumindest eine partielle Kompatibilität. Als dies geschrieben wurde, war der IE 4-Browser nicht mehr weit verbreitet. Neu geschriebener JavaScript-Code muss normalerweise nicht mit Kompatibilität zum IE 4 geschrieben werden. Deswegen wurden große Teile des Referenzmaterials für das IE 4 DOM in dieser Auflage des Buchs aus Teil IV gelöscht. Trotzdem gibt es immer noch eine große Menge bestehenden Codes, der immer noch das IE 4 DOM verwendet. Deswegen ist es nützlich, wenn man mit dieser API zumindest in ihren Grundzügen vertraut ist.
15.11.1 Ein Dokument durchqueren Das W3C DOM gibt vor, dass alle Node-Objekte, das Document-Objekt und alle Element-Objekte eingeschlossen, ein childNodes[]-Array haben, das die Kinder des Knotens enthält. Der IE 4 bietet keine Unterstützung für childNodes[], bietet aber ein ähnliches children[]-Array auf seinen Document- und HTMLElement-Objekten. Deswegen ist es leicht, eine rekursive Funktion wie die in Beispiel 15-2 gezeigte zu schreiben, um die vollständige Menge von HTML-Elementen in einem IE 4-Dokument zu durchqueren. Es gibt allerdings einen substanziellen Unterschied zwischen dem children[]-Array des IE 4 und dem childNodes[]-Array des W3C DOMs. Der IE 4 kennt keinen Text-Knotentyp und betrachtet Textstrings nicht als Kinder. Ein
-Tag, das nur Klartext ohne Markup enthält, hat im IE 4 also ein leeres children[]-Array. Wie Sie in Kürze sehen werden, steht der Textinhalt eines
-Tags über die IE 4-Eigenschaft innerText zur Verfügung.
15.11 Das IE 4 DOM |
379
clientseitiges JavaScript
In Firefox definieren Texteingabeelemente die Eigenschaften selectionStart und selectionEnd, die Sie einsetzen können, um den ausgewählten Text abzufragen (oder zu setzen). Zum Beispiel:
491-0.book Seite 380 Mittwoch, 4. April 2007 9:55 09
e-bol.net
15.11.2 Dokumentelemente finden IE 4 bietet keine Unterstützung für die getElementById( )- und getElementsByTagName( )Methoden des Document-Objekts. Stattdessen haben das Document-Objekt und alle Dokumentelemente eine Array-Eigenschaft namens all[]. Wie der Name andeutet, repräsentiert dieses Array alle Elemente in einem Dokument oder alle Elemente, die in einem anderen Element enthalten sind. Beachten Sie, dass all[] nicht einfach die Kinder des Document-Objekts oder eines Elements repräsentiert. Es repräsentiert alle Nachfahren, egal wie tief sie eingebettet sind. Das Array all[] kann auf mehrere Weisen verwendet werden. Wenn Sie es mit einem Integer n indizieren, liefert es das n+1. Element des Dokuments oder Elternelements zurück. Zum Beispiel: var e1 = document.all[0]; var e2 = e1.all[4];
// Das erste Element des Dokuments // Das fünfte Element von Element 1
Elemente werden in der Reihenfolge nummeriert, in der sie in der Dokumentquelle erscheinen. Beachten Sie einen wichtigen Unterschied zwischen der IE 4 API und dem DOM-Standard: Der IE kennt keine Text-Knoten. Das Array all[] enthält also nur Dokumentelemente, nicht den Text, der zwischen ihnen erscheint. In der Regel ist es viel praktischer, auf Dokumentelemente über einen Namen statt über eine Nummer zu verweisen. Das IE 4-Äquivalent zu getElementbyId( ) ist es, das Array all[] mit einem String statt mit einer Zahl zu indizieren. Wenn Sie das tun, liefert der IE 4 das Element zurück, dessen id- oder name-Attribut den angegebenen Wert hat. Wenn es mehrere derartige Elemente gibt (was passieren kann, weil es häufig vorkommt, dass mehrere Formularelemente wie Radiobutton das gleiche name-Attribut haben), ist das Ergebnis ein Array mit diesen Elementen. Zum Beispiel: var besondererAbsatz = document.all["besondererAbsatz"]; var buttons = form.all["lieferungsart"]; // Kann ein Array zurückliefern
JavaScript erlaubt Ihnen, diese Ausdrücke so zu schreiben, dass der Array-Index als Eigenschaftsname ausgedrückt wird: var besondererAbsatz = document.all.besondererAbsatz; var buttons = form.all.lieferungsart;
Wird das Array all[] auf diese Weise verwendet, stellt es die gleiche Grundfunktionalität wie getElementById( ) und getElementsByName( ) zur Verfügung steht. Der Hauptunterschied ist, dass das Array all[] die Features dieser beiden Methoden kombiniert. Das kann zu Problemen führen, wenn Sie aus Versehen die gleichen Werte für die id- und name-Attribute nicht verwandter Elemente verwenden. Das Array all[] hat eine ungewöhnliche Eigenart: Es kann eine tags( )-Methode verwenden, um ein Array mit Elementen mit diesem Tag-Namen zu erhalten. Zum Beispiel: var liste = document.all.tags("UL"); // Alle
-Tags im Dokument finden var elemente = lists[0].all.tags("LI"); // Alle
-Tags im ersten
finden
380 | Kapitel 15: Dokumente skripten
491-0.book Seite 381 Mittwoch, 4. April 2007 9:55 09
e-bol.net Diese IE 4-Syntax bietet im Wesentlichen die gleiche Funktionalität wie die standardmäßige getElementsByTagName( )-Methode der Interfaces Document und Element. Beachten Sie allerdings, dass der Tag-Name im IE 4 vollständig in Großbuchstaben angegeben werden muss.
Wie das W3C DOM veröffentlicht der IE 4 die Attribute von HTML-Tags als Eigenschaften der entsprechenden HTMLElement-Objekte. Deswegen ist es möglich, ein im IE 4 angezeigtes Element zu modifizieren, indem dynamisch seine HTML-Attribute geändert werden. Wenn eine Attributänderung die Größe eines Elements ändert, wird das Dokument neu aufgebaut, um die neue Größe des Elements aufzunehmen. Das HTMLElement-Objekt des IE 4 definiert ebenfalls die Methoden setAttribute( ), getAttribute( ) und removeAttribute( ). Diese ähneln den Methoden gleichen Namens, die vom ElementObjekt in der Standard-DOM API definiert werden. Das W3C DOM definiert eine API, die es ermöglicht, neue Knoten zu erzeugen, Knoten in den Dokumentbaum einzufügen, Knoten neue Elternknoten zu geben und Knoten im Baum zu verschieben. Der IE 4 kann das nicht. Stattdessen definieren alle HTMLElement-Objekte im IE 4 eine innerHTML-Eigenschaft. Dass Sie diese Eigenschaft auf einen String mit HTML-Text setzen können, ermöglicht Ihnen, den Inhalt eines Elements beliebig zu ändern. Weil diese innerHTML-Eigenschaft so mächtig ist, wurde sie von allen modernen Browsern implementiert. Und es scheint wahrscheinlich, dass sie in eine zukünftige Version des DOM-Standards integriert wird. innerHTML wurde in Abschnitt 15.8.2 beschrieben und eingesetzt. IE 4 definiert außerdem einige verwandte Eigenschaften und Methoden. Die Eigenschaft outerHTML ersetzt den Inhalt eines Elements und das Element selbst durch einen angegebenen String mit HTML-Text. Die Eigenschaften innerText und outerText ähneln innerHTML und outerHTML, behandeln den String aber als Klartext und parsen ihn nicht als HTML. Die Methoden insertAdjacentHTML( ) und insertAdjacentText( ) lassen schließlich den Inhalt eines Elements unverändert, fügen aber bei ihm (vor oder nach ihm, in ihm oder außerhalb von ihm) neues HTML oder neuen Klartext ein. Diese Eigenschaften und Funktionen werden nicht so verbreitet verwendet wie innerHTML und wurden von Firefox nicht implementiert.
15.11 Das IE 4 DOM |
381
clientseitiges JavaScript
15.11.3 Dokumente modifizieren
491-0.book Seite 382 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Chapter 1
KAPITEL 16
Cascading Style Sheets und dynamisches HTML Cascading Style Sheets (CSS) sind ein Standard, mit dem sich die Präsentation von HTML- oder XML-Dokumenten festlegen lässt. Theoretisch sollten Sie HTML-Markierungen verwenden, um die Struktur Ihres Dokuments festzulegen. Widerstehen Sie der Versuchung, veraltete HTML-Tags wie zu verwenden, um das Aussehen Ihres Dokuments anzugeben! Verwenden Sie stattdessen CSS zur Definition eines Stylesheets, das angibt, wie die strukturierten Elemente Ihres Dokuments angezeigt werden sollen. Beispielsweise können Sie CSS verwenden, um festzulegen, dass die durch -Tags definierten Überschriften erster Kategorie in fetter serifenloser Schrift, zentriert und in Großbuchstaben von 24 Punkt Größe angezeigt werden sollen. Cascading Style Sheets stellen eine Technologie bereit, die zur Verwendung durch Grafikdesigner und andere Leute gedacht ist, die die visuelle Darstellung von HTML-Dokumenten exakt kontrollieren wollen. Für die Programmierung clientseitigen JavaScripts sind sie interessant, weil sich die Styles, die auf die einzelnen Elemente eines Dokuments angewendet werden, über das Document Object Model per Skript steuern lassen. In Verbindung mit CSS ermöglicht JavaScript eine Vielzahl von visuellen Effekten, die auch gemeinhin als dynamisches HTML (DHTML)1 bezeichnet werden. Durch die Möglichkeit, mit Skripten auf Stylesheets zuzugreifen, können Sie Farben, Schriftarten usw. dynamisch ändern. Wichtiger noch: Sie können die Position von Elementen angeben und ändern und sie sogar anzeigen und verbergen. Sie können also DHTMLTechniken zur Erzeugung animierter Übergänge verwenden, bei denen der Dokumentinhalt beispielsweise von rechts »eingeschoben« wird, oder zur Erzeugung einer erweiterbaren und verkleinerbaren Umrissliste, bei der der Benutzer den angezeigten Informationsumfang bestimmen kann. Dieses Kapitel beginnt mit einer Übersicht über CSS. Dann werden die wichtigsten CSSStyles zur Erzeugung verbreiteter DHTML-Effekte erklärt. Als Nächstes beschreibt das 1 Viele fortgeschrittene DHTML-Effekte beziehen auch die in Kapitel 17 gezeigten Techniken zum Umgang mit Events ein.
382 |
491-0.book Seite 383 Mittwoch, 4. April 2007 9:55 09
e-bol.net
16.1 Überblick über CSS In CSS werden Styles als eine Liste von Name-Wert-Paaren angegeben, wobei jedem Name-Wert-Paar ein Semikolon als Trennzeichen folgt. In jedem Paar sind Name und Wert durch einen Doppelpunkt getrennt. Beispielsweise gibt der folgende Style einen fetten, blauen, unterstrichenen Text an: font-weight: bold; color: blue; text-decoration: underline;
Der CSS-Standard definiert viele Eigenschaften. Tabelle 16-1 führt die wichtigsten Eigenschaften auf, mit Ausnahme einiger schlecht unterstützter. Sie müssen diese Eigenschaften und ihre Werte und Bedeutungen nicht alle kennen oder verstehen. Wenn Sie CSS jedoch häufiger in Ihren Dokumenten und Skripten benutzen, kann Ihnen diese Tabelle als einfache Kurzreferenz nützlich sein. Eine ausführlichere Dokumentation zu CSS finden Sie in CSS: Das umfassende Handbuch von Eric Meyer (O’Reilly) und in Dynamic HTML: The Definitive Reference von Danny Goodman (O’Reilly). Sie können auch die Spezifikation selbst lesen, die unter http://www.w3c.org/TR/CSS21/ steht. Die rechte Spalte von Tabelle 16-1 gibt die Werte an, die für die einzelnen Eigenschaften erlaubt sind. Sie verwendet die Grammatik, die von der CSS-Spezifikation verwendet wird. In Festbreitenschrift angegebene Elemente sind Schlüsselwörter, die genau wie gezeigt angegeben werden müssen. In kursiver Schrift angegebene Elemente geben einen Datentyp wie String oder eine Länge an. Beachten Sie, dass der Typ length eine Zahl ist, an die sich eine Einheitsangabe, wie z.B. px (für Pixel), anschließt. In einer CSS-Referenz finden Sie weitere Details zu den anderen Typen. Elemente in einer kursiven Festbreitenschrift geben die Menge der erlaubten Werte an, die eine andere CSS-Eigenschaft besitzen kann. Zusätzlich zu den in der Tabelle aufgeführten Werten kann jede Eigenschaft den Wert »inherit« enthalten, der angibt, dass sie den Wert ihrer übergeordneten Eigenschaft erben soll. Durch | getrennte Werte stellen Alternativen dar; Sie müssen genau eine von ihnen angeben. Durch || getrennte Werte sind Optionen, von denen Sie mindestens eine angeben müssen; Sie dürfen jedoch auch mehrere Werte in beliebiger Reihenfolge angeben. Eckige Klammern [] gruppieren Werte. Ein Stern (*) gibt an, dass der vorhergehende Wert bzw. die vorhergehende Gruppe nullmal oder öfter auftreten darf; ein Plus-Zeichen (+) gibt an,
16.1 Überblick über CSS |
383
clientseitiges JavaScript
Kapitel unterschiedliche Arten der CSS-Skriptsteuerung. Die am häufigsten gebrauchte und wichtigste Technik ist die Skriptsteuerung der Styles einzelner Dokumentelemente über die style-Eigenschaft. Eine verwandte Technik modifiziert indirekt den Stil eines Elements, indem sie die CSS-Klassen ändert, die auf dieses Element angewendet werden. Das wird durch das Setzen oder Ändern der className-Eigenschaft des Elements erreicht. Stylesheets können auch direkt skriptgesteuert werden. Das Kapitel schließt mit einer Erläuterung der Aktivierung und Deaktivierung von Stylesheets und dem Abfragen, Hinzufügen und Entfernen von Stylesheet-Regeln.
491-0.book Seite 384 Mittwoch, 4. April 2007 9:55 09
e-bol.net dass der vorhergehende Wert bzw. die vorhergehende Gruppe einmal oder öfter auftreten darf; ein Fragezeichen (?) gibt an, dass das vorhergehende Element optional ist und nulloder einmal auftreten darf. Zahlen in geschweiften Klammern geben eine Anzahl von Wiederholungen an. Beispielsweise legt {2} fest, dass das vorhergehende Element zweimal wiederholt werden muss. {1,4} gibt an, dass das vorhergehende Element mindestens einmal und nicht häufiger als viermal auftreten darf. (Diese Syntax für die Angabe von Wiederholungen könnte Ihnen bekannt vorkommen: Sie gleicht der in Kapitel 11 vorgestellten Syntax, die von regulären Ausdrücken in JavaScript verwendet wird.) Tabelle 16-1: CSS 2.1-Eigenschaften und ihre Werte Name
baseline | sub | super | top | text-top | middle | bottom | text-bottom |
percentage | length visibility
visible | hidden | collapse
white-space
normal | pre | nowrap | pre-wrap | pre-line
width
length | percentage | auto
word-spacing
normal | length
z-index
auto | integer
386 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 387 Mittwoch, 4. April 2007 9:55 09
e-bol.net Der CSS-Standard erlaubt es, häufig gemeinsam verwendete Eigenschaften mit Hilfe spezieller Kurzschrift-Eigenschaften zusammenzufassen. Beispielsweise können Sie die Eigenschaften font-family, font-size, font-style und font-weight gleichzeitig mit der einen Eigenschaft font setzen: font: bold italic 24pt helvetica;
16.1.1 Stilregeln auf Elemente eines Dokuments anwenden Sie können Eigenschaften auf Elemente eines Dokuments auf verschiedene Weise anwenden. Eine Möglichkeit besteht darin, sie im Attribut style eines HTML-Tags zu verwenden. Um beispielsweise die Rahmen eines einzelnen Absatzes festzulegen, können Sie das folgende Tag verwenden:
Eines der wesentlichen Ziele von CSS besteht in der Trennung der Struktur von der Darstellung eines Dokuments. Die Angabe eines style-Attributs für einzelne HTML-Tags leistet dies nicht (auch wenn es eine nützliche Technik für DHTML sein kann). Um die Trennung von Struktur und Darstellung zu erreichen, verwenden wir Stylesheets, die alle Stilinformationen an einer einzelnen Stelle sammeln. Ein CSS-Stylesheet besteht aus einem Satz von Stilregeln. Jede Regel beginnt mit einem Selektor, der das oder die Elemente eines Dokuments angibt, für das bzw. die die Regel gilt. Darauf folgt eine Reihe von Eigenschaften und ihren Werten in geschweiften Klammern. Die einfachste Art solcher Regeln definiert Styles für einen oder mehrere bestimmte Tag-Namen. Beispielsweise legt die folgende Regel die Ränder und die Hintergrundfarbe des -Tags fest: body { margin-left: 30px; margin-right: 15px; background-color: #ffffff }
Die folgende Regel legt fest, dass Text in den Überschriften und zentriert werden soll: h1, h2 { text-align: center; }
Beachten Sie, wie im letzten Beispiel ein Komma verwendet wurde, um die Tag-Namen, für die die Styles angewendet werden sollen, voneinander zu trennen. Wenn das Komma weggelassen wird, gibt der Selektor eine Kontextregel an, die nur angewandt wird, wenn ein Tag in einem anderen eingeschlossen ist. Die folgenden Regeln legen beispielsweise fest, dass Text in -Tags in kursiver Schrift angezeigt werden soll, Text innerhalb eines -Tags in einem jedoch in normaler, nicht-kursiver Schrift: blockquote { font-style: italic; } blockquote i { font-style: normal; }
16.1 Überblick über CSS |
387
clientseitiges JavaScript
Die Kurzschrift-Eigenschaften margin und padding sind Abkürzungen für Eigenschaften, die Außen- und Innenabstände für die einzelnen Seiten eines Elements festlegen. Anstelle von margin können Sie margin-left, margin-right, margin-top und margin-bottom verwenden; analog gilt dies für padding.
491-0.book Seite 388 Mittwoch, 4. April 2007 9:55 09
e-bol.net Eine weitere Art von Stylesheet-Regel verwendet einen anderen Selektor, um eine Klasse von Elementen anzugeben, auf die ihre Styles angewandt werden sollen. Die Klasse eines Elements wird durch das class-Attribut des HTML-Tags definiert. Beispielsweise legt die folgende Regel fest, dass jedes Tag mit dem Attribut class="attention" in fetter Schrift angezeigt werden soll: .attention { font-weight: bold; }
Klassenselektoren können mit den Selektoren für Tag-Namen kombiniert werden. Die folgende Regel legt fest, dass ein
-Tag, das das Attribut class="attention" trägt, nicht nur in fetter Schrift (wie von der vorhergehenden Regel festgelegt), sondern zusätzlich in Rot angezeigt werden soll: p.attention { color: red; }
Schließlich können Stylesheets Regeln enthalten, die nur auf einzelne Elemente angewandt werden, für die ein id-Attribut angegeben ist. Die folgende Regel legt fest, dass das Element, dessen Attribut id den Wert »p1« trägt, nicht angezeigt werden soll: #p1 { visibility: hidden; }
Das id-Attribut haben wir bereits im Zusammenhang mit der Document-Methode getElementById( ) kennengelernt, die einzelne Elemente eines Dokuments zurückgibt. Wie Sie sich vorstellen können, ist diese Art elementspezifischer Regel nützlich, wenn der Stil eines einzelnen Elements geändert werden soll. Wurde die obige Regel definiert, kann ein Skript beispielsweise den Wert des Attributs visibility von hidden in visible ändern und so das Element dynamisch erscheinen lassen. Sie werden weiter unten in diesem Kapitel sehen, wie das funktioniert. Der CSS-Standard definiert eine Anzahl weiterer Selektoren außer den einfachen hier gezeigten, und einige werden durch moderne Browser gut unterstützt. In den CSS-Spezifikationen oder einer CSS-Referenz finden Sie weitere Details.
16.1.2 Stylesheets zu Dokumenten zuordnen Sie können ein Stylesheet in ein HTML-Dokument einbeziehen, indem Sie es zwischen und -Tags im des Dokuments stellen. Beispielsweise: Testdokument body { margin-left: 30px; margin-right: 15px; background-color: #ffffff } p { font-size: 24px; }
Test, test
Wenn ein Stylesheet von mehr als einer Seite auf einer Website verwendet werden soll, ist es meist besser, es in einer eigenen Datei unterzubringen, ohne umgebende HTML-Tags.
388 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 389 Mittwoch, 4. April 2007 9:55 09
e-bol.net Diese CSS-Datei kann dann in die HTML-Seite einbezogen werden. Anders als das -Tag hat das -Tag aber kein src-Attribut. Um ein Stylesheet in eine HTML-Seite einzubinden, verwenden Sie stattdessen das -Tag:
Sie können ein -Tag auch zur Angabe eines alternativen Stylesheets verwenden. Einige Browser (wie z.B. Firefox) lassen den Benutzer eine der von Ihnen angegebenen Alternativen auswählen (über Ansicht ➝ Seitenstil). So können Sie beispielsweise ein alternatives Stylesheet für Besucher Ihrer Site bereitstellen, die große Schriftarten und Farben mit hohem Kontrast vorziehen: title="Große Schrift">
Wenn Ihre Webseite ein seitenspezifisches Stylesheet mit einem -Tag enthält, können Sie die CSS-Direktive-@import zur Einbeziehung einer gemeinsam benutzten CSSDatei in das seitenspezifische Stylesheet verwenden: Testdokument @import "meinestyles.css"; /* gemeinsames Stylesheet importieren */ p { font-size: 48px; } /* importierte Styles überschreiben */
Test, test
16.1.3 Die Kaskade Der Buchstabe C in CSS steht für cascading (fallend). Mit diesem Begriff soll angedeutet werden, dass die auf ein beliebiges Element anzuwendenden Stilregeln aus einer Kaskade verschiedener Quellen stammen können. Jeder Webbrowser besitzt üblicherweise seine eigenen voreingestellten Styles für alle HTML-Elemente; er kann es dem Benutzer erlauben, diese durch ein Benutzer-Stylesheet zu modifizieren. Der Autor eines Dokuments kann Stylesheets innerhalb der -Tags oder in externen Dateien definieren, die in andere Stylesheets eingebunden oder importiert werden können. Der Autor kann außerdem Styles für einzelne Elemente im HTML-Code mit dem Attribut style festlegen. Die Spezifikation von CSS enthält einen vollständigen Satz von Regeln, der festlegt, welche Regeln der Kaskade Vorrang vor welchen anderen Regeln haben. In aller Kürze besagen die wichtigsten Regeln, dass das Stylesheet des Benutzers Vorrang vor dem StandardStylesheet des Browsers hat, dass Stylesheets des Autors die Stylesheets des Benutzers
16.1 Überblick über CSS |
389
clientseitiges JavaScript
Testdokument
Test, test
491-0.book Seite 390 Mittwoch, 4. April 2007 9:55 09
e-bol.net überschreiben und dass eingebettete Styles alles andere überschreiben. Die Ausnahme von dieser allgemeinen Regel besteht darin, dass Style-Attribute des Benutzers, deren Werte den Modifikator !important enthalten, Autoren-Styles überschreiben. Wenn innerhalb eines Stylesheets mehrere Regeln auf ein Dokument zutreffen, überschreiben die Styles spezifischerer Regeln immer die Styles weniger spezifischer Regeln. Regeln, die ein Element id angeben, sind am spezifischsten, dann folgen Regeln, die eine class angeben. Am wenigsten spezifisch sind Regeln, die nur einen Tag-Namen angeben, wobei hier diejenigen Regeln, die mehrfach geschachtelte Tag-Namen angeben, spezifischer sind als solche, die nur einen einfachen Tag-Namen angeben.
16.1.4 Versionen von CSS CSS ist ein vergleichsweise alter Standard. CSS1 wurde im Dezember 1996 verabschiedet; in ihm werden die Eigenschaften für die Angabe von Farben, Schriftarten, Außenabständen, Rahmen und andere grundlegende Styles festgelegt. Sogar so alte Browser wie Netscape 4 und Internet Explorer 4 unterstützen einen signifikanten Teil von CSS1. Die zweite Version des Standards, CSS2, wurde im Mai 1998 verabschiedet; in ihm wurden viele erweiterte Merkmale definiert, insbesondere solche zur Unterstützung einer absoluten Positionierung von Elementen. Als dieses Buch geschrieben wurde, wurden CSS2Features in den aktuellen Browsern halbwegs gut unterstützt. Die wichtigen Merkmale zur Positionierung wurden schon im Rahmen des CSS-Positioning (CSS-P) standardisiert, sodass diese Merkmale zur Unterstützung von DHTML in praktisch allen heute installierten Browsern verfügbar sind. (Diese wichtigen Styles zur Positionierung werden später in diesem Kapitel behandelt). Die Arbeit an CSS geht weiter. Als dieses Buch geschrieben wurde, war die Spezifikation von CSS 2.1 fast komplett. Sie klärt die CSS2-Spezifikation, behebt Fehler und entfernt einige CSS2-Styles, die nie irgendwo in einem Browser implementiert wurden. Für Version 3 wurde die CSS-Spezifikation in mehrere spezialisierte Module aufgeteilt, die den Standardisierungsprozess separat durchlaufen. Einige CSS3-Module sind fast komplett, und einige Browser fangen an, ausgewählte CSS3-Features zu implementieren, wie z.B. die opacity-Eigenschaft. Die Spezifikationen der einzelnen Versionen und die Arbeitsentwürfe können Sie unter http://www.w3.org/Style/CSS/ finden.
16.1.5 Ein CSS-Beispiel Beispiel 16-1 besteht aus einer HTML-Datei, die ein Stylesheet definiert und verwendet. Es zeigt die oben beschriebenen Stilregeln, die auf Tag-Namen, Klassen und IDs basieren. Außerdem enthält es ein Beispiel eines eingebetteten Styles, der mit dem Attribut style definiert wird. Abbildung 16-1 zeigt, wie dieses Beispiel in einem Browser wiedergegeben wird. Dieses Beispiel gibt nur einen Überblick über die Syntax und die Fähigkeiten von CSS. Eine umfassende Betrachtung von CSS würde den Rahmen dieses Buchs sprengen.
390 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 391 Mittwoch, 4. April 2007 9:55 09
e-bol.net
clientseitiges JavaScript
Abbildung 16-1: Eine mit CSS gestaltete Webseite Beispiel 16-1: Definition und Verwendung von Cascading Style Sheets /* Überschriften sollen in blauer, kursiver Schrift angezeigt werden. */ h1, h2 { color: blue; font-style: italic } /* * Elemente der Klasse class="WARNUNG" werden in großem, fettem Text mit breiten Rändern, * gelbem Hintergrund und breitem, rotem Rahmen angezeigt. */ .WARNUNG { font-weight: bold; font-size: 150%; margin: 0 1in 0 1in; /* oben rechts unten links */ background-color: yellow; border: solid red 8px; padding: 10px; /* 10 Pixel auf allen vier Seiten */ } /* * Text in einer Überschrift des Typs h1 oder h2 in einem Element der * class="WARNUNG" wird zentriert (zusätzlich zur blauen, kursiven Schrift). */ .WARNUNG h1, .WARNUNG h2 { text-align: center }
16.1 Überblick über CSS |
391
491-0.book Seite 392 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 16-1: Definition und Verwendung von Cascading Style Sheets (Fortsetzung) /* Das Element mit id="P23" wird zentriert in Großbuchstaben angezeigt. */ #P23 { text-align: center; text-transform: uppercase; } Demonstration von Cascading Style Sheets Warnung Dies ist eine Warnung! Sie zieht mit ihrem fetten Text und den kräftigen Farben Ihre Aufmerksamkeit auf sich. Die Überschrift ist zentriert und erscheint in blauer, kursiver Schrift.
Dieser Absatz ist zentriert und erscheint in Großbuchstaben. Hier verwenden wir einen eingebetteten Style, um die Großbuchstaben zu deaktivieren.
16.2 CSS für DHTML Für Entwickler von DHTML-Inhalten ist das wichtigste Merkmal von CSS die Fähigkeit, mit gewöhnlichen CSS-Eigenschaften die Sichtbarkeit, die Größe und die exakte Position einzelner Elemente eines Dokuments festlegen zu können. Mit anderen CSS-Styles können Sie die Stapelordnung, Transparenz, Clipping-Region, Außen- und Innenabstände, Rahmen und Farben angeben. Um in DHTML programmieren zu können, ist es wichtig zu verstehen, wie diese Eigenschaften funktionieren. Sie sind in Tabelle 16-2 zusammengestellt und werden in den folgenden Abschnitten ausführlicher dokumentiert. Tabelle 16-2: CSS-Eigenschaften für Positionierung und Sichtbarkeit Eigenschaft(en)
Beschreibung
position
gibt den Typ der auf ein Element angewandten Positionierung an
top, left
gibt die Position der oberen und linken Kante eines Elements an
bottom, right
gibt die Position der unteren und rechten Kante eines Elements an
width, height
gibt die Größe eines Elements an
z-index
gibt die »Höhe« eines Elements relativ zu überlappenden Elementen an; sie definiert eine dritte Dimension für die Positionierung von Elementen
392 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 393 Mittwoch, 4. April 2007 9:55 09
e-bol.net Tabelle 16-2: CSS-Eigenschaften für Positionierung und Sichtbarkeit (Fortsetzung) Beschreibung
display
gibt an, ob und wie ein Element angezeigt wird
visibility
gibt an, ob ein Element sichtbar ist
clip
definiert eine »Clipping-Region« für ein Element; nur innerhalb dieser Region liegende Teile des Elements werden angezeigt
overflow
gibt an, was zu tun ist, wenn ein Element größer ist als der für es vorgesehene Platz
margin, border, padding
geben die Abstände und Rahmen für ein Element an
background
gibt Hintergrundfarbe oder -bild eines Elements an
opacity
gibt an, wie deckend (oder lichtdurchlässig) ein Element ist; dabei handelt es sich um eine CSS3-Eigenschaft, das von ein paar Browsern unterstützt wird. Eine funktionsfähige Alternative für IE existiert.
16.2.1 Der Schlüssel zu DHTML: Absolute Positionierung Die CSS-Eigenschaft position gibt an, welche Art von Positionierung auf das Element angewandt werden soll. Die vier möglichen Werte dieser Eigenschaft sind: static
Dies ist der voreingestellte Wert. Er gibt an, dass das Element der normalen Abfolge der Dokumenteninhalte entsprechend positioniert werden soll (also bei den meisten westlichen Sprachen von links nach rechts und von oben nach unten). Statisch positionierte Elemente sind keine DHTML-Elemente; sie können nicht mit top, left oder anderen Eigenschaften positioniert werden. Um die Positionierungstechniken von DHTML anwenden zu können, müssen Sie zunächst die Eigenschaft position eines Elements auf einen der anderen drei Werte setzen. absolute
Dieser Wert ermöglicht die Angabe einer Position eines Elements relativ zu dem umgebenden Element. Absolut positionierte Elemente werden unabhängig von allen anderen Elementen positioniert und sind nicht Teil der Abfolge, in der statisch positionierte Elemente angeordnet werden. Ein absolut positioniertes Element wird entweder relativ zum des Dokuments oder, wenn es in einem anderen positionierten Element enthalten ist, relativ zu diesem Element angeordnet. Dies ist der am häufigsten verwendete Positionierungstyp in DHTML. IE 4 unterstützt nur die absolute Positionierung bestimmter Elemente. Wenn Sie diesen alten Browser unterstützen wollen, stellen Sie sicher, dass Sie Ihre absolut positionierten Elemente in - oder -Tags verpacken. fixed
Mit diesem Wert können Sie die Position eines Elements relativ zum Browserfenster angeben. Elemente mit der Positionierung fixed sind immer sichtbar und bewegen sich nicht, wenn das Dokument gescrollt wird. Wie absolut positionierte Elemente sind auch Elemente mit fester Position unabhängig von allen anderen und damit
16.2 CSS für DHTML |
393
clientseitiges JavaScript
Eigenschaft(en)
491-0.book Seite 394 Mittwoch, 4. April 2007 9:55 09
e-bol.net nicht Teil der Dokumentabfolge. Feste Positionierung wird in den meisten modernen Browsern unterstützt, mit der bemerkenswerten Ausnahme von IE 6. relative
Wenn die Eigenschaft position auf den Wert relative gesetzt ist, wird das Element entsprechend der normalen Dokumentabfolge positioniert. Die Position wird relativ zur Position im normalen Fluss angepasst. Der für das Element vorgesehene Platz in der normalen Dokumentabfolge bleibt reserviert, sodass seitlich angezeigte Elemente weder den leeren Platz auffüllen noch durch die neue Positionierung des Elements verdrängt werden. Nachdem Sie die Eigenschaft position eines Elements auf einen anderen Wert als static gesetzt haben, können Sie die Position dieses Elements mit einer Kombination der Eigenschaften left, top, right und bottom festlegen. Die am häufigsten verwendete Technik besteht in der Angabe der Eigenschaften left und top, die den Abstand vom linken Rand des umgebenden Elements (dies ist meist das Dokument selbst) zum linken Rand des Elements bzw. vom oberen Rand des umgebenden Elements zum oberen Rand des Elements festlegen. Um beispielsweise ein Element 100 Pixel von links und 100 Pixel vom oberen Rand des Dokuments entfernt zu platzieren, können Sie CSS-Styles in einem style-Attribut folgendermaßen festlegen:
Das umgebende Element, relativ zu dem ein dynamisches Element positioniert wird, ist nicht unbedingt dasselbe wie das umgebende Element, in dem das dynamische Element im Quelltext des Dokuments definiert ist. Da dynamische Elemente nicht Teil der normalen Dokumentabfolge sind, werden ihre Positionen nicht relativ zu dem statischen Container angegeben, in dem sie definiert sind. Die meisten dynamischen Elemente werden relativ zum Dokument selbst (dem -Tag) positioniert. Eine Ausnahme stellen dynamische Elemente dar, die in anderen dynamischen Elementen definiert sind. In diesem Fall wird das eingebettete dynamische Element relativ zum nächsten dynamischen Vorfahren positioniert. Wenn Sie ein Element relativ zu einem Container positionieren wollen, der Teil der normalen Dokumentabfolge ist, verwenden Sie position:relative für den Container und geben eine top- und left-Position von 0px an. Das positioniert den Container dynamisch, belässt ihn aber an seinem normalen Platz in der Dokumentabfolge. Etwaige absolut positionierte Kinder werden dann relativ zum Container positioniert. Obwohl es üblich ist, die Position der oberen linken Ecke eines Elements mit left und top festzulegen, können Sie auch right und bottom verwenden, um die Position der unteren und der rechten Kante eines Elements relativ zur unteren und rechten Kante des umgebenden Elements festzulegen. Um beispielsweise ein Element so zu positionieren, dass die untere rechte Ecke in der unteren rechten Ecke des Dokuments liegt, können Sie die folgenden Styles verwenden (wobei wir annehmen, dass das Element nicht in einem anderen dynamischen Element enthalten ist): position: absolute; right: 0px; bottom: 0px;
394 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 395 Mittwoch, 4. April 2007 9:55 09
e-bol.net Um ein Element so zu positionieren, dass seine obere Kante 10 Pixel vom oberen Rand und seine rechte Kante 10 Pixel vom rechten Rand des Fensters entfernt ist und es nicht mit dem Dokument scrollt, können Sie die folgenden Styles verwenden: position: fixed; right: 10px; top: 10px;
Sie können die Breite eines Elements auch durch die Angabe von Werten für die Eigenschaften left und right festlegen sowie die Höhe durch Angabe von Werten für die Attribute top und bottom bestimmen. Wenn Sie allerdings Werte für left, right und width angeben, hat width Vorrang vor dem right; analog dazu hat height Vorrang vor bottom, falls sich die Höhenangaben widersprechen. Denken Sie daran, dass es nicht notwendig ist, die Größe jedes dynamischen Elements festzulegen. Einige Elemente, wie beispielsweise Bilder, besitzen von sich aus bereits eine Größe. Auch für dynamische Elemente, die Text oder anderen fließenden Inhalt enthalten, reicht oft die Angabe der gewünschten Breite aus; die Höhe ergibt sich dann automatisch aus dem Layout des Elementinhalts. In den letzten Beispielen zur Positionierung wurden die Werte für die Position und Größe mit dem Suffix »px« angegeben, was für Pixel steht. Der CSS-Standard erlaubt die Angabe von Maßen in verschiedenen Einheiten; dazu gehören Zoll (»in«), Zentimeter (»cm«), Punkt (»pt«) und »em« (ein Maß für die Breite des Buchstabens »m« in der gerade verwendeten Schriftart). Pixel werden bei der DHTML-Programmierung am häufigsten verwendet. Beachten Sie, dass der CSS-Standard die Angabe einer Einheit vorschreibt. Manche Browser nehmen an, dass Sie Pixel meinen, wenn Sie keine Einheit angeben; darauf verlassen sollten Sie sich jedoch nicht. Statt absoluter Positionen und Größen in den oben genannten Einheiten können Sie bei CSS auch Prozentangaben verwenden, die sich auf die Größe des umgebenden Elements beziehen. Beispielsweise erzeugt der folgende HTML-Code ein leeres Element mit einem schwarzen Rahmen, der halb so breit und halb so hoch wie das umgebende Element (oder das Browserfenster) und in diesem zentriert ist:
16.2 CSS für DHTML |
395
clientseitiges JavaScript
Außer der Position von Elementen können Sie mit CSS auch deren Größe angeben. Dies geschieht meist durch Angabe von Werten für die Eigenschaften width und height. Beispielsweise erzeugt der folgende HTML-Code ein absolut positioniertes Element ohne Inhalt. Durch die Eigenschaften width, height und background-color erscheint es als kleines, blaues Viereck.
491-0.book Seite 396 Mittwoch, 4. April 2007 9:55 09
e-bol.net
16.2.2 CSS-Positionierungsbeispiel: Text mit Schatten Die CSS2-Spezifikation enthielt eine text-shadow-Eigenschaft zum Erzeugen von Schattenwurfeffekten unter Text. Diese Eigenschaft wurde vom Safari-Browser implementiert, aber von keinem anderen wichtigen Browserhersteller aufgegriffen und aus CSS2.1 entfernt, zur Neubegutachtung unter CSS3. Sie können Schatteneffekte bei Text allerdings auch ohne text-shadow erreichen. Sie müssen einfach nur die CSS-Positionierung verwenden und willens sein, den gewünschten Text zu wiederholen: einmal für den eigentlichen Text und einmal (oder mehr als einmal) für den oder die Schatten. Der folgende Code produziert die in Abbildung 16-2 gezeigte Ausgabe: Schatten Schatten Schatten Schatten | Kein Schatten
Abbildung 16-2: Schattierter Text mit CSS-Positionierung
Das hier gezeigte manuelle Hinzufügen von Schatten ist umständlich und verletzt das Prinzip der Trennung von Inhalt und Präsentation. Sie können dieses Problem durch etwas unauffälliges JavaScript beheben. Beispiel 16-2 ist ein JavaScript-Modul namens Schatten.js. Es definiert eine Funktion Schatten.addAll( ), die das Dokument (oder einen Teil desselben) nach Tags durchsucht, die ein schatten-Attribut haben. Wenn es ein solches Tag findet, parst es den Wert des schatten-Attributs und verwendet DOM und
396 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 397 Mittwoch, 4. April 2007 9:55 09
e-bol.net Skriptsteuerung, um dem Text im Tag Schatten hinzuzufügen. Als Beispiel können Sie dieses Modul verwenden, um die in Abbildung 16-2 gezeigte Ausgabe zu produzieren:
Der Code für das Schatten.js-Modul folgt. Beachten Sie, dass es sich dabei zum größten Teil um ein Beispiel für Skriptsteuerung des DOM handelt, das zufällig CSS auf eine interessante Weise verwendet. Bis auf eine Zeile steuert dieses Beispiel CSS nicht selbst: Es setzt einfach nur CSS-Eigenschaften an den Dokumentelementen, die es erzeugt. Später in diesem Kapitel zeige ich detailliertere Techniken zum Skripten von CSS. Beispiel 16-2: Schattierten Text mit unauffälligem JavaScript erzeugen /** * Schatten.js: schattierter Text mit CSS. * * Dieses Modul definiert ein einziges globales Objekt namens Schatten. * Die Eigenschaften dieses Objekts sind zwei Utility-Funktionen. * * Schatten.add(element, schatten): * Füge den angegebenen Schatten zum angegebenen Element hinzu. Das erste Argument * ist ein Dokumentelement oder eine Element-id. Dieses Element muss einen einzigen * Textknoten als Kind haben. Dieses Kind wird schattiert. * Schatten werden über ein Stringargument angegeben, dessen Syntax unten * erklärt wird. * * Schatten.addAll(root, tagname): * Finde alle Abkömmlinge des angegebenen Wurzelelements, die den * angegebenen Tagnamen haben. Wenn eines dieser Elemente ein Attribut namens * schatten hat, rufe Schatten.add( ) für das Element und den Wert seines * schatten-Attributs auf. Wenn tagname nicht angegeben ist, werden alle Elemente geprüft. * Wenn root nicht angegeben ist, wird das Document-Objekt verwendet. Diese Funktion sollte * nur einmal aufgerufen werden, und zwar nach dem ersten Laden eines Dokuments. * * Schatten-Syntax * * Schatten werden als String im Format [x y farbe]+ angegeben, d.h. als ein * oder mehrere Triplets, die einen x- und y-Offset und eine Farbe angeben. Jeder * dieser Werte muss in gültigem CSS-Format sein. Wenn mehr als ein Schatten * angegeben ist, wird der erste angebene Schatten der unterste, über dem * die anderen Schatten liegen, z.B.: "4px 4px #ccc 2px 2px #aaa" */ var Schatten = {};
16.2 CSS für DHTML |
397
clientseitiges JavaScript
Schatten | Kein Schatten
491-0.book Seite 398 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 16-2: Schattierten Text mit unauffälligem JavaScript erzeugen (Fortsetzung) // Füge Schatten an ein einzelnes angegebenes Element an Schatten.add = function(element, schatten) { if (typeof element == "string") element = document.getElementById(element); // Brich den Schattenstring an Whitespace auseinander, nach Entfernen // von Whitespace an Anfang und Ende. schatten = schatten.replace(/^\s+/, "").replace(/\s+$/, ""); var args = schatten.split(/\s+/); // Finde den Textknoten, der zu schattieren ist. // Dieses Modul wäre robuster, wenn wir alle Kinder schattieren würden. // Aus Gründen der Einfachheit belassen wir es bei einem. var textnode = element.firstChild; // Gib dem Containerelement relative Positionierung, damit // der Schatten relativ dazu positioniert werden kann. // Wir lernen noch, wie man die style-Eigenschaft so skriptsteuern kann. element.style.position = "relative"; // Erzeuge den Schatten var numschatten = args.length/3; for(var i = 0; i < numschatten; i++) { var schattenX = args[i*3]; var schattenY = args[i*31]; var schattenFarbe = args[i*3 + 2];
// // // // //
Wie viele Schatten? für jeden X-Offset ermitteln Y-Offset ermitteln und die Farbargumente
// Erzeuge ein neues zur Aufnahme des Schattens var schatten = document.createElement("span"); // Verwende sein style-Attribut zur Angabe von Offset und Farbe schatten.setAttribute("style", "position:absolute; " + "left:" + schattenX + "; " + "top:" + schattenY + "; " + "color:" + schattenFarbe + ";"); // Füge dem schatten-Span eine Kopie des Textknotens hinzu schatten.appendChild(textnode.cloneNode(false)); // und füge das Span in den Container ein element.appendChild(schatten); } // Jetzt setzen wir den Text über den Schatten. Erzeuge zuerst ein var text = document.createElement("span"); text.setAttribute("style", "position: relative"); // positioniere es text.appendChild(textnode); // Verschiebe den Original-Textknoten in dieses Span element.appendChild(text); // und füge es in den Container ein }; // Durchsuche den Dokumentenbaum am und unter dem angegebenen Wurzelelement // nach Elementen mit dem angegebenen Tag-Namen. Wenn eines davon ein schatten-Attribut hat, // übergib es an die Schatten.add( )-Methode oben zur Erzeugung des Schattens.
398 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 399 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 16-2: Schattierten Text mit unauffälligem JavaScript erzeugen (Fortsetzung) // Wenn root nicht angegeben ist, verwende das Document// Objekt. Wenn tagname nicht angegeben ist, durchsuche alle Tags. Schatten.addAll = function(root, tagname) { if (!root) root = document; // Verwende ganzes Dokument, wenn root fehlt if (!tagname) tagname = '*'; // Alle Tags nehmen, wenn tagname fehlt // // // //
clientseitiges JavaScript
var elemente = root.getElementsByTagName(tagname); for(var i = 0; i < elemente.length; i++) { var schatten = elemente[i].getAttribute("schatten"); if (schatten) Schatten.add(elemente[i], schatten); }
Finde alle Tags Für jedes Tag: Hat es einen Schatten? Erzeuge den Schatten
};
16.2.3 Abfrage der Position und Abmessungen von Elementen Nachdem Sie jetzt wissen, wie die Position und Größe von HTML-Elementen mit CSS gesetzt wird, stellt sich natürlich die Frage, wie Sie die Position und Größe eines Elements abfragen können. Vielleicht möchten Sie die CSS-Positionierung verwenden, um ein DHTML-Popup-»Fenster« über einem anderen HTML-Element zu zentrieren. Dazu müssen Sie die Position und Abmessungen des Elements kennen. In modernen Browsern geben die Eigenschaften offsetLeft und offsetTop eines Elements die X- und Y-Koordinate des Elements zurück. Ebenso geben die Eigenschaften offsetWidth und offsetHeight die Breite und Höhe zurück. Diese Eigenschaften sind schreibgeschützt und geben Pixelwerte als Zahlen zurück (nicht als CSS-Strings mit den angefügten »px«-Einheiten). Sie reflektieren die CSS-Eigenschaften left, top, width und height, sind aber nicht Teil des CSS-Standards. Überhaupt gehören sie zu keinem Standard: Sie wurden zum ersten Mal von Microsoft in IE 4 verwendet und dann von anderen Browsern übernommen. Leider sind die Eigenschaften offsetLeft und offsetTop allein meistens nicht ausreichend. Die Eigenschaften geben die X- und Y-Koordinaten eines Elements bezogen auf ein anderes Element an. Das andere Element ist der Wert der offsetParent-Eigenschaft. Bei positionierten Elementen ist offsetParent normalerweise entweder das -Tag, das -Tag (dessen offsetParent den Wert null hat) oder ein positionierter Vorfahre des positionierten Elements. Bei nicht positionierten Elementen handhaben verschiedene Browser offsetParent unterschiedlich. Unter IE werden beispielsweise Tabellenzeilen in Bezug auf die Tabelle positioniert, die die Zeilen enthält. Grundsätzlich besteht daher die portable Vorgehensweise zur Bestimmung der Position eines Elements im Verfolgen der offsetParent-Referenzen und in der Akkumulation der Offsets. Sie können zum Beispiel folgenden Code verwenden: // Hole die X-Koordinate des Elements e. function getX(e) { var x = 0; // Beginne mit 0
16.2 CSS für DHTML |
399
491-0.book Seite 400 Mittwoch, 4. April 2007 9:55 09
e-bol.net while(e) { x += e.offsetLeft; e = e.offsetParent; } return x;
// Beginne beim Element e // Summiere den Offset hinzu // und gehe zum offsetParent weiter // Gesamtwert für offsetLeft ausgeben
}
Eine getY( )-Funktion lässt sich schreiben, indem man einfach offsetLeft durch offsetTop ersetzt. Beachten Sie, dass die Werte, die im vorherigen Code von Funktionen wie z.B. getX( ) zurückgegeben werden, Dokumentkoordinaten darstellen. Sie sind mit den CSS-Koordinaten kompatibel und werden nicht von der Position der Browser-Bildlaufleiste beeinflusst. In Kapitel 17 erfahren Sie, dass die mit Maus-Events assoziierten Koordinaten Fensterkoordinaten sind und zur Bildlaufleistenposition hinzuaddiert werden müssen, um sie zu Dokumentkoordinaten zu konvertieren. Die oben gezeigte getX( )-Funktion hat ein Manko. Weiter unten erfahren Sie, dass die CSS-Eigenschaft overflow verwendet werden kann, um gescrollte Regionen in einem Dokument zu erzeugen. Wenn ein Element in einer solchen gescrollten Region erscheint, reflektieren seine Offset-Werte die Bildlaufleistenposition dieser Region nicht. Wenn Sie overflow in Ihrer Webseite verwenden, müssen Sie eventuell eine intelligentere Funktion zur Offsetberechnung verwenden, wie z.B. die folgende: function getY(element) { var y = 0; for(var e = element; e; e = e.offsetParent) // Iteriere durch die offsetParents y += e.offsetTop; // Summiere die offsetTop-Werte // Durchlaufe jetzt die Vorfahren des Elements, und suche nach allen, // bei denen scrollTop gesetzt ist. Subtrahiere diese Scrollwerte vom // Gesamtoffset. Wir müssen aber sicherstellen, dass der Durchlauf vor // document.body endet, sonst berücksichtigen wir auch das Dokumentscrollen // und konvertieren im Ende unseren Offset zu Fensterkoordinaten. for(e = element.parentNode; e && e != document.body; e = e.parentNode) if (e.scrollTop) y -= e.scrollTop; // subtrahiere Bildlaufleistenwerte // Das ist die Y-Koordinate unter Beachtung des dokumentinternen Scrolling. return y; }
16.2.4 Die dritte Dimension: z-index Sie haben gesehen, dass die Eigenschaften left, top, right und bottom verwendet werden können, um die X- und Y-Koordinaten eines Elements innerhalb eines umgebenden Elements in der Ebene festzulegen. Die Eigenschaft z-index definiert eine Art dritter Dimension: Sie gibt an, in welcher Reihenfolge überlappende Elemente übereinander angeordnet, also übereinandergezeichnet werden. Die Eigenschaft z-index ist eine ganze Zahl, deren voreingestellter Wert null ist. Die Standardeinstellung ist null, aber Sie kön-
400 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 401 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Beachten Sie, dass sich die Eigenschaft z-index nur auf benachbarte Elemente bezieht, also auf Elemente, die Kinder des gleichen Containers sind. Wenn sich zwei Elemente überlappen, die keine Nachbarn sind, kann durch die Angabe einzelner Werte für die Eigenschaft z-index nicht festgelegt werden, welches oben erscheint. Stattdessen müssen Sie z-index für die benachbarten Container festlegen, die die beiden überlappenden Elemente enthalten. Nicht-positionierte Elemente (d.h. Elemente mit der Standardpositionierung position: static) haben immer eine Anordnung, die Überlappungen vermeidet. Dadurch findet die Eigenschaft z-index bei diesen Elementen keine Anwendung. Dennoch besitzen sie einen voreingestellten z-index vom Wert null, sodass positionierte Elemente mit einem positiven z-index über dem normalen Dokumentenfluss liegen, positionierte Elemente mit einem negativen z-index dagegen unterhalb. Einige Browser werten die Eigenschaft z-index nicht aus, wenn sie auf -Tags angewandt wird, sodass solche Inline-Frames oberhalb von anderen Elementen schweben können, obwohl Sie eine andere Reihenfolge festgelegt haben. Das gleiche Problem kann Ihnen bei anderen fensterartigen Elementen begegnen, wie beispielsweise bei -Menüs. Alte Browser zeigen mitunter alle Formularelemente unabhängig von den Einstellungen des z-index oberhalb von absolut positionierten Elementen an.
16.2.5 Anzeige und Sichtbarkeit von Elementen Zwei CSS-Eigenschaften beeinflussen die Sichtbarkeit eines Dokumentelements: visibility und display. Die Eigenschaft visibility ist sehr einfach: Wenn sie auf den Wert hidden gesetzt wird, wird das Element nicht angezeigt; wird sie auf den Wert visible gesetzt, wird das Element angezeigt. Die Eigenschaft display ist allgemeiner und wird verwendet, um den Typ der Anzeige anzugeben, den ein Element erhält. Sie gibt an, ob ein Element ein Blockelement, ein Inline-Element, ein Listenelement oder was auch immer ist. Wenn display auf den Wert none gesetzt wird, wird das betreffende Element gar nicht angezeigt oder im Layout berücksichtigt. Der Unterschied zwischen den Eigenschaften visibility und display hängt damit zusammen, wie sie sich auf Elemente auswirken, die nicht dynamisch positioniert werden. Bei einem Element, das im normalen Layout erscheint (dessen Eigenschaft position den Wert static oder relative besitzt), wird das Element unsichtbar, wenn Sie visibility auf den Wert hidden setzen, jedoch wird im Layout Platz für das Element reserviert. Ein solches Ele-
16.2 CSS für DHTML |
401
clientseitiges JavaScript
nen positive oder negative Werte angeben. Wenn zwei Elemente übereinanderliegen – eventuell auch nur teilweise –, werden sie in der Reihenfolge vom niedrigsten zum höchsten z-index gezeichnet, sodass das Element mit dem höchsten z-index oben auf allen anderen liegt. Wenn überlappende Elemente den gleichen z-index besitzen, werden sie in der Reihenfolge gezeichnet, in der sie im Dokument erscheinen, sodass das letzte Element oben liegt.
491-0.book Seite 402 Mittwoch, 4. April 2007 9:55 09
e-bol.net ment kann wiederholt verborgen und angezeigt werden, ohne dass sich das Layout des Dokuments ändert. Wird dagegen für ein solches Element die Eigenschaft display auf den Wert none gesetzt, wird kein Platz für das Element im Layout des Dokuments reserviert – beiderseits werden andere Elemente so nah aneinandergelegt, als wäre das nicht angezeigte Element gar nicht vorhanden. (visibility und display verhalten sich bei absolut oder fest positionierten Elementen identisch, da diese ohnehin niemals in das Layout des Dokuments integriert sind.) Üblicherweise werden Sie visibility verwenden, wenn Sie mit dynamisch positionierten Elementen arbeiten. display ist hilfreich, wenn Sie beispielsweise Listen erzeugen möchten, die man expandieren und wieder schließen kann. Beachten Sie, dass es nicht sehr sinnvoll ist, visibility oder display zum Verbergen eines Elements zu benutzen, wenn Sie diese Eigenschaften nicht mit Hilfe von JavaScript dynamisch setzen und damit das Element irgendwann sichtbar machen! Ich zeige Ihnen weiter unten im Kapitel, wie das funktioniert.
16.2.6 Das CSS-Boxmodell und Positionierungsdetails Mit CSS lassen sich Rahmen, Innen- und Außenabstände für jedes Element festlegen. Das erschwert die CSS-Positionierung, da Sie wissen müssen, wie die Eigenschaften width, height, top und left berechnet werden, wenn Rahmen und Abstände vorhanden sind. Das Boxmodell in CSS gibt eine präzise Antwort darauf. Sie wird in den folgenden Abschnitten ausführlich beschrieben und ist in Abbildung 16-3 bildlich dargestellt.
Abbildung 16-3: Das CSS-Boxmodell: Rahmen, Innenabstände und Positionierungsattribute
402 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 403 Mittwoch, 4. April 2007 9:55 09
e-bol.net Fangen wir mit der Besprechung der Eigenschaften border, margin und padding an. Der Rahmen eines Elements ist ein Rechteck, das (teilweise) um das Element gezeichnet wird. Mit CSS-Eigenschaften können Sie die Art, Farbe und Breite des Rahmens festlegen: border: solid black 1px; /* Der Rahmen ist massiv, schwarz und 1 Pixel breit */ border: 3px dotted red; /* Der Rahmen ist rot und 3 Pixel breit */
Die Eigenschaften margin und padding geben beide Leerraum um ein Element herum an. Der (wichtige) Unterschied ist, dass margin den Raum außerhalb des Rahmens angibt, also zwischen dem Rahmen und angrenzenden Elementen. padding gibt den Raum innerhalb des Rahmens an, also zwischen dem Rahmen und dem Elementinhalt. In der normalen Dokumentabfolge erzeugt der Außenabstand (margin) optisch einen Raum zwischen einem (eventuell umrahmten) Element und dessen Nachbarn. Der Innenabstand (padding) trennt den Elementinhalt optisch vom Elementrahmen. Hat ein Element keinen Rahmen, so ist normalerweise kein Innenabstand erforderlich. Ist ein Element dynamisch positioniert und nicht Teil der normalen Dokumentabfolge, so sind seine Außenabstände bedeutungslos. (Aus diesem Grund enthält Abbildung 16-3 keine CSSMargin-Attribute). Der Außen- und Innenabstand eines Elements lassen sich mit den Eigenschaften margin und padding festlegen: margin: 5px; padding: 5px;
Außen- und Innenabstände lassen sich auch für einzelne Seiten eines Elements festlegen: margin-left: 25px; padding-bottom: 5px;
Sie können auch Werte für die Außen- und Innenabstände aller vier Kanten eines Elements mit margin- und padding festlegen. Die top-Werte werden zuerst angegeben und dann geht es im Uhrzeigersinn weiter: top, right, bottom und left. Der folgende Beispielcode zeigt zwei äquivalente Vorgehensweisen beim Setzen unterschiedlicher Innenabstände für jede der vier Seiten: padding: 1px 2px 3px 4px; /* Die vorhergehende Zeile ist äquivalent zu den folgenden Zeilen. */ padding-top: 1px; padding-right: 2px; padding-bottom: 3px; padding-left: 4px;
Die Eigenschaft margin funktioniert auf dieselbe Weise.
16.2 CSS für DHTML |
403
clientseitiges JavaScript
Es ist möglich, die Breite, den Stil und die Farbe des Rahmens über einzelne CSS-Eigenschaften festzulegen, und es kann auch nur der Rahmen für einzelne Seiten eines Elements angegeben werden. Um beispielsweise eine Linie unter einem Element zu zeichnen, legen Sie einfach dessen border-bottom-Eigenschaft fest. Es kann sogar die Breite, der Stil und die Farbe einer einzelnen Seite eines Elements angegeben werden. Abbildung 16-3 zeigt das: Sie enthält Rahmeneigenschaften wie border-top-width und border-left-width.
491-0.book Seite 404 Mittwoch, 4. April 2007 9:55 09
e-bol.net Jetzt verstehen wir die Außen- und Innenabstände und Rahmen und können uns damit ein paar wichtige Einzelheiten der CSS-Positionierungsattribute ansehen. Zunächst legen width und height nur die Größe des Bereichs fest, in dem der Inhalt des Elements erscheinen soll, nicht aber den zusätzlichen Platz für Rahmen, Innen- und Außenabstände. Um die Gesamtgröße eines Elements mit einem Rahmen zu bestimmen, müssen Sie den linken und rechten Innenabstand sowie die Breite des linken und rechten Rahmens zur Breite des Elements und den oberen und unteren Innenabstand sowie die Breite des oberen und unteren Rahmens zur Höhe des Elements addieren. Da width und height nur die für den Inhalt des Elements verwendete Fläche beschreiben, könnte man denken, dass auch left und top (sowie right und bottom) relativ zur Inhaltsfläche des umgebenden Elements gemessen würden. Das ist aber nicht der Fall. Der CSSStandard legt fest, dass diese Werte relativ zur äußeren Kante des Innenabstands des umgebenden Elements gemessen werden (diese entspricht der inneren Kante des Elementrahmens). Das wird alles in Abbildung 16-3 dargestellt, aber sehen wir uns trotzdem ein Beispiel an, um die Sache verständlicher zu machen. Nehmen wir an, Sie haben ein dynamisch positioniertes Container-Element erzeugt, das rings um seine Inhaltsfläche einen Innenabstand von 10 Pixeln Breite sowie einen Rahmen von 5 Pixeln Breite besitzt. Nehmen wir nun an, Sie wollten in diesem Container ein Kindelement dynamisch positionieren. Wenn Sie das Attribut left des Kindes auf den Wert »0 px« setzen, werden Sie feststellen, dass die linke Kante des Kindes direkt am inneren Rand der Containerrahmens klebt. Das Kind belegt also den Raum im Innenabstand, der vermutlich frei bleiben sollte (denn dies ist der Sinn eines Innenabstands). Wenn Sie das Kindelement in der oberen linken Ecke der Inhaltsfläche des Containers positionieren möchten, müssen Sie daher den Eigenschaften left und top jeweils den Wert »10px« zuweisen.
16.2.6.1 Eigenheiten des Internet Explorers Nachdem Sie nun wissen, dass width und height nur die Größe der Inhaltsfläche angeben und left, top, right und bottom relativ zu den Innenabständen des umgebenden Elements gemessen werden, ist ein weiteres wichtiges Detail zu beachten: In den Versionen 4 bis 5.5 des Internet Explorers für Windows (nicht aber in Internet Explorer 5 auf Macintosh-Computern) sind die Eigenschaften width und height fehlerhaft implementiert: Sie enthalten dort auch den Rahmen und den Innenabstand, nicht aber den Außenabstand des Elements. Wenn Sie beispielsweise die Breite eines Elements auf 100 Pixel setzen und einen Innenabstand von 10 Pixeln sowie einen Rahmen von 5 Pixeln Breite links und rechts festlegen, ist die Inhaltsfläche des Elements bei diesen fehlerhaften Versionen des Internet Explorers nur 70 Pixel breit. In Internet Explorer 6 funktionieren die CSS-Eigenschaften für die Position und Größe richtig, wenn der Browser im Standardmodus arbeitet, aber nicht richtig (wenn auch kompatibel zu älteren Versionen), wenn der Browser im Kompatibilitätsmodus arbeitet.
404 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 405 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Die Unterscheidung zwischen Standardmodus und Kompatibilitätsmodus (manchmal auch als Quirks-Modus bezeichnet) gibt es nicht nur in Internet Explorer. Andere Browser brauchen ebenfalls -Deklarationen, um eine strikte Übereinstimmung mit dem Standard zu erzwingen und nehmen ohne diese Deklaration Rückwärtskompatibilität als Standardverhalten an. Allerdings hat nur IE ein so ungeheuerliches Kompatibilitätsproblem.
16.2.7 Farbe, Transparenz und Durchsichtigkeit Die Erörterung der Rahmen enthielt Beispiele, in denen Rahmenfarben anhand der englischen umgangssprachlichen Namen »red« und »black« angegeben wurden. Die allgemeinere Schreibweise zur Festlegung von Farben in CSS ist die Verwendung von Hexadezimalzahlen. Damit werden die Farbkomponenten Rot, Grün und Blau gesetzt. Für jede Komponente können Sie eine oder zwei Zahlen verwenden, beispielsweise: #000000 #fff #f00 #404080 #ccc
Zusätzlich zur Angabe von Rahmenfarben in dieser Farbnotation lassen sich auch Textfarben festlegen, und zwar mit der CSS-Eigenschaft color. Die Hintergrundfarbe jedes beliebigen Elements kann mit der background-color-Eigenschaft gesetzt werden. In CSS kann die genaue Position, Größe, Hintergrundfarbe und Rahmenfarbe von Elementen festgelegt werden. Das gibt Ihnen eine rudimentäre Grafikfähigkeit zum Zeichnen von Rechtecken und horizontalen und vertikalen Linien (durch Reduzierung der Breite bzw. Höhe). Auf dieses Thema komme ich noch einmal in Kapitel 22 zu sprechen, das die Verwendung der CSS-Positionierung und DOM-Skriptsteuerung zum Zeichnen von Säulendiagrammen erläutert. Zusätzlich zur background-color-Eigenschaft können Sie auch Bilder angeben, die als Hintergrund für ein Element verwendet werden sollen. Die background-image-Eigenschaft legt das zu verwendende Bild fest, und background-attachment, background-position und background-repeat geben weitere Einzelheiten darüber an, wie dieses Bild gezeichnet wer-
16.2 CSS für DHTML |
405
clientseitiges JavaScript
Der Standardmodus – und damit die korrekte Implementierung des CSS-Modells für die Schachtelung von Elementen – wird durch die Anwesenheit eines Tags am Anfang des Dokuments aktiviert, wenn dort bekannt gegeben wird, dass das Dokument dem Standard HTML 4.0 (oder neuer) oder einer Version des XHTML-Standards entspricht. Die folgenden drei Deklarationen des HTML-Dokumenttyps sind Beispiele, die Internet Explorer 6 in den Standardmodus versetzen:
491-0.book Seite 406 Mittwoch, 4. April 2007 9:55 09
e-bol.net den soll. Mit der Kurzschrift-Eigenschaft background können Sie diese Eigenschaften in einem Schritt festlegen. Sie können diese Hintergrundbilder zum Erzeugen interessanter optischer Effekte verwenden, die jedoch den Umfang dieses Buchs überschreiten. Es ist wichtig zu verstehen, dass der Hintergrund des Elements normalerweise transparent ist, wenn Sie für ein Element keine Hintergrundfarbe und kein Bild angeben. Wenn Sie beispielsweise ein -Element über einen bereits vorhandenen Text in der normalen Dokumentabfolge absolut positionieren, ist dieser Text normalerweise hinter dem -Element sichtbar. Wenn das seinen eigenen Text enthält, können sich die Buchstaben überlappen und unleserlichen Wirrwarr ergeben. Allerdings sind nicht alle Elemente in der Standardeinstellung transparent. Zum Beispiel sehen Formularelemente mit einem transparenten Hintergrund nicht richtig aus, weswegen beispielsweise das -Tag eine Standardhintergrundfarbe hat. Mit der Eigenschaft background-color können Sie diese Standardeinstellung ändern und sie sogar ausdrücklich auf »transparent« setzen. Die bisher besprochene Transparenz zeigt die Extreme: Entweder hat ein Element einen völlig transparenten oder einen völlig deckenden Hintergrund. Es ist auch möglich, ein Element (sowohl seinen Hintergrund als auch seinen Inhalt im Vordergrund) als durchsichtig anzugeben. (Abbildung 16-4 enthält hierzu ein Beispiel.) Das machen Sie über die CSS3-Eigenschaft opacity. Der Wert dieser Eigenschaft ist eine Zahl zwischen 0 und 1, wobei 1 für 100% deckend (Standardeinstellung) und 0 für 0% deckend (bzw. 100% transparent) steht. Opacity wird vom Firefox-Browser unterstützt. Frühe Versionen von Mozilla unterstützten eine experimentelle Eigenschaft namens -moz-opacity. IE stellt mit seinem IE-spezifischer filter-Eigenschaft eine funktionsgleiche Alternative bereit. Um für ein Element eine Deckung von 75 Prozent zu erreichen, können Sie die folgenden CSS-Styles verwenden: opacity: .75; -moz-opacity: .75; filter: alpha(opacity=75);
/* standardmäßiger CSS3-Style für Transparenz */ /* Transparenz für ältere Mozillas */ /* Transparenz für IE; beachten Sie den fehlenden Dezimalpunkt */
16.2.8 Partielle Sichtbarkeit: overflow und clip Mit der Eigenschaft visibility können Sie ein Element als Ganzes verbergen. Die Eigenschaften overflow und clip ermöglichen es, nur einen Teil eines Elements anzuzeigen. overflow gibt an, was passieren soll, wenn der Inhalt eines Elements über den dafür vorgesehenen Platz (der beispielsweise durch width und height festgelegt wurde) hinausragt. Es kann die folgenden Werte annehmen: visible
Der Inhalt kann über den Platz hinausragen und wird dort gegebenenfalls angezeigt. Dies ist die Voreinstellung.
406 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 407 Mittwoch, 4. April 2007 9:55 09
e-bol.net hidden
Der über den Platz hinausragende Inhalt wird abgeschnitten und verborgen, sodass außerhalb des Platzes, der durch die Größe und die Position festgelegt wurde, keinerlei Inhalt sichtbar ist. scroll
auto
Scrollleisten werden nicht dauerhaft, sondern nur dann angezeigt, wenn der Inhalt mehr Platz benötigt, als für das Element festgelegt wurde. Während Sie mit der Eigenschaft overflow festlegen können, was passiert, wenn der Inhalt des Elements größer ist als der umgebende Kasten, können Sie mit clip genau festlegen, welcher Teil eines Elements angezeigt werden soll – unabhängig davon, ob das Element in den dafür vorgesehenen Platz passt oder nicht. Diese Eigenschaft ist besonders nützlich für skriptmäßig gesteuerte DHTML-Effekte, bei denen ein Element allmählich angezeigt oder aufgedeckt wird. Der Wert der Eigenschaft clip gibt die sogenannte Clipping-Region des Elements an. Im CSS2-Standard sind dies Rechtecke, die Syntax von clip lässt jedoch für zukünftige Versionen des Standards auch andere Formen zu. Die Syntax von clip sieht folgendermaßen aus: rect(oben rechts unten links)
Die Werte oben, rechts, unten und links geben die Begrenzungen des Clipping-Rechtecks relativ zur oberen linken Ecke des Kastens um das Element an. Um beispielsweise nur einen 100 × 100 Pixel großen Teil eines Elements anzuzeigen, können Sie dem Element diese style-Eigenschaft zuweisen: style="clip: rect(0px 100px 100px 0px);"
Beachten Sie, dass die vier in den Klammern angegebenen Werte Längeneinheiten sind und daher eine Maßeinheit wie px für Pixel tragen müssen. Prozentzahlen sind hier nicht erlaubt. Es können auch negative Werte angegeben werden, die angeben, dass die Clipping-Region über den für das Element festgelegten Kasten hinausragt. Sie können für jeden der vier Werte auch das Schlüsselwort auto angeben, um festzulegen, dass diese Kante der Clipping-Region mit der entsprechenden Kante des Kastens um das Element übereinstimmt. Beispielsweise können Sie von einem Element nur die linken 100 Pixel anzeigen lassen, indem Sie den folgenden Code verwenden: style="clip: rect(auto 100px auto auto);"
16.2 CSS für DHTML |
407
clientseitiges JavaScript
Der Kasten, der das Element umgibt, wird mit dauerhaften senk- und waagerechten Scrollleisten versehen. Wenn der Inhalt über den Kasten hinausragt, ermöglichen die Leisten dem Benutzer, den zusätzlichen Inhalt so zu scrollen, dass er sichtbar wird. Dieser Wert wird nur berücksichtigt, wenn das Dokument auf einem Bildschirm angezeigt wird. Wenn das Dokument ausgedruckt wird, ergeben die Scrollleisten offensichtlich nur wenig Sinn.
491-0.book Seite 408 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beachten Sie, dass zwischen den Werten keine Kommata stehen und dass die Kanten der Clipping-Region im Uhrzeigersinn von der oberen Kante ausgehend angegeben werden.
16.2.9 Beispiel: Überlappende durchsichtige Fenster Dieser Abschnitt schließt mit einem Beispiel, das viele der hier besprochenen CSS-Eigenschaften veranschaulicht. Beispiel 16-3 verwendet CSS, um einen visuellen Effekt mit scrollenden, überlappenden und durchsichtigen Fenstern im Browserfenster zu erzeugen. Abbildung 16-4 zeigt, wie das aussieht. Das Beispiel enthält weder JavaScript-Code noch Event-Handler, sodass man mit den Fenstern nicht interagieren kann (außer sie zu scrollen), es ist aber eine nützliche Demonstration der Leistungsfähigkeit von CSS-Effekten. Beispiel 16-3: Anzeige von Fenstern mit CSS /** * Dieses Stylesheet definiert drei Stilregeln, die wir im Body des * Dokuments verwenden, um visuelle "Fenster" zu erzeugen. * Die Regeln verwenden Positionierungseigenschaften, um die Gesamtgröße des Fensters * und die Position der Komponenten festzulegen. Eine Änderung der Fenstergröße erfordert * eine sorgfälitge Anpassung der Positionierungseigenschaften in allen drei Regeln. **/ div.window { /* Legt Größe und Rahmen des Fensters fest */ position: absolute; /* Die Position wird anderswo festgelegt */ width: 300px; height: 200px; /* Fenstergröße ohne Rahmen */ border: outset gray 3px; /* 3D-Rahmeneffekt "outset" */ } div.titlebar { /* Legt Position, Größe position: absolute; /* top: 0px; height: 18px; /* width: 290px; /* background-color: ActiveCaption; /* border-bottom: groove gray 2px; /* padding: 3px 5px 2px 5px; /* font: bold 11pt sans-serif; /* }
und Stil der Titelleiste fest */ Das Element wird positioniert */ Höhe: 18px + Innenabstand und Rahmen */ 290 + 5px Innenabstand links und rechts = 300 */ Systemfarbe für die Titelleiste */ Die Titelleiste hat nur unten einen Rahmen */ Werte im Uhrzeigersinn: oben, rechts, unten, links */ Titelschriftart */
div.content { /* Legt Position, Größe und Scrollleisten für den Inhalt fest */ position: absolute; /* Das Element wird positioniert */ top: 25px; /* 18px Titel + 2px Rahmen + 3px + 2px Innenabstand */ height: 165px; /* 200px gesamt - 25px Titelleiste - 10px Innenabstand */ width: 290px; /* 300px Breite - 10px Innenabstand */ padding: 5px; /* Etwas Platz auf allen Seiten */ overflow: auto; /* Scrollleisten, wenn wir sie brauchen */ background-color: #ffffff; /* Als Standard: weißer Hintergrund */ }
408 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 409 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 16-3: Anzeige von Fenstern mit CSS (Fortsetzung) /* /* /* /*
Diese Klasse macht ein Fenster teilweise transparent */ standardmäßiger CSS3-Style für Transparenz */ Transparenz für ältere Mozillas */ Transparenz für IE */
Test-Fenster 1234567890 1234567890 class="window" style="left: 75px; top: 110px; z-index: 20;"> class="titlebar">Noch ein Fenster class="content translucent" style="background-color:#d0d0d0; font-weight:bold;"> Dies ist ein weiteres Fenster. Sein z-index sorgt dafür, dass es über dem anderen angezeigt wird. CSS-Styles machen seinen Inhaltsbereich in Browsern durchsichtig, die das unterstützen.
Die größte Beschränkung dieses Beispiels besteht darin, dass das Stylesheet eine feste Größe für alle Fenster vorschreibt. Da die Titelleiste und der Inhaltsteil des Fensters exakt in dem umgebenden Fenster positioniert werden müssen, erfordert eine Änderung der Größe des Fensters die Anpassung verschiedener Positionierungseigenschaften in allen drei von dem Stylesheet definierten Regeln. In einem statischen HTML-Dokument kann man dies nicht leicht erreichen; wenn wir aber mit einem Skript auf alle benötigten Eigenschaften zugreifen könnten, wäre es nicht so schwierig. Diesem Thema werden wir uns im nächsten Abschnitt zuwenden.
16.3 Eingebettete Styles per Skript steuern DHTML ist deswegen schwierig, weil Sie die Eigenschaften, die auf einzelne Elemente eines Dokuments angewandt werden, mit JavaScript dynamisch ändern können. Der DOM Level 2-Standard definiert eine API, die dies recht einfach macht. In Kapitel 15 haben Sie gesehen, wie man mit der DOM API Referenzen auf Elemente eines Doku-
16.3 Eingebettete Styles per Skript steuern |
409
491-0.book Seite 410 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Abbildung 16-4: Mit CSS erzeugte Fenster
ments erhält, indem man entweder den Namen des Tags oder die ID verwendet oder indem das Dokument rekursiv durchlaufen wird. Wenn Sie eine Referenz auf das Element, dessen Stil Sie verändern möchten, beschafft haben, verwenden Sie dessen Eigenschaft style, um ein CSS2Properties-Objekt für dieses Element zu erhalten. Dieses JavaScript-Objekt besitzt JavaScript-Eigenschaften, die sämtlichen Eigenschaften von CSS1 und CSS2 entsprechen. Wenn Sie diesen Eigenschaften einen Wert zuweisen, hat dies die gleiche Auswirkung wie die Zuweisung eines entsprechenden Stils in einer styleEigenschaft des Elements. Durch das Auslesen dieser Eigenschaften erhalten Sie den Wert der CSS-Eigenschaft, falls in der style-Eigenschaft des Elements ein solcher angegeben wurde. Das CSS2Properties-Objekt wird in Teil IV dokumentiert. Dabei ist zu beachten, dass das CSS2Properties-Objekt, das Sie mit Hilfe der Eigenschaft style eines Elements erhalten, nur die in einem Dokument eingebetteten Styles eines Elements angibt. Sie können das CSS2Properties-Objekt nicht verwenden, um Informationen über die durch ein Stylesheet angegebenen Styles zu erhalten, die auf das Element angewandt werden. Indem Sie Eigenschaften dieses Objekts setzen, definieren Sie eingebettete Styles, die die von Stylesheets angegebenen überschreiben. Betrachten Sie beispielsweise das folgende Skript. Es sucht alle -Elemente im Dokument und sucht (auf Basis ihrer Größe) diejenigen heraus, die Werbung in Form von Bannern zu enthalten scheinen. Wenn das Skript ein Werbebild entdeckt, verwendet es die Eigenschaft style.visibility, um die CSS-Eigenschaft visibility auf den Wert hidden zu setzen und so die Werbung auszublenden:
410 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 411 Mittwoch, 4. April 2007 9:55 09
e-bol.net var bilder = document.getElementsByTagName("img"); for(var i = 0; i < bilder.length; i++) { var bild=bilder[i]; if (bild.width == 468 && bild.height == 60) bild.style.visibility = "hidden"; }
// Suche alle Bilder // Durchlaufe sie // Wenn es ein 468x60-Banner ist ... // Verbirg es!
16.3.1 Namenskonventionen: CSS-Eigenschaften in JavaScript Viele CSS-Eigenschaften, wie beispielsweise font-family, enthalten in ihrem Namen einen Bindestrich. In JavaScript wird der Bindestrich jedoch als Minuszeichen interpretiert, sodass ein Ausdruck wie der folgende nicht verwendet werden kann: element.style.font-family = "sans-serif";
Aus diesem Grund unterscheiden sich die Namen der Eigenschaften des CSS2PropertiesObjekts leicht von den Namen der eigentlichen CSS-Eigenschaften. Wenn eine CSSEigenschaft einen oder mehrere Bindestriche enthält, wird der Name der entsprechenden Eigenschaft des CSS2Properties-Objekts gebildet, indem die Bindestriche weggelassen und die auf die Bindestriche folgenden Buchstaben großgeschrieben werden. Die Eigenschaft border-left-width wird daher mit der Eigenschaft borderLeftWidth angesprochen; auf font-family können Sie beispielsweise folgendermaßen zugreifen: element.style.fontFamily = "sans-serif";
Es gibt einen weiteren Unterschied zwischen der Benennung von CSS-Eigenschaften und JavaScript-Eigenschaften des Objekts CSS2Properties. Das Wort »float« ist ein Schlüsselwort in Java und anderen Sprachen; es wird zwar derzeit in JavaScript nicht verwendet, ist aber für zukünftige Erweiterungen reserviert. Daher kann das CSS2Properties-Objekt keine Eigenschaft namens float besitzen, die der CSS-Eigenschaft float entspricht. Dieses Problem wird gelöst, indem der CSS-Eigenschaft float der String »css« vorangestellt wird, sodass die Eigenschaft den Namen cssFloat besitzt. Um also den Wert der Eigenschaft float eines Elements abzufragen oder zu setzen, verwenden Sie die Eigenschaft cssFloat des CSS2Properties-Objekts.
16.3.2 Arbeiten mit Stileigenschaften Wenn Sie die Stileigenschaften des CSS2Properties-Objekts benutzen, müssen Sie daran denken, alle Werte als Strings anzugeben. In einem Stylesheet oder einem style-Attribut können Sie Folgendes schreiben: position: absolute; font-family: sans-serif; background-color: #ffffff;
16.3 Eingebettete Styles per Skript steuern |
411
clientseitiges JavaScript
Nebenbei bemerkt: Sie können dieses einfache Skript auch in Form einer javascript:URL als Lesezeichen in Ihrem Browser benutzen (siehe Abschnitt 13.4.1).
491-0.book Seite 412 Mittwoch, 4. April 2007 9:55 09
e-bol.net Um das Gleiche für ein Element e mit Hilfe von JavaScript zu erreichen, müssen Sie alle Werte in Anführungszeichen einschließen: e.style.position = "absolute"; e.style.fontFamily = "sans-serif"; e.style.backgroundColor = "#ffffff";
Beachten Sie, dass die Semikola außerhalb der Strings stehen. Es handelt sich bei ihnen um ganz gewöhnliche Semikola in JavaScript; die in CSS verwendeten Semikola werden in den Stringwerten, die Sie in JavaScript angeben, nicht benötigt. Denken Sie außerdem daran, dass alle Positionierungseigenschaften mit einer Längeneinheit versehen werden müssen. Den Wert der Eigenschaft left können Sie daher nicht wie folgt setzen: e.style.left = 300; // falsch: dies ist eine Zahl, kein String e.style.left = "300"; // falsch: die Längeneinheit fehlt
Einheiten werden benötigt, wenn Stileigenschaften in JavaScript ein Wert zugewiesen werden soll – genau wie bei der Angabe von Stileigenschaften in Stylesheets. Um der Eigenschaft left eines Elements e den Wert 300 Pixel zuzuweisen, müssen Sie die folgende Anweisung verwenden: e.style.left = "300px";
Wenn Sie der Eigenschaft left einen berechneten Wert zuweisen möchten, müssen Sie am Ende der Berechnung die Maßeinheit anhängen: e.style.left = (x0 + left_margin + left_border + left_padding) + "px";
Durch das Anhängen von Einheiten, das ja in Form eines Strings erfolgt, wird der berechnete Wert von einer Zahl in einen String umgewandelt. Sie können das CSS2Properties-Objekt auch verwenden, um die Werte der CSS-Eigenschaften abzufragen, die ausdrücklich im style-Attribut eines Elements gesetzt wurden, oder um einen Wert eines eingebetteten Styles zu lesen, der zuvor von einer JavaScript-Anweisung gesetzt wurde. Sie müssen jedoch wiederum daran denken, dass die von diesen Eigenschaften zurückgegebenen Werte Strings und keine Zahlen sind. Die folgenden Anweisungen (die davon ausgehen, dass die Rahmen des Elements e durch eingebettete Styles angegeben wurden) könnten daher nicht den von Ihnen beabsichtigten Effekt haben: var gesamtRandbreite = e.style.marginLeft + e.style.marginRight;
Stattdessen sollten Sie eine Anweisung wie die folgende verwenden: var totalMarginWidth = parseInt(e.style.marginLeft) + parseInt(e.style.marginRight);
Dieser Ausdruck entfernt einfach die angegebenen Einheiten am Ende der beiden zurückgegebenen Strings. Er nimmt an, dass sowohl marginLeft als auch marginRight mit denselben Einheiten angegeben wurden. Wenn Sie ausschließlich die Einheit Pixel in Ihren eingebetteten Styles verwenden, können Sie üblicherweise in dieser einfachen Weise die Einheiten abschneiden.
412 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 413 Mittwoch, 4. April 2007 9:55 09
e-bol.net Wie bereits gesagt, sind einige CSS-Eigenschaften wie margin Abkürzungen für andere Eigenschaften wie margin-top, margin-right, margin-bottom und margin-left. Das CSS2Properties-Objekt besitzt Eigenschaften, die diesen Abkürzungen entsprechen. Beispielsweise können Sie die Eigenschaft margin folgendermaßen setzen: clientseitiges JavaScript
Es ist jedoch einfacher, die vier Abstandseigenschaften separat zu setzen: e.style.marginTop = topMargin + "px"; e.style.marginRight = rightMargin + "px"; e.style.marginBottom = bottomMargin + "px"; e.style.marginLeft = leftMargin + "px";
Sie können auch die Werte von zusammengefassten Eigenschaften abfragen; meist lohnt sich das jedoch nicht, da Sie den zurückgegebenen Wert analysieren und in die einzelnen Bestandteile zerlegen müssen. Dies ist oft recht kompliziert, sodass es einfacher ist, die Eigenschaften einzeln abzufragen. Lassen Sie mich zum Abschluss noch einmal betonen, dass die Eigenschaften eines CSS2Properties-Objekts, das Sie aus der Eigenschaft style eines HTMLElement-Objekts gewonnen haben, die Werte der eingebetteten Stilattribute des Elements darstellen. Eine dieser Eigenschaften zu setzen ist daher das Gleiche, wie eine CSS-Eigenschaft im styleAttribut des Elements zu setzen: Nur das eine Element wird davon beeinflusst, und der so festgelegte Wert hat Vorrang vor allen anderen Quellen der CSS-Kaskade. Wenn Sie Java-Script verwenden, um DHTML-Effekte zu erzeugen, ist die genaue Steuerung einzelner Elemente genau das, was Sie wünschen. Wenn Sie andererseits die Werte dieser CSS2Properties-Eigenschaften lesen, erhalten Sie nur dann sinnvolle Werte, wenn Ihr JavaScript-Code oder das HTML-Element, das Sie verwenden, eine eingebettete style-Eigenschaft besitzt, das den gewünschten Eigenschaften einen Wert zuweist. Beispielsweise kann Ihr Dokument ein Stylesheet enthalten, das den linken Außenabstand für alle Absätze auf 30 Pixel setzt. Wenn Sie die Eigenschaft marginLeft eines Ihrer Absatzelemente abfragen, erhalten Sie jedoch einen leeren String, sofern der Absatz nicht eine eigene style-Eigenschaft besitzt, die die Einstellung des Stylesheets überschreibt. Obwohl das CSS2Properties-Objekt also zum Setzen von Styles nützlich ist, die alle anderen Styles überschreiben, bietet es uns keine Möglichkeit, die CSS-Kaskade abzufragen und eine vollständige Übersicht über alle Styles für ein gegebenes Element zu erhalten. Abschnitt 16.4 geht kurz auf die getComputedStyle( )-Methode und die entsprechende IE-Eigenschaft currentStyle ein, die diese Fähigkeit zur Verfügung stellen.
16.3.3 Beispiel: CSS-Tooltips Beispiel 16-4 ist ein Modul mit JavaScript-Code zur Anzeige einfacher DHTML-Tooltips, wie des in Abbildung 16-5 abgebildeten.
16.3 Eingebettete Styles per Skript steuern |
413
491-0.book Seite 414 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Abbildung 16-5: Ein CSS-Tooltip
Die Tooltips werden durch zwei ineinander verschachtelte -Elemente angezeigt. Das äußere ist absolut positioniert und hat einen Hintergrund, der als TooltipSchatten dient. Das innere ist relativ positioniert in Bezug auf den Schatten und zeigt den Inhalt des Tooltips an. Der Tooltip bekommt Styles aus drei unterschiedlichen Quellen. Als erste Quelle gibt ein statisches Stylesheet den Schatten, die Hintergrundfarbe, den Rahmen und die Schriftart des Tooltips an. Als zweite Quelle werden eingebettete Styles (wie z.B. position:absolute) angegeben, wenn die Tooltip--Elemente im Tooltip( )-Konstruktor erzeugt werden. Die dritte Quelle sind die top-, left- und visibility-Styles, die gesetzt werden, wenn der Tooltip mit der Tooltip.show( )-Methode angezeigt wird. Beachten Sie, dass Beispiel 16-4 ein einfaches Tooltip-Modul ist, das einfach Tooltips anzeigt und wieder versteckt. Dieses Beispiel wird in Beispiel 17-3 zu einem etwas praktischeren erweitert, das Unterstützung für die Anzeige von Tooltips in Reaktion auf Mouseover-Events hinzufügt. Beispiel 16-4: Tooltips /** * Tooltip.js: Einfache CSS-Tooltips mit Schattenwurf. * * Dieses Modul definiert eine Tooltip-Klasse. Erzeuge ein Tooltip-Objekt mit dem * Tooltip( )-Konstruktor. Dann mache ihn mit der show( )-Methode sichtbar. * Wenn wir fertig sind, verstecke es mit hide( ). * * Beachten Sie, dass dieses Modul mit entsprechenden CSS-Klassendefinitionen * verwendet werden muss, damit es richtig angezeigt wird. Das hier sind Beispiele:
414 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 415 Mittwoch, 4. April 2007 9:55 09
// div für Inhalt // relativ positioniert // um Styles zu setzen
this.tooltip.appendChild(this.inhalt);
// Inhalt zu Schatten hinzufügen
clientseitiges JavaScript
* .tooltipSchatten { * background: url(shadow.png); /* durchsichtiger Schatten * / * } * * .tooltipContent { * left: -4px; top: -4px; /* wie viel des Schattens ist sichtbar? * / * background-color: #ff0; /* gelber Hintergrund * / * border: solid black 1px; /* dünner schwarzer Rahmen * / * padding: 5px; /* Abstand zwischen Text und Rahmen * / * font: bold 10pt sans-serif; /* kleine fette Schriftart * / * } * * In Browsern, die durchsichtige PNG-Grafiken unterstützen, kann man * durchsichtige Schatten werfen. Andere Browser müssen Deckfarbe verwenden oder * Transparenz mit einem gesprenkelten GIF simulieren, das zwischen deckenden * und transparenten Pixeln abwechselt. */ function Tooltip( ) { // Die Konstruktorfunktion für die Tooltip-Klasse this.tooltip = document.createElement("div"); // div für Schatten this.tooltip.style.position = "absolute"; // absolut positioniert this.tooltip.style.visibility = "hidden"; // anfangs unsichtbar this.tooltip.className = "tooltipSchatten"; // um Styles zu setzen
} // Inhalt und Position des Tooltips setzen und ihn anzeigen Tooltip.prototype.show = function(text, x, y) { this.inhalt.innerHTML = text; // Text des Tooltips setzen. this.tooltip.style.left = x + "px"; // Position setzen. this.tooltip.style.top = y + "px"; this.tooltip.style.visibility = "visible"; // Sichtbar machen // Tooltip ins Dokument einfügen, falls das noch nicht passiert ist if (this.tooltip.parentNode != document.body) document.body.appendChild(this.tooltip); }; // Tooltip verstecken Tooltip.prototype.hide = function( ) { this.tooltip.style.visibility = "hidden"; };
// Unsichtbar machen.
16.3 Eingebettete Styles per Skript steuern |
415
491-0.book Seite 416 Mittwoch, 4. April 2007 9:55 09
e-bol.net
16.3.4 DHTML-Animationen Animationen zählen zu den leistungsfähigsten DHTML-Techniken, die Sie mit JavaScript und CSS nutzen können. Eigentlich sind DHTML-Animationen nichts Besonderes: Sie müssen lediglich in periodischen Abständen eine oder mehrere Stileigenschaften eines oder mehrerer Elemente ändern. Um beispielsweise eine Grafik von links an ihren Platz zu schieben, erhöhen Sie die style.left-Eigenschaft des Bilds wiederholt, bis es die gewünschte Position erreicht hat. Sie können auch die Eigenschaft style.clip wiederholt ändern, um ein Bild Pixel für Pixel aufzudecken. Beispiel 16-5 zeigt eine einfache HTML-Datei, die ein zu animierendes div-Element sowie ein kurzes Skript definiert, das die Rahmenfarbe des Elements alle 500 Millisekunden ändert. Beachten Sie, dass die Farbänderung einfach dadurch erfolgt, dass einer CSSEigenschaft ein Wert zugewiesen wird. Eine Animation wird daraus, indem wir die Farbe mit Hilfe der Funktion setInterval( ) des Window-Objekts wiederholt ändern. (Sie müssen setInterval( ) oder setTimeout( ) für alle DHTML-Animationen benutzen; schlagen Sie in der Referenz in Teil IV nach, wenn Sie sich nicht mehr an die Einzelheiten der Methoden erinnern). Beachten Sie außerdem, wie wir den Modulo-Operator (%) zur Bestimmung des Rests bei einer ganzzahligen Division verwenden, um die Farben zyklisch zu durchlaufen. Falls Sie vergessen haben, wie dieser Operator funktioniert, können Sie dies in Kapitel 5 nachschlagen. Beispiel 16-5: Eine einfache Animation mit Farbänderungen Alarmstufe Rot!Der Webserver wird angegriffen! var e = document.getElementById("dringend"); // Element-Objekt beschaffen e.style.border = "solid black 5px"; // Gib ihm einen Rahmen e.style.padding = "50px"; // und etwas Innenabstand var farben = ["white", "yellow", "orange", "red"] // die zu durchlaufenden Farben var naechsteFarbe = 0; // Position im Farbzyklus // Rufe die folgende Funktion alle 500 ms zur Animierung der Rahmenfarbe auf setInterval(function( ) { e.style.borderColor=farben[naechsteFarbe++%farben.length]; }, 500);
Beispiel 16-5 erzeugt eine sehr einfache Animation. In der Praxis werden bei den meisten CSS-Animationen zwei oder mehr Stileigenschaften gleichzeitig verändert (wie beispielsweise top, left und clip). Komplexere Animationen können mit der in Beispiel 16-5 gezeigten Technik schnell recht kompliziert werden. Um außerdem den Benutzer nicht zu belästigen, sollten Animationen normalerweise nur eine kurze Zeit laufen und anschließend anhalten – anders als bei der Animation in Beispiel 16-5.
416 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 417 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 16-6 zeigt eine JavaScript-Datei, die eine Funktion für eine CSS-Animation definiert, mit der auch komplexere Animationen erzeugt werden können. Beispiel 16-6: Ein Framework für CSS-basierte Animationen
// Bereite den Aufruf von zeigeNaechstesBild( ) alle zeitProBild Millisekunden vor. // Dadurch werden alle Einzelbilder der Animation angezeigt. var intervallId = setInterval(zeigeNaechstesBild, zeitProBild); // Der Aufruf von animiereCSS( ) ist nun beendet, aber durch die obige Zeile // ist sichergestellt, dass die im Folgenden definierte innere Funktion // einmal für jedes Einzelbild der Animation aufgerufen wird. function zeigeNaechstesBild( ) { if (einzelbild >= anzBilder) { // Prüfe, ob wir fertig sind clearInterval(intervallId); // Wenn ja, rufen wir uns nicht // mehr selbst auf if (wennFertig) wennFertig(element); // Rufe wennFertig auf, return; // und wir sind fertig }
16.3 Eingebettete Styles per Skript steuern |
417
clientseitiges JavaScript
/** * AnimiereCSS.js: * Diese Datei definiert eine Funktion animiereCSS( ), die als Framework für * die Erzeugung CSS-basierter Animationen dient. Die Argumente für diese Funktion sind: * * element: Das zu animierende HTML-Element. * anzBilder: Die Anzahl der Einzelbilder in der Animation. * zeitProBild: Die Anzahl der Millisekunden zur Anzeige der Einzelbilder. * animation: Ein Objekt, das die Animation definiert; s.u. * wennFertig: Eine optionale Funktion, die nach Ende der Animation aufgerufen wird. * Wenn angegeben, wird dieser Funktion element als Argument übergeben. * * Die Funktion animiereCSS( ) definiert einfach ein Framework für Animationen. * Die Eigenschaften des Animationsobjekts legen die durchzuführende Animation fest. * Jede Eigenschaft sollte den gleichen Namen wie eine CSS-Stileigenschaft * besitzen. * Der Wert jeder Eigenschaft muss eine Funktion sein, die gültige Werte für diese * Stileigenschaft zurückgibt. Jeder Funktion wird die Nummer des Einzelbilds * und die bereits verstrichene Zeit übergeben, die verwendet werden können, * um den zurückzugebenden Stilwert zu berechnen. Um beispielsweise ein Bild so zu animieren, * dass es von links oben hereingleitet, können Sie animiereCSS wie folgt aufrufen: * * animiereCSS(bild, 25, 50, // Animiere das Bild in 25 Einzelbildern mit je 50ms Standzeit * { // Setze die Eigenschaften top und left für jedes Einzelbild: * top: function(einzelbild,zeit) { return einzelbild*8 + "px"; }, * left: function(einzelbild,zeit) { return einzelbild*8 + "px"; } * }); * **/ function animiereCSS(element, anzBilder, zeitProBild, animation, wennFertig) { var einzelbild = 0; // Speichere die aktuelle Nummer des Einzelbilds var zeit = 0; // Speichere die verstrichene Zeit
491-0.book Seite 418 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 16-6: Ein Framework für CSS-basierte Animationen (Fortsetzung) // Durchlaufe nun alle im Animationsobjekt definierten Eigenschaften for(var cssEigenschaft in animation) { // Rufe die Animationsfunktion jeder Eigenschaft auf, und übergib // die Einzelbildnummer und die verstrichene Zeit. Verwende den // Rückgabewert der Funktion als neuen Wert der entsprechenden Stileigenschaft // des übergebenen Elements. Verwende try/catch, um Exceptions // abzufangen, die durch ungültige Rückgabewerte erzeugt werden. try { element.style[cssEigenschaft] = animation[cssEigenschaft] (einzelbild, zeit); } catch(e) {} } einzelbild++; zeit += zeitProBild;
// Erhöhe die Einzelbildnummer // Erhöhe die verstrichene Zeit
} }
Der in diesem Beispiel definierten Funktion animateCSS( ) werden fünf Argumente übergeben. Das erste gibt das zu animierende HTMLElement-Objekt an. Das zweite und dritte Argument geben die Anzahl der Einzelbilder der Animation sowie die Standzeit jedes Einzelbildes an. Das vierte Argument ist ein JavaScript-Objekt, das die durchzuführende Animation festlegt. Als fünftes Argument kann optional eine Funktion übergeben werden, die einmal ausgeführt werden soll, wenn die Animation beendet ist. Das vierte an animateCSS( ) übergebene Argument ist das entscheidende. Jede Eigenschaft des JavaScript-Objekts muss den gleichen Namen haben wie eine CSS-Eigenschaft; die Werte aller Eigenschaften müssen jeweils eine Funktion sein, die einen gültigen Wert für den angegebenen Stil zurückgibt. Sobald ein neues Einzelbild der Animation angezeigt wird, wird jede Funktion aufgerufen, um einen neuen Wert für jede der Stileigenschaften zu bestimmen. Jeder Funktion wird die Nummer des Einzelbilds sowie die insgesamt verstrichene Zeit übergeben, sodass diese Werte zur Berechnung des neuen Werts herangezogen werden können. Der Code in Beispiel 16-6 ist recht einfach; wie Sie bald sehen werden, ist die eigentliche Komplexität in den Eigenschaften des Animationsobjekts eingebettet, das Sie an animiereCSS( ) übergeben. animiereCSS( ) definiert eine innere Funktion namens zeigeNaechstesBild( ) und macht nicht viel mehr, als die Methode setInterval( ) zu verwenden, um zeigeNaechstesBild( ) wiederholt aufzurufen. zeigeNaechstesBild( ) durchläuft die Eigenschaften des Animationsobjekts und ruft die einzelnen Funktionen auf, um die neuen Werte für die Stileigenschaften zu berechnen. Da zeigeNaechstesBild( ) innerhalb von animiereCSS( ) definiert wird, kann diese Funktion auf die Argumente und lokalen Variablen von animiereCSS( ) zugreifen, auch wenn zeigeNaechstesBild( ) aufgerufen wird, nachdem animiereCSS( ) bereits beendet ist!
418 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 419 Mittwoch, 4. April 2007 9:55 09
e-bol.net (Wenn Sie nicht verstehen, warum dies funktioniert, können Sie noch einmal Abschnitt 8.8 studieren). Durch ein Beispiel wird die Verwendung von animiereCSS( ) viel leichter verständlich. Der folgende Code bewegt ein Element auf dem Bildschirm nach oben, während es allmählich durch das Vergrößern der Clipping-Region aufgedeckt wird.
Das folgende Code-Fragment verwendet animiereCSS( ), um ein Button-Objekt im Kreis zu bewegen. Das optionale fünfte Argument wird verwendet, um den Button-Text in »Fertig« zu ändern, wenn die Animation beendet ist. Beachten Sie, dass das animierte Element als Argument an die Funktion übergeben wird, die das fünfte Argument bildet. // Bewege einen Button im Kreis, und ändere zum Schluss den von ihm angezeigten Text animiereCSS(document.forms[0].elements[0], 40, 50, // Button, 40 Bilder, 50ms { // Diese Berechnung definiert einen Kreis mit einem Radius von 100 an der // Stelle (200,200): left: function(b,t){ return 200 + 100*Math.cos(b/8) + "px"}, top: function(b,t){ return 200 + 100*Math.sin(b/8) + "px"} }, function(button) { button.value = "Fertig"; });
Die JavaScript-Bibliothek Scriptaculous enthält ein hochentwickeltes Animationsframework mit vielen leistungsfähigen vordefinierten Animationseffekten. Besuchen Sie die einschlägig benannte Website http://script.aculo.us/, um mehr darüber zu lernen.
16.4 Berechnete Styles per Skript steuern Die style-Eigenschaft eines HTML-Elements entspricht dem style-Attribut in HTML, und das CSS2Properties-Objekt, das der Wert der style-Eigenschaft ist, enthält nur Informationen über die eingebetteten Stile für dieses eine Element. Es enthält keine Styles aus anderen Teilen der CSS-Kaskade. Manchmal wollen Sie die genauen Stile eines Elements wissen, und zwar unabhängig davon, wo sie in der Kaskade festgelegt wurden. In diesem Fall suchen Sie nach dem berechneten Stil für das Element. Leider ist die Bedeutung des Namens berechneter Stil nicht offensichtlich; er bezieht sich auf die Berechnung, die durchgeführt wird, bevor das Element vom Webbrowser angezeigt wird: Die Regeln aller Stylesheets werden getestet, um herauszufinden, welche auf das Element angewendet werden, und die Stile der betreffenden Regeln werden mit gegebenenfalls vorhandenen eingebetteten Styles für das Element kombiniert. Mit dieser aggregierten Stilinformation kann das Element im Browserfenster korrekt wiedergegeben werden.
16.4 Berechnete Styles per Skript steuern |
419
clientseitiges JavaScript
// Animiere das Element mit dem Bezeichner "title" in 40 Einzelbildern, // die je 50 Millisekunden Standzeit haben animiereCSS(document.getElementById("title"), 40, 50, { // Setze die Stileigenschaften top und clip jedes Einzelbildes wie folgt: top: function(f,t) { return 300-f*5 + "px"; }, clip: function(f,t) {return "rect(auto "+f*10+"px auto auto)";} });
491-0.book Seite 420 Mittwoch, 4. April 2007 9:55 09
e-bol.net Die Standard-W3C API zur Bestimmung des berechneten Stils eines Elements ist die getComputedStyle( )-Methode des Window-Objekts. Das erste Argument dieser Methode ist das Element, dessen berechneter Stil ermittelt werden soll. Das zweite Argument ist ein beliebiges CSS-Pseudoelement, wie z.B. :before oder :after, dessen Stil ermittelt werden soll. Sie haben wahrscheinlich kein Interesse an Pseudoelementen, aber in der Mozilla- und Firefox-Implementierung dieser Methode ist das zweite Argument vorgeschrieben und kann nicht weggelassen werden. Daher wird getComputedStyle( ) normalerweise mit dem Wert null als zweites Argument aufgerufen. Der Rückgabewert von getComputedStyle( ) ist ein CSS2Properties-Objekt, das alle Styles repräsentiert, die auf das angegebene Element oder Pseudoelement Anwendung finden. Im Gegensatz zu dem CSS2Properties-Objekt, das Informationen über die eingebetteten Styles enthält, ist das von getComputedStyle( ) zurückgegebene Objekt schreibgeschützt. IE unterstützt die getComputedStyle( )-Methode nicht, stellt aber eine einfachere Alternative zur Verfügung: Jedes HTML-Element hat eine currentStyle-Eigenschaft, die seinen berechneten Style enthält. Der einzige Mangel der IE API ist, dass sie keine Möglichkeit zur Abfrage der Stile von Pseudoelementen bietet. Als Beispiel für berechnete Styles könnten Sie plattformübergreifenden Code wie den folgenden verwenden, um zu bestimmen, in welcher Schriftart ein Element angezeigt wird: var p = document.getElementsByTagName("p")[0]; // Hole ersten Absatz des Dok. var schriftart = ""; // Wir wollen seine Schriftart if (p.currentStyle) // Erst einfache IE API probieren schriftart = p.currentStyle.fontFamily; else if (window.getComputedStyle) // ansonsten W3C API verwenden schriftart = window.getComputedStyle(p, null).fontFamily;
Berechnete Styles sind eigenwillig, und ihre Abfrage resultiert nicht immer in den Informationen, die Sie haben wollen. Nehmen Sie beispielsweise das eben gezeigte Beispiel mit der Schriftart. Die CSS-Eigenschaft font-family nimmt eine durch Kommata getrennte Liste gewünschter Schriftartenfamilien, um plattformübergreifende Portabilität sicherzustellen. Wenn Sie die fontFamily-Eigenschaft eines berechneten Styles abfragen, bekommen Sie einfach den Wert des spezifischen font-family-Styles, der auf das Element zutrifft. Damit können Sie einen Wert wie »arial,helvetica,sans-serif« zurückbekommen, der Ihnen nicht sagt, welche Schriftart denn nun eigentlich gerade benutzt wird. Ebenso führt der Versuch, die Position und Abmessungen eines nicht absolut positionierten Elements über die top- und left-Eigenschaften seines berechneten Styles ermitteln, oft zu einem Rückgabewert von »auto«. Das ist ein völlig ordnungsgemäßer CSS-Wert, aber vermutlich nicht der, nach dem Sie gesucht haben.
420 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 421 Mittwoch, 4. April 2007 9:55 09
e-bol.net
16.5 CSS-Klassen per Skript steuern
Bei der Verwendung des HTML-Attributs class und der ihm entsprechenden classNameEigenschaft ist es wichtig, daran zu denken, dass es mehr als eine Klasse auflisten kann. Bei der Skriptsteuerung der Eigenschaft className ist es daher im Allgemeinen nicht sinnvoll, diesen Wert einfach so zu setzen und abzufragen, als enthalte er nur einen Klassennamen (obwohl das aus Gründen der Einfachheit in Kapitel 18 der Fall ist). Vielmehr brauchen Sie eine Funktion zum Testen, ob ein Element ein Mitglied einer Klasse ist, und Funktionen, um Klassen zur Elementeigenschaft className hinzuzufügen oder aus ihr zu entfernen. Beispiel 16-7 zeigt, wie diese Funktionen definiert werden. Der Code ist einfach, stützt sich aber stark auf reguläre Ausdrücke. Beispiel 16-7: Utility-Funktion zur Manipulation von className /** * CSSClass.js: Utilities zur Manipulation der CSS-Klasse eines HTML-Elements. * * Dieses Modul definiert ein einziges globales Symbol namens CSSClass. Dieses Objekt * enthält Utility-Funktionen zum Umgang mit dem class-Attribut (className* Eigenschaft) von HTML-Elementen. Alle Funktionen haben zwei Argumente: das Element, * das zu testen/manipulieren ist, und die CSS-Klasse k, die zu testen, * hinzuzufügen oder zu entfernen ist. Ist Element e ein String, dann wird er als Element* id betrachtet und an document.getElementById( ) übergeben. */ var CSSClass = {}; // Erzeuge unser namespace-Objekt // Gib true zurück, wenn e ein Mitglied der Klasse k ist; ansonsten false CSSClass.ist = function(e, k) { if (typeof e == "string") e = document.getElementById(e); // Element-id // Vor der Regexp-Suche optimieren wir den Code für einige häufige Fälle. var klassen = e.className; if (!klassen) return false; // Kein Mitglied einer Klasse if (klassen == k) return true; // Nur Mitglied dieser einen Klasse
16.5 CSS-Klassen per Skript steuern |
421
clientseitiges JavaScript
Eine Alternative zur Skriptsteuerung individueller CSS-Styles über die style-Eigenschaft besteht darin, in HTML den Werts des class-Attributs zu ändern, und zwar per Skript über die className-Eigenschaft eines beliebigen HTML-Elements. Das dynamische Setzen einer Elementklasse kann die Styles, die auf das Element angewendet werden, dramatisch ändern – vorausgesetzt natürlich, dass die von Ihnen verwendete Klasse entsprechend in einem Stylesheet definiert ist. Diese Technik kommt in Beispiel 18-3 zur Anwendung, einem Formularüberprüfungsbeispiel, das noch einmal in diesem Buch vorkommt. Der JavaScript-Code in diesem Beispiel setzt den className von Formularelementen auf »valid« bzw. »invalid«, abhängig davon, ob die Benutzereingaben gültig waren oder nicht. Beispiel 18-2 enthält ein einfaches Stylesheet, das die Klassen »valid« und »invalid« so definiert, dass sie die Hintergrundfarbe des Eingabeelements in einem Formular ändern.
491-0.book Seite 422 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 16-7: Utility-Funktion zur Manipulation von className (Fortsetzung) // Ansonsten suchen wir per regulärem Ausdruck nach c als eigenständigem Wort // \b in regulären Ausdrücken verlangt Übereinstimmung an einer Wortgrenze. return e.className.search("\\b" + k + "\\b") != -1; }; // Füge Klasse k an den className von e an, wenn er sie nicht bereits enthält. CSSClass.anfuegen = function(e, k) { if (typeof e == "string") e = document.getElementById(e); // Element-id if (CSSClass.ist(e, k)) return; // Ist k bereits Mitglied, nichts machen if (e.className) k = " " + k; // Leerzeichen zum Trennen, falls nötig e.className += k; // Füge die neue Klasse ans Ende an }; // Entferne Klasse k (falls vorhanden, ggf. auch mehrfach) aus dem className von e CSSClass.remove = function(e, k) { if (typeof e == "string") e = document.getElementById(e); // Element-id // Durchsuche den className nach k, und ersetze sie jeweils durch "". // \s* passt auf eine beliebige Anzahl von Whitespace-Zeichen. // mit "g" im regulären Ausdruck darf k beliebig oft vorkommen e.className = e.className.replace(new RegExp("\\b"+ k +"\\b\\s*", "g"), ""); };
16.6 Stylesheets per Skript steuern Die vorangegangenen Abschnitte beschreiben zwei Techniken der CSS-Skriptsteuerung: die Änderung des eingebetteten Styles eines Elements und die Änderung der Klasse eines Elements. Wie die folgenden Unterabschnitte zeigen, können auch die Stylesheets selbst über Skripten gesteuert werden.
16.6.1 Stylesheets aktivieren und deaktivieren Die einfachste Technik für die Stylesheet-Steuerung über Skripten ist gleichzeitig die portabelste und die robusteste. Der HTML DOM Level 2-Standard definiert eine disabledEigenschaft für sowohl das - als auch das -Element. Für die HTML-Tags existiert kein entsprechendes disabled-Attribut, aber es gibt eine Eigenschaft, die in JavaScript gesetzt und abgefragt werden kann. Wenn die disabled-Eigenschaft auf true steht, ist das Stylesheet, das sich auf das - oder -Element bezieht, deaktiviert und wird vom Browser ignoriert. Das wird in Beispiel 16-8 veranschaulicht. Es besteht aus einer HTML-Seite, die vier Stylesheets enthält. Sie zeigt vier Checkboxen an, über die der Benutzer jedes der vier Stylesheets einzeln (de-)aktivieren kann.
422 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 423 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 16-8: Stylesheets aktivieren und deaktivieren
// Diese Funktion (de)aktiviert ein über id angegebenes Stylesheet. // Das funktioniert für - und -Elemente. function enableSS(sheetid, aktiviert) { document.getElementById(sheetid).disabled = !aktiviert; } Einfach Riesenschrift Kontrast Sans Serif
16.6.2 Stylesheet-Objekte und Stylesheet-Regeln Das Level 2 DOM ermöglicht nicht nur das Aktivieren und Deaktivieren der - und -Tags, die sich auf die Stylesheets beziehen, es definiert auch eine vollständige API zum Abfragen, Manipulieren und Navigieren in Stylesheets selbst. Als dieses Buch geschrieben wurde, war Firefox der einzige Browser, der einen erheblichen Teil dieser standardisierten API zu Navigation in Stylesheets unterstützte. IE 5 definiert eine andere API, und andere Browser haben nur eingeschränkte (oder keine) Unterstützung für das direkte Arbeiten mit Stylesheets. Im Allgemeinen ist die direkte Manipulation von Stylesheets nicht sinnvoll. Statt beispielsweise einem Stylesheet neue Regeln hinzuzufügen, ist es normalerweise besser, das Stylesheet statisch zu belassen und die className-Eigenschaft Ihres Elements per Skript
16.6 Stylesheets per Skript steuern |
423
clientseitiges JavaScript
body { font-family: sans-serif; }
491-0.book Seite 424 Mittwoch, 4. April 2007 9:55 09
e-bol.net zu setzen. Wenn Sie dem Benutzer aber freie Bahn bei der Auswahl der auf Ihrer Seite benutzten Stile lassen wollen, müssen Sie ein Stylesheet eventuell dynamisch verändern können (vielleicht durch das Speichern der vom Benutzer gewünschten Stile in einem Cookie). Wenn Sie sich dafür entscheiden, Stylesheets direkt per Skript zu steuern, funktioniert der in diesem Abschnitt vorgestellte Code unter Firefox und IE, aber eventuell nicht in anderen Browsern. Die auf ein Dokument angewandten Stylesheets werden im styleSheets[]-Array des Document-Objekts gespeichert. Hat ein Dokument nur ein Stylesheet, können Sie wie folgt auf es verweisen: var ss = document.styleSheets[0]
Die Elemente in diesem Array sind CSSStyleSheet-Objekte. Beachten Sie, dass diese Objekte sich von den - und -Tags unterscheiden, die auf das Stylesheet verweisen oder es enthalten. CSSStyleSheet-Objekte besitzen ein Array cssRules[], das die Regeln des Stylesheets enthält. var ersteRegel = document.styleSheets[0].cssRules[0];
IE unterstützt zwar die cssRules-Eigenschaft nicht, hat aber eine gleichwertige Eigenschaft namens rules. Die Elemente der cssRules[]- und rules[]-Arrays sind CSSRule-Objekte. Im W3C-Standard kann ein CSSRule-Objekt jede beliebige CSS-Regel darstellen, einschließlich der atrules, wie z.B. die Anweisungen @import und @page. In IE stellt das CSSRule-Objekt jedoch nur die derzeitigen Stilregeln des Stylesheets dar. CSSRule-Objekte besitzen zwei Eigenschaften, die plattformübergreifend verwendet werden können. (Im W3C DOM sind diese Eigenschaften einer Regel nicht definiert, wenn diese keine Stilregel ist. Beim Navigieren durch das Stylesheet werden Sie diese Regel wahrscheinlich überspringen wollen). selectorText ist der CSS-Selektor für die Regel, und style bezieht sich auf ein CSS2Properties-Objekt, das die mit diesem Selektor assoziierten Styles beschreibt. Rufen wir uns ins Gedächtnis, dass CSS2Properties das gleiche Interface ist und zur Repräsentation der eingebetteten Styles eines HTML-Elements über die style-Eigenschaft verwendet wird. Sie können dieses CSS2Properties-Objekt zum Abfragen der Stilwerte oder zum Setzen neuer Styles für die Regel verwenden. Wenn Sie durch ein Stylesheet navigieren, haben Sie oft mehr Interesse am Text der Regel als an ihrer geparsten Darstellung. In diesem Fall verwenden Sie die cssText-Eigenschaft des CSS2Properties-Objekts, was Ihnen eine Textdarstellung der Regeln liefert. Der folgende Code durchläuft die Regeln eines Stylesheets und zeigt, was sich mit ihnen machen lässt: // Hole das erste Stylesheet des Dokuments var ss = document.styleSheets[0]; // Hole das rules-Array über W3C oder IE API var regeln = ss.cssRules?ss.cssRules:ss.rules;
424 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 425 Mittwoch, 4. April 2007 9:55 09
e-bol.net // Iteriere durch diese Regeln for(var i = 0; i < regeln.length; i++) { var regel = regeln[i]; // Überspringe @import und andere Regeln, die keine Styles sind if (!regel.selectorText) continue;
// Wenn die Regel einen Rand angibt, gehen wir davon aus, dass er in Pixeln ist, und // verdoppeln ihn var rand = parseInt(regel.style.margin); if (rand) regel.style.margin = (rand*2) + "px"; }
Zusätzlich zum Abfragen und Ändern bereits bestehender Regeln eines Stylesheetskönnen Sie Regeln zu einem Stylesheet hinzufügen und aus ihm entfernen. Das W3C CSSStyleSheet-Interface definiert die Methoden insertRule( ) und deleteRule( ) zum Hinzufügen und Entfernen von Regeln: document.styleSheets[0].insertRule("H1 { text-weight: bold; }", 0);
IE unterstützt insertRule( ) und deleteRule( ) nicht, definiert aber die weitgehend äquivalenten Funktionen addRule( ) und removeRule( ). Der einzige Unterschied (abgesehen von den Namen) ist, dass bei addRule( ) der Selektortext und der Stiltext als zwei getrennte Argumente übergeben werden müssen. Beispiel 16-9 definiert eine StylesheetUtility-Klasse, die sowohl die W3C- als auch die IE API zum Hinzufügen und Entfernen von Regeln enthält. Beispiel 16-9: Stylesheet-Utility-Methoden /** * Stylesheet.js: Utility-Methoden zur Skriptsteuerung von Stylesheets. * * Dieses Modul definiert eine Stylesheet-Klasse, die ein einfacher Wrapper * um ein Element des Arrays document.styleSheets[] ist. Sie definiert nützliche * plattformübergreifende Methoden zur Abfrage und Änderung des Stylesheets. **/ // Erzeuge ein neues Stylesheet-Objekt, das das angegebene CSSStylesheet verpackt. // Wenn ss eine Zahl ist, dann suche das Stylesheet im styleSheet[]-Array. function Stylesheet(ss) { if (typeof ss == "number") ss = document.styleSheets[ss]; this.ss = ss; } // Gib das rules-Array für dieses Stylesheet zurück. Stylesheet.prototype.holeRegeln = function( ) { // Verwende die W3C-Eigenschaft, wenn sie definiert ist; ansonsten die IE-Eigenschaft return this.ss.cssRules?this.ss.cssRules:this.ss.rules; }
16.6 Stylesheets per Skript steuern |
425
clientseitiges JavaScript
// Das ist die Textform der Regel var regelText = regel.selectorText + " { " + regel.style.cssText + " }";
491-0.book Seite 426 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 16-9: Stylesheet-Utility-Methoden (Fortsetzung) // Gib eine Regel des Stylesheets zurück. Wenn s eine Zahl ist, geben wir die Regel // mit diesem Index zurück. Sonst nehmen wir an, dass s ein Selektor ist, und suchen nach // einer Regel, die mit diesem Selektor übereinstimmt. Stylesheet.prototype.holeRegel = function(s) { var regeln = this.holeRegeln( ); if (!regeln) return null; if (typeof s == "number") return regeln[s]; // Gehe davon aus, dass s ein Selektor ist. // Durchlaufe die Regeln rückwärts. Bei mehreren auf s passenden Regeln // finden wir dadurch die mit der höchsten Priorität. s = s.toLowerCase( ); for(var i = regeln.length-1; i >= 0; i--) { if (regeln[i].selectorText.toLowerCase( ) == s) return regeln[i]; } return null; }; // Gib das CSS2Properties-Objekt für die angegebene Regel zurück. // Regeln können über eine Zahl oder einen Selektor angegeben werden. Stylesheet.prototype.holeStyles = function(s) { var regel = this.holeRegel(s); if (regel && regel.style) return regel.style; else return null; }; // Gib den Stiltext der angegebenen Regel zurück. Stylesheet.prototype.holeStyleText = function(s) { var regel = this.holeRegel(s); if (regel && regel.style && regel.style.cssText) return regel.style.cssText; else return ""; }; // Füge eine Regel in ein Stylesheet ein. // Die Regel besteht aus dem angegebenen Selektor und Style-Strings. // Sie wird am Index n eingefügt. Wenn n fehlt, wird sie ans Ende angefügt. Stylesheet.prototype.regelEinfügen = function(selector, styles, n) { if (n == undefined) { var regeln = this.holeRegeln( ); n = regeln.length; } if (this.ss.insertRule) // Versuche es zuerst mit der W3C API this.ss.insertRule(selector + "{" + styles + "}", n); else if (this.ss.addRule) // Verwende ansonsten die IE API this.ss.addRule(selector, styles, n); }; // Entferne die Regel von der angegebenen Position im Stylesheet. // Wenn s eine Zahl ist, lösche die Regel an dieser Position.
426 | Kapitel 16: Cascading Style Sheets und dynamisches HTML
491-0.book Seite 427 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 16-9: Stylesheet-Utility-Methoden (Fortsetzung)
clientseitiges JavaScript
// Wenn s ein String ist, lösche die Regel mit diesem Selektor. // Wenn n nicht angegeben ist, lösche die letzte Regel im Stylesheet. Stylesheet.prototype.loescheRegel = function(s) { // Wenn s nicht definiert ist, nimm den Index der letzten Regel if (s == undefined) { var regeln = this.holeRegeln( ); s = regeln.length-1; } // Wenn s keine Zahl ist, suche nach einer passenden Regel, und hole ihren Index. if (typeof s != "number") { s = s.toLowerCase( ); // Konvertiere zu Kleinbuchstaben var regeln = this.holeRegeln( ); for(var i = regeln.length-1; i >= 0; i--) { if (regeln[i].selectorText.toLowerCase( ) == s) { s = i; // Speichere den Index der zu löschenden Regel, break; // und beende die Suche } } // Haben wir keine Übereinstimmung gefunden, geben wir auf. if (i == -1) return; } // An dieser Stelle ist s eine Zahl. // Versuche es zuerst mit der W3C API und dann mit der IE API if (this.ss.deleteRule) this.ss.deleteRule(s); else if (this.ss.removeRule) this.ss.removeRule(s); };
16.6 Stylesheets per Skript steuern |
427
491-0.book Seite 428 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Chapter 1
KAPITEL 17
Events und Event-Handling
Wie ich in Kapitel 13 erklärt habe, verwenden interaktive JavaScript-Programme ein Event-gesteuertes Programmiermodell. Bei dieser Art der Programmierung erzeugt der Webbrowser ein Event, sobald mit dem Dokument oder einem seiner Elemente etwas Interessantes passiert. Beispielsweise erzeugt der Webbrowser ein Event, wenn ein Dokument vollständig geladen wurde, wenn der Benutzer die Maus bewegt oder auf einen Button eines Formulars klickt. Wenn sich eine JavaScript-Anwendung für eine bestimmte Art von Events interessiert, die an einem bestimmten Dokumentelement eintreten, kann sie einen Event-Handler – eine JavaScript-Funktion oder ein kurzes Stück Code – für diesen EventTyp bei dem Element registrieren. Wenn dann ein entsprechendes Event eintritt, ruft der Browser diesen Handler auf. Anwendungen mit grafischen Benutzeroberflächen sind immer in dieser Art programmiert: Sie warten darauf, dass der Benutzer etwas tut, was sie interessiert (d.h., sie warten darauf, dass Events eintreten), und reagieren dann. Nebenbei bemerkt hängen Timer und Error-Handler zur Fehlerbehandlung (die beide in Kapitel 14 beschrieben sind) mit dem Event-gesteuerten Programmiermodell zusammen. Wie die in diesem Kapitel beschriebenen Event-Handler funktionieren auch Timer und Error-Handler, indem sie eine Funktion beim Browser registrieren und ihm erlauben, diese Funktion aufzurufen, wenn das entsprechende Event eintritt. In diesen Fällen ist das interessante Ereignis, dass eine bestimmte Zeitspanne verstrichen oder ein JavaScript-Fehler aufgetreten ist. Obwohl Timer und Error-Handler in diesem Kapitel nicht behandelt werden, ist es hilfreich, sich die Verwandtschaft mit der Behandlung von Events vor Augen zu halten. Ich möchte Sie daher dazu anregen, Abschnitt 14.1 und Abschnitt 14.7 im Zusammenhang mit diesem Kapitel noch einmal zu lesen. Die meisten nicht-trivialen JavaScript-Programme verwenden Event-Handler intensiv. In den vorhergehenden Kapiteln haben wir bereits einige JavaScript-Beispiele gesehen, die einfache Event-Handler verwenden. Dieses Kapitel erläutert all die Details, die wir zu den Themen Events und Event-Handling bislang ausgespart haben. Leider sind diese Details
428 |
491-0.book Seite 429 Mittwoch, 4. April 2007 9:55 09
e-bol.net komplexer, als sie sein müssten, da derzeit drei verschiedene und zueinander inkompatible Event-Handling-Modelle verwendet werden1, und zwar:
Das Standard-Event-Modell: Dieses leistungsfähige Event-Modell mit allen Features wurde im DOM Level 2 standardisiert. Es wird von allen modernen Browsern außer Internet Explorer unterstützt. Das Event-Modell des Internet Explorers Dieses Event-Modell wurde erstmals in IE 4 verwendet und in IE 5 erweitert. Es hat einige, aber nicht alle der fortgeschrittenen Merkmale des Standard-Event-Modells. Obwohl Microsoft an der Entwicklung des Event-Modells des DOM Level 2 beteiligt war und genügend Zeit hatte, dieses Standard-Event-Modell in IE 5.5, IE 6 und IE 7 zu implementieren, ist Microsoft bei seinem Event-Modell geblieben. Daher müssen JavaScript-Programmierer, die fortgeschrittene Funktionen zum EventHandling verwenden wollen, speziellen Code für die Versionen des Internet Explorers programmieren. Dieses Kapitel dokumentiert die einzelnen Event-Modelle. Nach der Beschreibung der drei Event-Modelle folgen drei Abschnitte, die ausführliche Beispiele zur Handhabung von Maus-, Tastatur- und Onload-Events enthalten. Das Kapitel endet mit einer kurzen Einführung in das Erzeugen und Auslösen synthetischer Events.
17.1 Grundlegendes Event-Handling In den in diesem Buch bisher vorgestellten Programmen wurden Event-Handler als Strings mit JavaScript-Anweisungen angegeben, die als Werte bestimmter HTML-Attribute wie onclick verwendet wurden. Auch wenn dies den Schlüssel zum ursprünglichen Event-Modell darstellt, gibt es eine Reihe weiterer Einzelheiten, die Sie wissen sollten. Diese werden in den folgenden Abschnitten erläutert.
1 Netscape 4 hatte auch ein eigenes und inkompatibles Event-Modell. Dieser Browser ist allerdings kaum mehr in Gebrauch, und die Dokumentation seines Event-Modells ist aus diesem Buch entfernt worden.
17.1 Grundlegendes Event-Handling |
429
clientseitiges JavaScript
Das ursprüngliche Event-Modell: Dies ist das einfache Schema zum Event-Handling, das wir bislang in diesem Buch verwendet haben (ohne es gründlich zu dokumentieren). Es wurde – in beschränktem Umfang – im Standard HTML 4 festgelegt und wird informell als Teil der API des DOM Level 0 angesehen. Auch wenn es nur einen begrenzten Funktionsumfang bietet, wird es von allen JavaScript-fähigen Webbrowsern unterstützt und ist daher portabel.
491-0.book Seite 430 Mittwoch, 4. April 2007 9:55 09
e-bol.net
17.1.1 Events und Event-Typen Verschiedene Arten von Vorkommnissen erzeugen unterschiedliche Typen von Events. Wenn der Benutzer die Maus über einen Hypertext-Verweis bewegt, tritt ein anderer Typ von Event ein, als wenn der Benutzer mit der Maus auf den Hyperlink klickt. Auch kann dasselbe Vorkommnis je nach Kontext verschiedene Typen von Events auslösen: Wenn der Benutzer mit der Maus beispielsweise auf einen Submit-Button klickt, wird ein anderes Event erzeugt, als wenn er auf den Reset-Button eines Formulars klickt. Im ursprünglichen Event-Modell ist ein Event eine interne Abstraktion des Webbrowsers; JavaScript-Anweisungen können ein Event nicht unmittelbar bearbeiten. Wenn wir im ursprünglichen Event-Modell von einem Event-Typ sprechen, meinen wir eigentlich den Namen des Event-Handlers, der als Reaktion auf dieses Event aufgerufen wird. Bei diesem Modell werden die Anweisungen zum Event-Handling mit Hilfe der Attribute von HTML-Elementen angegeben (und den entsprechenden Eigenschaften der sie repräsentierenden JavaScript-Objekte). Wenn Ihre Anwendung daher mitbekommen soll, dass der Benutzer die Maus über einem bestimmten Hypertext-Verweis bewegt, müssen Sie das Attribut onmouseover des -Tags verwenden, das diesen Verweis definiert. Wenn Ihre Anwendung mitbekommen soll, dass der Benutzer den Submit-Button angeklickt hat, verwenden Sie das Attribut onclick des -Tags, das den Button definiert, oder das Attribut onsubmit des -Elements, das den Button enthält. Es gibt eine ganze Anzahl verschiedener Event-Handler-Attribute, die Sie im ursprünglichen Event-Modell verwenden können. Sie sind in Tabelle 17-1 aufgeführt. Dort wird auch angegeben, wann diese Event-Handler ausgelöst werden und welche HTML-Elemente die Handler-Attribute unterstützen. Mit der Weiterentwicklung von clientseitiger JavaScript-Programmierung wurde auch das Event-Modell erweitert. Jeder neuen Browserversion wurden neue Event-HandlerAttribute hinzugefügt. Die Spezifikation von HTML 4 hat schließlich eine Standardmenge von Event-Handler-Attributen für HTML-Tags festgelegt. Die dritte Spalte in Tabelle 17-1 gibt an, welche HTML-Elemente das jeweilige Event-Handler-Attribut unterstützen. Bei den Maus-Event-Handlern gibt Spalte drei an, dass das Handler-Attribut von den »meisten Elementen« unterstützt wird. Die HTML-Elemente, die diese Event-Handler nicht unterstützen, sind üblicherweise solche Elemente, die sich im -Teil eines Dokuments befinden oder keine eigene grafische Darstellung besitzen. Die folgenden Tags unterstützen diese annähernd universellen Attribute von MausEvent-Handlern nicht: , , , , , , , , , , und .
430 | Kapitel 17: Events und Event-Handling
491-0.book Seite 431 Mittwoch, 4. April 2007 9:55 09
e-bol.net Tabelle 17-1: Event-Handler und sie unterstützende HTML-Elemente Ausgelöst, wenn
Unterstützt von
onabort
das Laden des Bildes abgebrochen wurde.
onblur
das Element den Eingabefokus verliert.
, , , , ,
onchange
die Auswahl in einem -Element oder in einem anderen Formularelement den Fokus verliert und sein Wert sich geändert hat, seit das Element den Fokus erhalten hat.
, ,
onclick
die Maus gedrückt und losgelassen wurde; folgt auf ein mouseup-Event. Wird false zurückgegeben, wird die Standardaktion nicht durchgeführt (d.h. der Link verfolgt, das Formular abgeschickt, …).
den meisten Elementen
ondblclick
ein Doppelklick ausgeführt wurde.
den meisten Elementen
onerror
ein Fehler beim Laden des Bildes auftrat.
onfocus
das Element den Eingabefokus erhält.
, , , , ,
onkeydown
eine Taste heruntergedrückt wurde. Wird false zurückgegeben, wird die Eingabe nicht angezeigt.
Formularelementen und
onkeypress
eine Taste heruntergedrückt wurde; folgt keydown. Wird false zurückgegeben, wird die Eingabe nicht angezeigt.
Formularelementen und
onkeyup
eine Taste losgelassen wird; folgt keypress.
Formularelementen und
onload
das Dokument vollständig geladen wurde.
, ,
onmousedown
die Maustaste gedrückt wird.
den meisten Elementen
onmousemove
die Maus bewegt wurde.
den meisten Elementen
onmouseout
die Maus von einem Element wegbewegt wurde.
den meisten Elementen
onmouseover
die Maus über ein Element bewegt wurde.
den meisten Elementen
onmouseup
die Maustaste losgelassen wird.
den meisten Elementen
onreset
das Rücksetzen eines Formulars angefordert wurde. Wird false zurückgegeben, wird das Formular nicht zurückgesetzt.
onresize
die Fenstergröße geändert wurde.
,
onselect
Text ausgewählt wurde.
,
onsubmit
das Abschicken eines Formulars angefordert wurde. Wird false zurückgegeben, wird das Formular nicht abgeschickt.
onunload
das Dokument oder Frameset aus dem Browser entfernt wird.
,
clientseitiges JavaScript
Handler
17.1.1.1 Geräteabhängige und -unabhängige Events Wenn Sie die verschiedenen Event-Handler-Attribute in Tabelle 17-1 genauer betrachten, können Sie zwei grobe Kategorien von Events unterscheiden. Die eine ist die Kategorie der rohen Events oder Eingabe-Events. Diese Events werden erzeugt, wenn der Benutzer die Maus bewegt oder mit ihr klickt oder wenn der Benutzer eine Taste auf der Tastatur drückt. Diese elementaren Events beschreiben einfach eine Aktion des Benut-
17.1 Grundlegendes Event-Handling |
431
491-0.book Seite 432 Mittwoch, 4. April 2007 9:55 09
e-bol.net zers und haben keine weitergehende Bedeutung. Die zweite Kategorie von Events sind semantische Events. Sie haben eine komplexere Bedeutung und treten üblicherweise nur in bestimmten Kontexten auf – beispielsweise wenn der Browser ein Dokument vollständig geladen hat oder ein Formular abgeschickt werden soll. Ein semantisches Event tritt häufig als Nebeneffekt eines elementaren Events auf. Wenn beispielsweise der Benutzer mit der Maus einen Submit-Button anklickt, werden drei der Button-Eingabe-Handler ausgelöst: onmousedown, onmouseup und onclick. Als Resultat dieses Mausklicks erzeugt dann außerdem das HTML-Formular, das den Button enthält, ein onsubmit-Event. Eine andere wichtige Unterscheidung teilt Events in geräteabhängige Events, die speziell mit der Maus oder der Tastatur zusammenhängen, und geräteunabhängige Events ein, die auf mehr als eine Art und Weise ausgelöst werden können. Diese Unterscheidung ist besonders für die Barrierefreiheit wichtig (siehe Abschnitt 13.7), weil manche Benutzer eine Maus, aber keine Tastatur verwenden können. Andere können vielleicht eine Tastatur verwenden, aber keine Maus. Semantische Events, wie beispielsweise onsubmit und onchange, sind fast immer geräteunabhängige Events: Alle modernen Browser ermöglichen es Benutzern, durch HTML-Formulare sowohl per Maus als auch per Tastatur zu navigieren. Die Events, die die Wörter »mouse« oder »key« enthalten, sind ganz klar geräteabhängige Events. Wenn Sie sie verwenden, sollten Sie sie gegebenenfalls in Paaren verwenden, sodass Sie Handler sowohl für Mausgesten als auch eine Tastaturalternative zur Verfügung stellen. Beachten Sie, dass das onclick-Event als geräteunabhängiges Event gelten kann. Es ist nicht mausabhängig, da die Aktivierung von Formelementen und Hyperlinks durch die Tastatur ebenfalls dieses Event auslöst.
17.1.2 Event-Handler als Attribute Wie wir bereits in den vergangenen Kapiteln an mehreren Beispielen gesehen haben, werden Event-Handler (im ursprünglichen Event-Modell) als Strings mit JavaScript-Anweisungen angegeben, die als Werte von HTML-Attributen verwendet werden. Um daher beispielsweise JavaScript-Code auszuführen, wenn der Benutzer einen Button anklickt, geben Sie diesen Code als Wert des Attributs onclick des - oder -Tags an:
Der Wert eines Event-Handler-Attributs ist ein beliebiger String mit JavaScript-Anweisungen. Wenn der Handler aus mehreren JavaScript-Anweisungen besteht, müssen diese durch Semikola voneinander getrennt sein – beispielsweise:
Wenn ein Event-Handler mehrere Anweisungen benötigt, ist es meist einfacher, diese im Body einer Funktion zu definieren und anschließend das Event-Handler-Attribut für den Aufruf dieser Funktion zu verwenden. Wenn Sie beispielsweise die Eingaben eines Benutzers in einem Formular überprüfen wollen, bevor das Formular abgeschickt wird,
432 | Kapitel 17: Events und Event-Handling
491-0.book Seite 433 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Denken Sie daran, dass HTML nicht zwischen Groß- und Kleinschreibung unterscheidet, sodass Sie das Event-Handler-Attribut schreiben können, wie Sie möchten. Es hat sich eingebürgert, eine gemischte Schreibweise zu verwenden, bei der das initiale »on« kleingeschrieben wird: onClick, onLoad, onMouseOut und so fort. In diesem Buch verwende ich durchgängig kleingeschriebene Attribute, um so kompatibel zu XHTML zu sein, das zwischen Groß- und Kleinschreibung unterscheidet. Der JavaScript-Code in einem Event-Handler-Attribut darf eine return-Anweisung enthalten. Dabei kann der Rückgabewert eine besondere Bedeutung für den Browser besitzen. Wir werden uns dies bald ansehen. Beachten Sie außerdem, dass der JavaScriptCode eines Event-Handlers in einem anderen Geltungsbereich (siehe Kapitel 4) ausgeführt werden kann als globaler JavaScript-Code. Auch dies wird weiter unten in diesem Abschnitt besprochen.
17.1.3 Event-Handler als Eigenschaften Kapitel 15 zeigt, dass jedes HTML-Element in einem Dokument ein ihm entsprechendes DOM-Element im Dokumentenbaum besitzt und dass die Eigenschaften dieses JavaScript-Objekts den Attributen des HTML-Elements entsprechen. Das trifft für EventHandler-Attribute ebenfalls zu. Wenn also ein -Tag ein onclick-Attribut besitzt, kann auf den in diesem Attribut enthaltenen Event-Handler mit der onclick-Eigenschaft des Formularelement-Objekts zugegriffen werden. (JavaScript unterscheidet zwischen Groß- und Kleinschreibung; unabhängig von der im HTML-Attribut verwendeten Schreibweise muss die JavaScript-Eigenschaft vollständig kleingeschrieben werden.) Da der Wert eines Event-Handler-Attributs ein String mit JavaScript-Anweisungen ist, erwarten Sie vielleicht, dass der Wert der entsprechenden JavaScript-Eigenschaft ebenfalls ein String ist. Dies ist jedoch nicht der Fall: Beim Zugriff von JavaScript sind EventHandler-Eigenschaften Funktionen. Sie können dies mit einem einfachen Beispiel überprüfen:
2 Kapitel 18 beschreibt HTML-Formulare ausführlich und enthält ein Beispiel zur Formularüberprüfung.
17.1 Grundlegendes Event-Handling |
433
clientseitiges JavaScript
können Sie das Attribut onsubmit des -Tags verwenden.2 Für die Überprüfung eines Formulars sind meist mehrere oder sogar recht viele Programmzeilen notwendig. Anstatt alle diese Anweisungen in einen einzelnen langen Attributwert zu packen, ist es sinnvoller, eine Funktion für die Überprüfung des Formulars zu definieren und einfach das onclick-Attribut für den Aufruf der Funktion zu verwenden. Wenn Sie beispielsweise eine Funktion namens pruefeFormular( ) definiert haben, die die Überprüfung vornimmt, können Sie sie aus einem Event-Handler folgendermaßen aufrufen:
491-0.book Seite 434 Mittwoch, 4. April 2007 9:55 09
e-bol.net Wenn Sie den Button anklicken, wird ein Dialog angezeigt, der das Wort »function«, nicht das Wort »string« enthält. (Beachten Sie, dass sich bei Event-Handlern das Schlüsselwort this auf das Objekt bezieht, bei dem das Event eingetreten ist. Wir werden uns das Schlüsselwort this gleich genauer ansehen.) Um in JavaScript einem Dokumentelement einen Event-Handler zuzuweisen, weisen Sie der Event-Handler-Eigenschaft einfach die gewünschte Funktion zu. Betrachten Sie beispielsweise das folgende HTML-Formular:
Auf den Button in diesem Formular können Sie mit document.f1.b1 zugreifen, sodass mit einer JavaScript-Zeile wie der folgenden ein Event-Handler zugewiesen werden kann: document.f1.b1.onclick=function( ) { alert('Danke!'); };
Ein Event-Handler kann auch folgendermaßen zugewiesen werden: function bitten( ) { document.f1.b1.value += " bitte!"; } document.f1.b1.onmouseover = bitten;
Beachten Sie besonders die letzte Zeile: Auf den Namen der Funktion folgen dort keine Klammern! Um einen Event-Handler zu definieren, weisen Sie der Event-Handler-Eigenschaft die Funktion selbst zu, nicht das Ergebnis eines Funktionsaufrufs. Hier stolpern unerfahrene JavaScript-Programmierer oft. Wenn man Event-Handler als JavaScript-Eigenschaften ausdrückt, ergeben sich verschiedene Vorteile. Der erste und wichtigste Vorteil ist die geringere Vermischung von HTMLund JavaScript, was die Modularität und saubereren und einfacher zu wartenden Code fördert. Zweitens können Event-Handler-Funktionen somit dynamisch werden. Im Gegensatz zu HTML-Attributen, die einen statischen Teil des Dokuments darstellen, können JavaScript-Eigenschaften jederzeit geändert werden. In komplexen interaktiven Programmen kann es hilfreich sein, die für HTML-Elemente registrierten Event-Handler dynamisch zu ändern. Ein kleiner Nachteil bei der Definition von Event-Handlern in JavaScript besteht darin, dass der Handler von dem Element getrennt wird, zu dem er gehört. Wenn der Benutzer mit einem Dokumentelement interagiert, bevor das Dokument vollständig geladen wurde (und bevor alle seine Skripten ausgeführt wurden), kann es sein, dass der EventHandler für das Dokumentelement noch nicht definiert ist. Beispiel 17-1 zeigt, wie Sie eine einzige Funktion als Event-Handler für viele Dokumentelemente angeben. Das Beispiel ist eine einfache Funktion, die einen onclick-Event-Handler für jeden Link in einem Dokument definiert. Der Event-Handler bittet den Benutzer um Bestätigung, bevor der Browser den Hyperlink verfolgt, auf den der Benutzer soeben geklickt hat. Die Event-Handler-Funktion gibt false zurück, wenn der Benutzer die Nachfrage nicht bestätigt; dadurch verfolgt der Browser den Link nicht. Die Rückgabewerte von Event-Handlern werden wir uns gleich anschauen.
434 | Kapitel 17: Events und Event-Handling
491-0.book Seite 435 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-1: Eine Funktion, viele Event-Handler
clientseitiges JavaScript
// Diese Funktion kann als onclick-Event-Handler für - und -Elemente // verwendet werden. Sie verwendet das Schlüsselwort this, um auf das Dokumentelement // zuzugreifen, und kann false zurückgeben, damit der Browser dem Link nicht folgt. function bestaetigeLink( ) { return confirm("Möchten Sie wirklich die Seite " + this.href + " besuchen?"); } // Diese Funktion durchläuft alle Hyperlinks in einem Dokument und weist jeweils // die Funktion bestaetigeLink als Event-Handler zu. Sie darf erst aufgerufen // werden, wenn das Dokument analysiert wurde und alle Links definiert sind. // Am besten wird sie vom onload-Event-Handler eines -Tags aufgerufen. function bestaetigeAlleLinks( ) { for(var i = 0; i < document.links.length; i++) { document.links[i].onclick = bestaetigeLink; } }
17.1.3.1 Event-Handler explizit aufrufen Da die Werte von Event-Handler-Eigenschaften in JavaScript Funktionen sind, können Sie JavaScript verwenden, um Event-Handler-Funktionen direkt aufzurufen. Wenn Sie beispielsweise das onsubmit-Attribut eines -Tags verwenden, um eine Funktion zur Überprüfung eines Formulars zu definieren, und Sie dieses Formular bereits prüfen möchten, bevor der Benutzer versucht, es abzuschicken, können Sie die onsubmit-Eigenschaft des Form-Objekts verwenden, um die Event-Handler-Funktion aufzurufen. Die Anweisung dazu kann folgendermaßen aussehen: document.meinFormular.onsubmit( );
Beachten Sie jedoch, dass der Aufruf eines Event-Handlers nicht das Eintreten des entsprechenden Events simuliert. Wenn Sie beispielsweise die onclick( )-Methode eines Link-Objekts aufrufen, folgt der Browser dem Link nicht, und es wird kein neues Dokument geladen. Er führt lediglich die von Ihnen als Wert dieser Eigenschaft definierte Funktion aus. Damit der Browser ein neues Dokument lädt, setzen Sie die locationEigenschaft des Window-Objekts (wie in Kapitel 14 gezeigt). Das Gleiche gilt für die onsubmit( )-Methode eines Form-Objekts oder die onclick( )-Methode eines SubmitObjekts: Der Aufruf der Methode führt die Event-Handler-Funktion aus, sendet aber das Formular nicht ab. Um das Formular tatsächlich abzuschicken, rufen Sie die submit( )Methode des Form-Objekts auf. Eine Event-Handler-Funktion rufen Sie z.B. dann explizit auf, wenn Sie JavaScript verwenden möchten, um einen Event-Handler, der eventuell bereits im HTML-Text definiert wurde, um zusätzliche Funktionen zu erweitern. Nehmen wir an, Sie wollten eine bestimmte Aktion ausführen, wenn der Benutzer einen Button anklickt, aber einen bereits im HTML-Dokument definierten onclick-Event-Handler nicht außer Kraft setzen. (Dies ist eines der Probleme, die wir in Beispiel 17-1 haben: Durch die Definition
17.1 Grundlegendes Event-Handling |
435
491-0.book Seite 436 Mittwoch, 4. April 2007 9:55 09
e-bol.net eines Handlers für jeden Hyperlink werden bereits für die Links definierte onclick-Handler überschrieben.) Sie können dies mit Programmzeilen wie den folgenden erreichen: var b = document.meinFormular.meinButton; // Der Button, der uns interessiert var alterHandler = b.onclick; // Sichere den HTML-Event-Handler function neuerHandler( ) { /* Hier folgt mein Code zum Event-Handling */ } // Nun weisen wir einen neuen Event-Handler zu, der sowohl den alten als auch den neuen // Handler aufruft b.onclick = function() { alterHandler(); neuerHandler( ); }
17.1.4 Rückgabewerte von Event-Handlern In vielen Fällen verwenden Event-Handler (unabhängig davon, ob sie als HTML-Attribut oder als JavaScript-Eigenschaft angegeben wurden) ihren Rückgabewert, um die Art des Events anzuzeigen. Sie könnten beispielsweise den Event-Handler onsubmit eines FormObjekts benutzen, um die Überprüfung eines Formulars durchzuführen. Wenn Sie dabei feststellen, dass der Benutzer nicht alle Felder ausgefüllt hat, kann der Handler den Wert false zurückgeben, um zu verhindern, dass das Formular abgeschickt wird. Um ein leeres Formular nicht abzuschicken, können Sie den folgenden Code verwenden:
Im Allgemeinen können Sie den Wert false zurückgeben, wenn der Webbrowser als Antwort auf ein Event eine voreingestellte Aktion nicht ausführen soll. Außer dem EventHandler onsubmit können auch onclick, onkeydown, onkeypress, onmousedown, onmouseup und onreset den Wert false zurückgeben, um eine vordefinierte Aktion nicht auszuführen. Die zweite Spalte von Tabelle 17-1 zeigt, was passiert, wenn Sie false zurückgeben. Von der Regel, false für den Abbruch einer Aktion zurückzugeben, gibt es eine Ausnahme: Wenn der Benutzer die Maus auf einen Hyperlink bewegt, besteht die vordefinierte Aktion des Browsers darin, die URL des Links in der Statuszeile anzuzeigen. Wenn Sie dies verhindern möchten, muss Ihr Event-Handler onmouseover den Wert true zurückgeben. Beispielsweise können Sie versuchen, eine von einer URL verschiedene Mitteilung mit der folgenden Zeile in der Statuszeile anzuzeigen: Hilfe
Für diese Ausnahme gibt es keinen guten Grund, außer dass Browser sich schon immer so verhalten haben. Wie in Kapitel 14 bereits erwähnt wurde, betrachten die meisten Browser die Fähigkeit, die Ziel-URL eines Links nicht anzuzeigen, allerdings als Sicherheitslücke und haben sie daher deaktiviert. Deshalb wurde die einzige Ausnahme zur Regel »false zum Abbruch einer Aktion zurückgeben« irrelevant. Beachten Sie, dass Event-Handler keinen Wert zurückgeben müssen. Wenn Sie keinen Wert zurückgeben, wird die vordefinierte Aktion ausgeführt.
436 | Kapitel 17: Events und Event-Handling
491-0.book Seite 437 Mittwoch, 4. April 2007 9:55 09
e-bol.net
17.1.5 Event-Handler und das Schlüsselwort this
Beachten Sie jedoch, was dies bedeutet! Nehmen wir an, Sie hätten ein Objekt o mit einer Methode meineMethode definiert. Sie könnten einen Event-Handler dann folgendermaßen registrieren: button.onclick= o.meineMethode;
Durch diese Anweisung verweist button.onclick auf die gleiche Funktion wie o.meineMethode. Diese Funktion ist jetzt eine Methode von sowohl o als auch button. Wenn der Browser diesen Event-Handler auslöst, ruft er die Funktion als Methode des buttonObjekts auf und nicht als Methode von o. Das Schlüsselwort this bezieht sich auf das Button-Objekt und nicht auf Ihr o-Objekt. Machen Sie nicht den Fehler zu glauben, Sie könnten den Browser dazu bringen, einen Event-Handler als Methode eines anderen Objekts aufzurufen. Wenn Sie dies tun möchten, müssen Sie explizit eine eigene Funktion definieren: button.onclick = function( ) { o.meineMethode( ); }
17.1.6 Geltungsbereich von Event-Handlern Wie Sie in Kapitel 8.8 gesehen haben, besitzen Funktionen in JavaScript einen lexikalischen Geltungsbereich. Sie werden daher in dem Geltungsbereich ausgeführt, in dem sie definiert wurden, und nicht in dem Geltungsbereich, aus dem heraus sie aufgerufen werden. Wenn Sie einen Event-Handler definieren, indem Sie den Wert eines HTML-Attributs auf einen String von JavaScript-Code setzen, definieren Sie damit automatisch eine JavaScript-Funktion. Es ist wichtig zu verstehen, dass der Geltungsbereich einer auf diese Weise definierten Event-Handler-Funktion nicht das Gleiche ist wie der Geltungsbereich anderer normal definierter globaler JavaScript-Funktionen. Als HTML-Attribute definierte Event-Handler werden in einem anderen Geltungsbereich ausgeführt als andere Funktionen.3 Sie haben in Kapitel 4 gesehen, dass der Geltungsbereich einer Funktion durch eine Geltungsbereichskette definiert ist – eine Liste von Objekten, die nacheinander nach Variablendefinitionen durchsucht werden. Wenn in einer normalen Funktion nach einer
3 Es ist wichtig, dies zu verstehen. Die folgende Darstellung ist sehr interessant, aber auch sehr kompakt. Wenn Sie das Buch erstmals lesen, können Sie dieses Kapitel auch überspringen und es später studieren.
17.1 Grundlegendes Event-Handling |
437
clientseitiges JavaScript
Egal ob Sie einen Event-Handler durch ein HTML-Attribut oder durch eine JavaScriptEigenschaft definieren: Sie weisen einer Eigenschaft eines Dokumentelements eine Funktion zu. Anders gesagt, definieren Sie eine neue Methode des Dokumentelements. Wenn Ihr Event-Handler aufgerufen wird, wird er als eine Methode des Elements aufgerufen, an dem das Event eingetreten ist. Das Schlüsselwort this verweist daher auf dieses Zielelement – nützlicherweise und wenig überraschend.
491-0.book Seite 438 Mittwoch, 4. April 2007 9:55 09
e-bol.net Variablen x gesucht wird, schaut JavaScript zunächst nach einer lokalen Variablen oder einem Argument, indem das Aufrufobjekt der Funktion nach einer Eigenschaft dieses Namens durchsucht wird. Wenn keine solche Eigenschaft gefunden wird, fährt JavaScript mit dem nächsten Objekt in der Geltungsbereichskette fort: mit dem globalen Objekt. Die Eigenschaften des globalen Objekts werden geprüft, um herauszufinden, ob die Variable eine globale Variable ist. Als HTML-Attribute definierte Event-Handler besitzen eine komplexere Geltungsbereichskette. Der Anfang der Geltungsbereichskette ist das Aufrufobjekt. Alle an den Event-Handler übergebenen Argumente sind hier definiert (weiter unten in diesem Kapitel werden Sie sehen, dass in einigen der fortgeschrittenen Event-Modelle Event-Handler ein Argument erhalten) – genauso wie alle lokalen Variablen, die im Body des EventHandlers definiert sind. Das nächste Objekt in der Geltungsbereichskette des EventHandlers ist jedoch nicht das globale Objekt, sondern das Objekt, das den Event-Handler ausgelöst hat. Nehmen wir beispielsweise an, Sie verwenden ein -Tag, um ein Button-Objekt in einem HTML-Formular zu definieren, und benutzen das Attribut onclick, um einen Event-Handler zu definieren. Wenn die Anweisungen des EventHandlers eine Variable namens form verwenden, wird diese Variable so aufgelöst, dass sie sich auf die form-Eigenschaft des Button-Objekts bezieht. Dies kann eine nützliche Abkürzung sein, wenn Sie Event-Handler als HTML-Attribute schreiben, beispielsweise:
Wie Sie an diesem Beispielcode sehen, endet die Geltungsbereichskette eines EventHandlers nicht bei dem Objekt, das den Handler definiert: Sie wird entlang der Hierarchie fortgeführt, in der die einzelnen Elemente enthalten sind. Sie enthält mindestens das HTML-Element , das wiederum die Schaltfläche und das Document-Objekt mit
438 | Kapitel 17: Events und Event-Handling
491-0.book Seite 439 Mittwoch, 4. April 2007 9:55 09
e-bol.net dem Formular enthält.4 Das letzte Objekt in der Geltungsbereichskette ist, wie immer in clientseitigem JavaScript, das Window-Objekt. Eine andere Möglichkeit, die erweiterte Geltungsbereichskette der Event-Handler zu sehen, ist die Übersetzung des JavaScript-Texts im HTML-Event-Handler-Attribut in eine JavaScript-Funktion. Nehmen wir die folgenden Zeilen aus dem letzten Beispiel: clientseitiges JavaScript
Der entsprechende JavaScript-Code wäre der folgende: var b3 = document.getElementById('b3'); // Hole den Button, der uns interessiert b3.onclick = function( ) { with (document) { with(this.form) { with(this) { alert(b4.value); } } } }
Die sich wiederholenden with-Anweisungen erzeugen eine erweiterte Geltungsbereichskette. Wenn Sie sich an diese selten genutzte Anweisung nicht mehr erinnern können, sollten Sie in Abschnitt 6.18 nachschlagen. Die Anwesenheit des Zielobjekts in der Geltungsbereichskette eines Event-Handlers ist eine nützliche Abkürzung. Dagegen kann eine erweiterte Geltungsbereichskette, die auch andere Dokumentelemente umfasst, ein Ärgernis sein. Beispielsweise definieren sowohl Window- als auch Document-Objekte Methoden namens open( ). Wenn Sie den Bezeichner open ohne weitere Angaben verwenden, greifen Sie meistens auf die Methode window.open( ) zu. In einem als HTML-Attribut definierten Event-Handler allerdings steht das Document-Objekt in der Geltungsbereichskette vor dem Window-Objekt. Wenn Sie open ohne weiteren Zusatz verwenden, rufen Sie daher die Methode document.open( ) auf. Bedenken Sie auch, was geschieht, wenn Sie in einem Form-Objekt eine Eigenschaft namens window definieren (oder ein Eingabefeld mit dem Attribut name="window"). Wenn Sie dann einen Event-Handler in diesem Formular definieren, der den Ausdruck window.open( ) verwendet, wird der Bezeichner window so aufgelöst, dass er auf die Eigenschaft des Form-Objekts statt auf das globale Window-Objekt verweist. Event-Handler in diesem Formular können daher nicht auf einfache Weise auf das globale Window-Objekt zugreifen oder die Methode window.open( ) aufrufen!
4 Die genaue Zusammensetzung der Geltungsbereichskette ist nie standardisiert worden und kann von der jeweiligen Implementierung abhängen.
17.1 Grundlegendes Event-Handling |
439
491-0.book Seite 440 Mittwoch, 4. April 2007 9:55 09
e-bol.net Daher müssen Sie vorsichtig sein, wenn Sie Event-Handler als HTML-Attribute definieren. Das sicherste Verfahren besteht darin, die Handler sehr einfach zu halten. Im Idealfall sollten sie einfach eine globale Funktion aufrufen, die andernorts definiert wurde und gegebenenfalls einen Wert zurückgibt: function validateForm( ) { /* Formularüberprüfungscode steht hier */ } ...
Ein einfacher Event-Handler wie dieser wird nichtsdestotrotz mit Hilfe einer ungewöhnlichen Geltungsbereichskette ausgeführt. Da aber der Code kurz gehalten wird, minimieren Sie die Gefahr, über eine lange Geltungsbereichskette zu stolpern. Denken Sie wieder daran, dass bei der Ausführung von Funktionen der Geltungsbereich verwendet wird, in dem die Funktion definiert wurde, nicht der Geltungsbereich, in dem sie aufgerufen wird. Selbst wenn also unsere Beispielmethode pruefeFormular( ) von einem ungewöhnlichen Geltungsbereich aus aufgerufen wird, wird sie in ihrem eigenen globalen Geltungsbereich ausgeführt, sodass keine Verwirrungen auftreten können. Da es keinen Standard für die genaue Zusammensetzung der Geltungsbereichskette eines Event-Handlers gibt, ist es am sichersten anzunehmen, dass sie nur aus dem Zielelement und dem globalen Window-Objekt besteht. Verwenden Sie beispielsweise this, um auf das Zielelement zu verweisen; und wenn das Ziel ein -Element ist, dürfen Sie auch form statt this.form verwenden, um auf das umgebende Form-Objekt zuzugreifen. Verlassen Sie sich aber nicht darauf, dass die Form- oder Document-Objekte in der Geltungsbereichkette sind. Verwenden Sie zum Beispiel nicht action statt form.action oder getElementById statt document.getElementById. Denken Sie schließlich daran, dass alles, was hier zum Thema Geltungsbereich von Event-Handlern gesagt wurde, nur für Event-Handler gilt, die als HTML-Attribute definiert sind. Wenn Sie einen Event-Handler durch Zuweisung einer Funktion an eine entsprechende Event-Handler-Eigenschaft in JavaScript angeben, wird keine besondere Geltungsbereichskette gebildet. Ihre Funktion wird dann in dem Geltungsbereich ausgeführt, in dem sie definiert wurde. Dies ist fast immer der globale Geltungsbereich – außer wir haben es mit einer inneren Funktion zu tun; dann kann die Geltungsbereichskette wieder interessant werden!
17.2 Fortgeschrittenes Event-Handling mit dem DOM Level 2 Die Techniken zum Event-Handling, die wir in diesem Kapitel bislang betrachtet haben, sind Teil des Level 0 des DOM: der De-facto-Standard für die API, der von jedem JavaScript-fähigen Browser unterstützt wird. DOM Level 2 definiert eine erweiterte API für das Event-Handling, die sich grundlegend von der API des Level 0 unterscheidet (und ein gutes Stück mächtiger ist). Der Standard des Level 2 übernimmt die vorhandene API nicht in das Standard-DOM; dennoch besteht keine Gefahr, dass die API des Level 0 nicht mehr unterstützt wird. Für einfache Aufgaben des Event-Handlings können Sie die einfache API weiterhin verwenden.
440 | Kapitel 17: Events und Event-Handling
491-0.book Seite 441 Mittwoch, 4. April 2007 9:55 09
e-bol.net Das DOM Level 2 Event-Modell wird von allen modernen Browsern außer Internet Explorer unterstützt.
17.2.1 Event-Propagation
Die nächste Phase der Verbreitung von Events betrifft den Zielknoten selbst: Alle für das Event direkt am Zielobjekt registrierten Event-Handler werden ausgeführt. Dies ähnelt dem Event-Handling, das vom Event-Modell im Level 0 durchgeführt wurde. In der dritten Phase steigt das Event wie ein Bläschen durch die Dokument-Hierarchie vom Zielelement bis zum Document-Objekt nach oben (engl. bubbling). Zwar durchlaufen alle Events die erste Phase der Event-Verbreitung, aber nicht alle Typen von Events steigen auf: Beispielsweise ist es wenig sinnvoll, ein Event, mit dem ein Formular abgeschickt wird, oberhalb des betroffenen -Elements weiter durch das Dokument zu verbreiten. Andererseits können generische Events wie das Drücken einer Maustaste für jedes Element im Dokument von Interesse sein, sodass diese durch die Dokument-Hierarchie aufsteigen und dabei alle angemessen erscheinenden Event-Handler bei jedem der Vorfahren des Zielelements auslösen. Im Allgemeinen steigen Eingabe-Events auf, semantische Events dagegen nicht. (In Tabelle 17-3 finden Sie eine Liste dazu, welche Events aufsteigen und welche nicht.) Während der Event-Propagation kann jeder Event-Handler die weitere Verbreitung des Events durch den Aufruf der Methode stopPropagation( ) des Event-Objekts beenden, das das Event repräsentiert. Das Event-Objekt und seine Methode stopPropagation( ) werden weiter unten in diesem Kapitel näher besprochen. Einige Events veranlassen den Webbrowser, eine voreingestellte Aktion durchzuführen. Wenn beispielsweise ein Mausklick als Event bei einem -Tag auftritt, besteht die vordefinierte Aktion des Browsers darin, dem Verweis zu folgen. Solche vordefinierten
17.2 Fortgeschrittenes Event-Handling mit dem DOM Level 2 |
441
clientseitiges JavaScript
Im Event-Modell des Level 0 verteilt der Browser eintretende Events an die Dokumentelemente, bei denen sie eingetreten sind. Wenn das betreffende Objekt einen entsprechenden Event-Handler besitzt, wird dieser ausgeführt. Das ist alles. Die Situation in DOM Level 2 ist etwas komplexer. Wenn in diesem erweiterten Event-Modell ein Event bei einem Dokumentknoten (dem Ziel des Events) auftritt, werden der bzw. die EventHandler des Zielobjekts ausgelöst; zusätzlich aber erhalten die Vorfahren des Zielobjekts im Dokumentenbaum jeweils ein oder zwei Möglichkeiten, das Event zu behandeln. Die Verbreitung von Events (die sogenannte Event-Propagation) erfolgt in drei Phasen. Zunächst wird das Event abgefangen (engl. capturing); dabei werden Events vom Document-Objekt nach unten durch den Dokumentenbaum zum Zielknoten verbreitet. Wenn einer der Vorfahren des Ziels (nicht aber das Ziel selbst) einen zu diesem Zweck registrierten abfangenden Event-Handler definiert hat, werden diese Handler in dieser Phase der Event-Verbreitung ausgeführt. (Wie normale und abfangende Event-Handler registriert werden, werden Sie gleich herausfinden.)
491-0.book Seite 442 Mittwoch, 4. April 2007 9:55 09
e-bol.net Aktionen werden erst ausgeführt, nachdem alle drei Phasen der Event-Propagation abgeschlossen sind. Während der Verbreitung der Events hat jeder der dabei aufgerufenen Handler die Gelegenheit, die Ausführung der voreingestellten Aktion zu verhindern, indem er die Methode preventDefault( ) des Event-Objekts aufruft. Diese Art der Event-Propagation mag zwar etwas gewunden aussehen; sie kann Ihnen aber bei der Zentralisierung Ihres Event-Handling-Codes helfen. DOM Level 1 legt alle Dokumentelemente offen und erlaubt das Eintreten von Events (wie beispielsweise mouseover-Events) für beliebige dieser Elemente. Daher gibt es sehr, sehr viel mehr Orte, an denen Event-Handler registriert werden können, als im alten Event-Modell des Level 0. Nehmen wir an, Sie wollten einen Event-Handler immer dann auslösen, wenn der Benutzer die Maus über ein
-Element in Ihrem Dokument bewegt. Anstatt einen onmouseover-Event-Handler für jedes
-Tag zu registrieren, können Sie einen einzigen Event-Handler für das Document-Objekt registrieren und diese Events während der Phase des Abfangens oder Aufsteigens der Events behandeln. Es gibt einen weiteren wichtigen Aspekt der Event-Propagation. Im Modell des Level 0 können Sie nur einen einzelnen Event-Handler für jeden Typ von Event an einem gegebenen Objekt registrieren. Im Modell des Level 2 dagegen können Sie beliebig viele Handler-Funktionen für einen gegebenen Event-Typ an einem gegebenen Objekt registrieren. Dies gilt auch für Vorfahren des Event-Ziels, deren Handler-Funktion oder -Funktionen während der Phasen des Abfangens oder Aufsteigens der Events aufgerufen werden.
17.2.2 Registrierung von Event-Handlern In der API des Level 0 registrieren Sie einen Event-Handler, indem Sie einem Attribut in Ihrem HTML-Quelltext oder einer Objekteigenschaft in Ihrem JavaScript-Code einen Wert zuweisen. Im Event-Modell des Level 2 registrieren Sie einen Event-Handler für ein gegebenes Element, indem Sie die Methode addEventListener( ) dieses Objekts aufrufen. (Der DOM-Standard verwendet den Begriff »Listener« in seiner API; ich werde dennoch weiterhin das Synonym »Handler« in diesen Erörterungen verwenden.) Diese Methode nimmt drei Argumente entgegen. Das erste ist der Name des Event-Typs, für den der Handler registriert wird. Der Event-Typ sollte als String angegeben werden, der den kleingeschriebenen Namen des HTML-Handler-Attributs ohne die Vorsilbe »on« enthält. Wenn Sie also im Modell des Level 0 ein HTML-Attribut onmousedown oder eine Eigenschaft onmousedown verwenden würden, benutzen Sie im Event-Modell des Level 2 den String »mousedown«. Das zweite an addEventListener( ) übergebene Argument ist die Handler- (oder Listener-) Funktion, die aufgerufen werden soll, wenn der angegebene Event-Typ eintritt. Wenn Ihre Funktion aufgerufen wird, wird ihr als einziges Argument ein Event-Objekt übergeben. Dieses Objekt enthält genauere Informationen über das Event (beispielsweise, welche Maustaste gedrückt wurde). Außerdem definiert das Event-Objekt Methoden wie stopPropagation( ). Das Event-Interface und seine Sub-Interfaces werden später in diesem Kapitel ausführlicher beschrieben.
442 | Kapitel 17: Events und Event-Handling
491-0.book Seite 443 Mittwoch, 4. April 2007 9:55 09
e-bol.net Das letzte an addEventListener( ) übergebene Argument ist ein Boolescher Wert. Ist dieser true, fängt der angegebene Event-Handler Events während der ersten Phase der Event-Propagation ein. Wenn das Argument den Wert false besitzt, ist der Event-Handler ganz normal und wird nur ausgelöst, wenn das Event direkt an dem Objekt oder einem Nachfolger des Elements auftritt und anschließend zu dem Element aufsteigt.
Wenn Sie alle mousedown-Events abfangen möchten, die in einem bestimmten benannten -Element eintreten, können Sie addEventListener( ) wie folgt verwenden: var meinDiv = document.getElementById("meinDiv"); meinDiv.addEventListener("mousedown", behandleMouseDown, true);
Beachten Sie, dass in diesen Beispielen angenommen wird, dass Sie die Funktionen namens pruefe( ) und behandleMouseDown( ) andernorts in Ihrem JavaScript-Code definiert haben. Mit addEventListener( ) registrierte Event-Handler werden in dem Geltungsbereich ausgeführt, in dem sie definiert sind. Sie werden nicht mit der in Abschnitt 17.1.6 beschriebenen erweiterten Geltungsbereichskette aufgerufen. Da Event-Handler im Modell des Level 2 durch den Aufruf einer Methode statt durch Zuweisung eines Attributs oder einer Eigenschaft registriert werden, können Sie mehrere Event-Handler für einen gegebenen Event-Typ an einem gegebenen Objekt registrieren. Wenn Sie addEventListener( ) mehrfach aufrufen, um mehrere Handler-Funktionen für den gleichen Event-Typ beim gleichen Objekt zu registrieren, werden alle von Ihnen registrierten Funktionen aufgerufen, wenn ein Event dieses Typs an diesem Objekt eintritt (oder zu ihm aufsteigt oder von ihm abgefangen wird). Beachten Sie, dass der DOMStandard keine Garantie dafür gibt, dass die Handler-Funktionen eines einzelnen Objekts in einer bestimmten Reihenfolge aufgerufen werden. Daher sollten Sie sich nicht darauf verlassen, dass die Handler-Funktionen in der Reihenfolge aufgerufen werden, in der Sie sie registriert haben. Wenn Sie dieselbe Handler-Funktion mehrfach für das gleiche Element registrieren, werden alle Registrierungen nach der ersten ignoriert. Warum sollten Sie mehrere Handler-Funktionen für das gleiche Event an demselben Objekt registrieren wollen? Dies kann bei einer Modularisierung Ihrer Software sehr nützlich sein. Nehmen Sie beispielsweise an, dass Sie ein wiederverwendbares JavaScript-Modul geschrieben haben, das mouseover-Events an Bildern verwendet, um Rollover-Effekte zu erzielen. Stellen Sie sich vor, Sie haben ein anderes Modul, das die gleichen mouseover-Events verwenden will, um zusätzliche Informationen über das Bild in einem DHTML-Popup oder -Tooltip anzuzeigen. In der API des Level 0 müssten Sie
17.2 Fortgeschrittenes Event-Handling mit dem DOM Level 2 |
443
clientseitiges JavaScript
Beispielsweise können Sie mit addEventListener( ) einen Handler für Submit-Events eines -Elements folgendermaßen registrieren:
491-0.book Seite 444 Mittwoch, 4. April 2007 9:55 09
e-bol.net diese beiden Module zu einem zusammenfassen, so dass beide die eine onmouseoverEigenschaft des Image-Objekts gemeinsam nutzen können. In der API des Level 2 dagegen kann jedes Modul den von ihm benötigten Event-Handler registrieren, ohne etwas über das andere Modul zu wissen oder diesem ins Gehege zu kommen. Das Gegenstück zu addEventListener( ) ist die Methode removeEventListener( ), die dieselben drei Argumente entgegennimmt, aber eine Event-Handler-Funktion von einem Objekt entfernt, anstatt eine Funktion hinzuzufügen. Oft ist es hilfreich, einen EventHandler nur zeitweilig zu registrieren und ihn bald danach wieder zu entfernen. Wenn Sie beispielsweise ein mousedown-Event erhalten, können Sie vorübergehend abfangende Event-Handler für mousemove- und mouseup-Events registrieren, um festzustellen, ob der Benutzer die Maus zieht. Sie können diese Handler sofort deregistrieren, wenn das mouseup-Event eintritt. In einem solchen Fall können Ihre Anweisungen zur Entfernung der Event-Handler folgendermaßen aussehen: document.removeEventListener("mousemove", behandleMouseMove, true); document.removeEventListener("mouseup", behandleMouseUp, true);
Die Methoden addEventListener( ) und removeEventListener( ) werden vom Interface EventTarget definiert. Bei Webbrowsern, die das DOM Level 2-Event-Modul unterstützen, implementieren die Element- und Dokumentknoten dieses Interface und stellen diese Event-Registrierungsmethoden zur Verfügung.5 Teil IV dokumentiert diese Methoden unter Document und Element, hat aber keinen Eintrag für das Interface EventTarget selbst.
17.2.3 addEventListener( ) und das Schlüsselwort this Wenn im ursprünglichen Event-Modell des Level 0 eine Funktion als Event-Handler für ein Dokumentelement registriert wird, wird sie zu einer Methode des Dokumentelements (wie oben in Abschnitt 17.1.5 dargestellt). Wenn der Event-Handler aufgerufen wird, wird er als eine Methode des Elements aufgerufen; innerhalb der Funktion verweist das Schlüsselwort this auf das Element, an dem das Event eintrat. DOM Level 2 ist sprachunabhängig geschrieben und schreibt vor, dass Event-Listener keine einfachen Funktionen, sondern Objekte sind. Die JavaScript-Bindung des DOM macht JavaScript-Funktionen zu Event-Handlern, anstatt die Verwendung eines JavaScript-Objekts zu verlangen. Leider sagt die Bindung nicht, wie die Handler-Funktion aufgerufen wird, und gibt den Wert des this-Schlüsselworts nicht an.
5 Genau genommen sagt DOM, dass alle Knoten eines Dokuments (einschließlich z.B. Textknoten) das EventTarget-Interface implementieren. In der Praxis unterstützen Webbrowser allerdings die Event-Handler-Registrierung nur an Element- und Document-Knoten sowie am Window-Objekt, obwohl dieses außerhalb des DOMGeltungsbereichs liegt.
444 | Kapitel 17: Events und Event-Handling
491-0.book Seite 445 Mittwoch, 4. April 2007 9:55 09
e-bol.net
17.2.4 Registrierung von Objekten als Event-Handler Mit der Methode addEventListener( ) können Sie Event-Handler-Funktionen registrieren. In der objektorientierten Programmierung werden Sie es vielleicht vorziehen, EventHandler als Methoden eines speziellen Objekts zu definieren, sodass diese als Methoden des Objekts aufgerufen werden. Für Java-Programmierer erlaubt der DOM-Standard genau dies: Er legt fest, dass Event-Handler Objekte sind, die das EventListener-Interface und eine Methode namens handleEvent( ) implementieren. Wenn Sie in Java einen EventHandler registrieren, übergeben Sie ein Objekt an addEventListener( ), keine Funktion. Der Einfachheit halber verlangt die JavaScript-Bindung der DOM API von Ihnen nicht, dass Sie ein EventListener-Interface implementieren. Stattdessen können Sie direkt Funktionsreferenzen an addEventListener( ) übergeben. Wenn Sie ein objektorientiertes JavaScript-Programm schreiben und lieber Objekte als Event-Handler verwenden, können Sie eine Funktion wie die folgende für die Registrierung benutzen: function registerObjectEventHandler(element, eventtype, listener, captures) { element.addEventListener(eventtype, function(event) { listener.handleEvent(event); } captures); }
Mit dieser Funktion kann jedes Objekt als Event-Listener registriert werden, sofern es eine Methode namens handleEvent( ) definiert. Diese Methode wird als eine Methode des Listener-Objekts aufgerufen. Das Schlüsselwort this verweist dann auf das ListenerObjekt, nicht auf das Dokumentelement, das das Event ausgelöst hat. Über die DOM-Spezifikation hinausgehend erlaubt Firefox (und andere Browser, die auf dem Mozilla-Code aufbauen), dass Event-Listener-Objekte, die eine handleEvent( )Methode definieren, anstelle einer Funktionsreferenz direkt an addEvent-Listener( ) übergeben werden können. Für diese Browser ist keine spezielle Registrierungsfunktion wie die gerade gezeigte notwendig.
17.2 Fortgeschrittenes Event-Handling mit dem DOM Level 2 |
445
clientseitiges JavaScript
Trotz der fehlenden Standardisierung rufen alle bekannten Implementierungen die über addEventListener( ) registrierten Handler so auf, als wären sie Methoden des Zielelements. Wenn der Handler aufgerufen wird, bezieht sich das this-Schlüsselwort also auf das Objekt, auf dem der Handler registriert wurde. Wenn Sie sich lieber nicht auf dieses nicht festgeschriebene Verhalten verlassen wollen, können Sie die currentTarget-Eigenschaft des Event-Objekts verwenden, das an Ihre Handler-Funktionen übergeben wird. Bei der Besprechung des Event-Objekts weiter unten in diesem Kapitel sehen Sie, dass sich die currentTarget-Eigenschaft auf das Objekt bezieht, auf dem der Event-Handler registriert wurde.
491-0.book Seite 446 Mittwoch, 4. April 2007 9:55 09
e-bol.net
17.2.5 Module und Typen von Events Wie ich zuvor angemerkt habe, ist das Level 2 DOM modular aufgebaut, sodass eine Implementierung es in Teilen unterstützen kann, andere Teile aber nicht zu unterstützen braucht. Die Events-API ist ein solches Modul. Ob ein Browser dieses Modul unterstützt, können Sie mit der folgenden Programmzeile feststellen: document.implementation.hasFeature("Events", "2.0")
Das Events-Modul enthält jedoch nur die API für die grundlegende Infrastruktur zum Event-Handling. Die Unterstützung bestimmter Arten von Events ist in Untermodule ausgelagert. Jedes Untermodul unterstützt jeweils eine Gruppe miteinander verwandter Arten von Events und definiert einen an Event-Handler übergebenen Event-Typ für jede Art von Event. Beispielsweise stellt das Untermodul mit dem Namen MouseEvents eine Unterstützung für die Event-Typen mousedown, mouseup, click usw. bereit. Es definiert außerdem das MouseEvent-Interface. Für jeden von diesem Modul unterstützten EventTyp wird ein Objekt, das dieses Interface implementiert, an die Handler-Funktion übergeben. Tabelle 17-2 führt die einzelnen Event-Module, die von ihnen definierten Event-Interfaces sowie die unterstützten Event-Typen auf. Beachten Sie, dass das Level 2 DOM keine Typen von Tastatur-Events standardisiert, sodass hier keine Module für TastaturEvents aufgeführt werden. Die derzeitigen Browser unterstützen allerdings TastenEvents, über die Sie später in diesem Kapitel mehr erfahren. Tabelle 17-2 und der Rest des Buches übergehen die Beschreibung der MutationEvents-Module. Mutation-Events werden ausgelöst, wenn die Struktur eines Dokuments verändert wird. Für Anwendungen wie z.B. HTML-Editoren sind sie nützlich, sie werden aber im Allgemeinen von Webbrowsern nicht implementiert und von Webprogrammierern nicht verwendet. Tabelle 17-2: Event-Module, Interfaces und Typen Modulname
Wie Sie in Tabelle 17-2 sehen können, definieren die Module HTMLEvents und MouseEvents Event-Typen, die uns aus dem Event-Modul des Level 0 vertraut sind. Das Modul UIEvents definiert Event-Typen, die den von HTML-Formularelementen unterstützten Events focus, blur und click ähneln. Sie sind jedoch insofern verallgemeinert, als dass sie von beliebigen Dokumentelementen erzeugt werden können, die den Eingabefokus erhalten oder in anderer Weise aktiviert werden können.
446 | Kapitel 17: Events und Event-Handling
491-0.book Seite 447 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Es ist hilfreich, Tabelle 17-3 mit Tabelle 17-1 zu vergleichen, wo alle von HTML 4 definierten Event-Handler des Level 0 aufgeführt sind. Die von den beiden Modellen unterstützten Event-Typen entsprechen sich weitgehend (abgesehen vom UIEvents-Modul). Der DOM Level 2 Standard unterstützt zusätzlich die Event-Typen abort, error, resize und scroll, die von HTML 4 nicht standardisiert wurden; aber er unterstützt die im HTML 4-Standard definierten Tasten- und dblclick-Eventtypen nicht. (Wie Sie bald sehen werden, gibt die Eigenschaft detail des an einen click-Event-Handler übergebenen Objekts die Anzahl der aufgetretenen Klicks an.) Tabelle 17-3: Event-Typen Event-Typ
17.2 Fortgeschrittenes Event-Handling mit dem DOM Level 2 |
447
clientseitiges JavaScript
Wie bereits gesagt, wird beim Eintreten eines Events seinem Handler ein Objekt übergeben, das das mit diesem Event-Typ assoziierte Event-Interface implementiert. Die Eigenschaften dieses Objekts enthalten für den Handler nützliche Informationen über das Event. Tabelle 17-3 führt die Standard-Events erneut auf. Dort sind sie nach dem EventTyp statt nach dem Modul sortiert. Für jeden Event-Typ gibt die Tabelle die Art des an den Handler übergebenen Event-Objekts an. Außerdem wird angegeben, ob der EventTyp die Dokument-Hierarchie im Zuge der Event-Propagation aufsteigt (die Spalte »B« steht für »bubbling«) und ob das Event eine voreingestellte Aktion besitzt, deren Aufruf mit der Methode preventDefault( ) verhindert werden kann (die Spalte »C« steht für »cancel«). Für Events des Moduls HTMLEvents gibt die fünfte Spalte an, welche HTMLElemente das Event erzeugen können. Für alle anderen Event-Typen gibt die fünfte Spalte an, welche Eigenschaften des Event-Objekts sinnvolle Informationen über das Event enthalten (diese Eigenschaften werden im nächsten Abschnitt beschrieben). Beachten Sie, dass unter den in dieser Spalte aufgeführten Eigenschaften nicht die Eigenschaften zu finden sind, die vom grundlegenden Interface Event definiert werden. Diese enthalten sinnvolle Werte für alle Event-Typen.
491-0.book Seite 448 Mittwoch, 4. April 2007 9:55 09
17.2.6 Event-Interfaces und Event-Informationen Wenn ein Event eintritt, stellt die API des DOM Level 2 zusätzliche Informationen über das Event (beispielsweise, wann und wo das Event eintrat) als Eigenschaften eines an den Event-Handler übergebenen Objekts bereit. Jedes Event-Modul besitzt ein mit ihm assoziiertes Event-Interface, das für den jeweiligen Event-Typ genauere Informationen angibt. Tabelle 17-2 führte drei verschiedene Event-Module und drei verschiedene Event-Interfaces auf. Diese drei Interfaces hängen tatsächlich miteinander zusammen und bilden eine Hierarchie. An der Wurzel befindet sich als grundlegendes Event-Interface das Interface Event, das von allen Event-Objekten implementiert wird. UIEvent ist ein Unterinterface von Event: Jedes Event-Objekt, das UIEvent implementiert, implementiert auch alle Methoden und Eigenschaften von Event. Das Event-Interface Mouse ist ein Unterinterface von UIEvent. Daher implementiert beispielsweise das Event-Objekt, das für ein MausklickEvent an einen Event-Handler übergeben wird, alle von den Interfaces MouseEvent, UIEvent und Event definierten Methoden und Eigenschaften. Die folgenden Abschnitte beschreiben jedes einzelne Event-Interface und erläutern ihre wichtigsten Eigenschaften und Methoden. Teil IV enthält alle Einzelheiten über jedes Interface.
448 | Kapitel 17: Events und Event-Handling
491-0.book Seite 449 Mittwoch, 4. April 2007 9:55 09
e-bol.net 17.2.6.1 Event
type
Der Typ des eingetretenen Events. Der Wert dieser Eigenschaft ist der Name des Event-Typs; sein Wert ist derselbe String, der bei der Registrierung des Event-Handlers verwendet wurde (z.B. »click« oder »mouseover«). target
Der Knoten, an dem das Event eingetreten ist; dies muss nicht dasselbe sein wie currentTarget. currentTarget
Der Knoten, an dem das Event derzeit verarbeitet wird (d.h. der Knoten, dessen Event-Handler derzeit ausgeführt wird). Wenn das Event während des Abfangens oder Aufsteigens bei der Event-Propagation verarbeitet wird, unterscheidet sich der Wert dieser Eigenschaft vom Wert der Eigenschaft target. Wie bereits gesagt wurde, können Sie diese Eigenschaft anstelle des Schlüsselworts this in Ihren EventHandler-Funktionen verwenden. eventPhase
Diese Zahl gibt an, in welcher Phase der Event-Propagation wir uns derzeit befinden. Der Wert ist eine der Konstanten Event.CAPTURING_PHASE, Event.AT_TARGET oder Event.BUBBLING_PHASE. timeStamp
Dieses Date-Objekt gibt an, wann das Event aufgetreten ist. bubbles
Dieser Boolesche Wert gibt an, ob dieses Event (und Events dieses Typs) im Dokumentenbaum aufsteigen. cancelable
Dieser Boolesche Wert gibt an, ob mit dem Event eine vordefinierte Aktion verknüpft ist, deren Ausführung mit der Methode preventDefault( ) verhindert werden kann. Zusätzlich zu diesen sieben Eigenschaften definiert das Event-Interface zwei Methoden, die ebenfalls von allen Event-Objekten implementiert werden: stopPropagation( ) und preventDefault( ). Durch einen Aufruf von stopPropagation( ) kann ein Event-Handler verhindern, dass das Event über den Knoten, an dem es derzeit verarbeitet wird, weiterverbreitet wird. Durch einen Aufruf von preventDefault( ) kann ein Event-Handler den
17.2 Fortgeschrittenes Event-Handling mit dem DOM Level 2 |
449
clientseitiges JavaScript
Die vom Modul HTMLEvents definierten Event-Typen verwenden das Interface Event. Alle anderen Event-Typen verwenden Unterinterfaces dieses Interfaces, sodass Event von allen Event-Objekten implementiert wird und Informationen für alle Event-Typen bereitstellt. Das Event-Interface definiert die folgenden Eigenschaften (beachten Sie, dass diese Eigenschaften und die Eigenschaften aller Unterinterfaces von Event nur gelesen werden können):
491-0.book Seite 450 Mittwoch, 4. April 2007 9:55 09
e-bol.net Browser daran hindern, eine mit dem Event assoziierte vordefinierte Aktion auszuführen. Ein Aufruf von preventDefault( ) in der API des DOM Level 2 entspricht der Rückgabe des Werts false im Event-Modell des Level 0.
17.2.6.2 UIEvent Das Interface UIEvent ist ein Unterinterface von Event. Es definiert den Typ von EventObjekten, die an Events der Typen DOMFocusIn, DOMFocusOut und DOMActivate übergeben werden. Diese Event-Typen werden selten verwendet; das UIEvent-Interface ist insbesondere deshalb wichtig, weil es das Eltern-Interface von MouseEvent ist. UIEvent definiert zusätzlich zu den von Event definierten Eigenschaften zwei weitere: view
Das Window-Objekt (in der DOM-Terminologie als »view« bezeichnet), in dem das Event eingetreten ist. detail
Eine Zahl, die zusätzliche Informationen über das Event bereitstellen kann. Bei click- sowie mousedown- und mouseup-Events gibt dieses Feld die Anzahl der Klicks an: 1 bei einem einfachen Mausklick, 2 bei einem Doppelklick und 3 bei einem Dreifachklick. (Beachten Sie, dass jeder Klick ein Event erzeugt; wenn aber Mehrfachklicks schnell genug aufeinanderfolgen, zeigt der Wert detail dies an. Einem Maus-Event, dessen Eigenschaft detail den Wert 2 enthält, geht immer ein MausEvent voraus, dessen Eigenschaft detail den Wert 1 enthält). Bei DOMActivateEvents enthält dieses Feld den Wert 1 bei normaler Aktivierung und den Wert 2 bei einer Hyperaktivierung wie einem Doppelklick oder einer Umschalt-Eingabe-Kombination (Shift-Enter).
17.2.6.3 MouseEvent Das Interface MouseEvent erbt die Eigenschaften und Methoden von Event und UIEvent und definiert die folgenden zusätzlichen Eigenschaften: button
Eine Zahl, die angibt, welche Maustaste während eines mousedown-, mouseup- oder click-Events ihren Zustand geändert hat. Der Wert 0 verweist auf die linke Taste, 1 auf die mittlere und 2 auf die rechte. Diese Eigenschaft wird nur verwendet, wenn eine Maustaste ihren Zustand ändert; sie wird nicht verwendet, wenn beispielsweise eine Taste während eines mousemove-Events gedrückt gehalten wird. Beachten Sie außerdem, dass Netscape 6 hier abweichend vom Standard die Werte 1, 2 und 3 anstelle von 0, 1 und 2 verwendet. Dieses Problem ist in Netscape 6.1 behoben. altKey, ctrlKey, metaKey, shiftKey Diese vier Booleschen Felder zeigen an, ob die Tasten Alt, Strg (Ctrl), Meta oder Umschalt (Shift) bei Eintreten eines Maus-Events gedrückt waren. Im Gegensatz zur Eigenschaft button enthalten diese Tasten-Eigenschaften für jeden Typ von MausEvent einen gültigen Wert.
450 | Kapitel 17: Events und Event-Handling
491-0.book Seite 451 Mittwoch, 4. April 2007 9:55 09
e-bol.net clientX, clientY
screenX, screenY
Diese beiden Eigenschaften geben die X- und Y-Koordinaten des Mauszeigers relativ zur oberen linken Ecke des Bildschirms an. Diese Werte sind nützlich, wenn Sie ein neues Browserfenster an der Stelle des Maus-Events oder in dessen Nähe öffnen möchten. relatedTarget
Diese Eigenschaft verweist auf einen Knoten, der mit dem Zielknoten des Events zusammenhängt. Bei mouseover-Events ist dies der Knoten, den die Maus verlassen hat, als sie über den neuen Zielknoten bewegt wurde. Bei mouseout-Events ist es der Knoten, zu dem die Maus bewegt wurde, als sie den Zielknoten verlassen hat. Bei anderen Eventtypen wird sie nicht verwendet.
17.2.7 Mischen von Event-Modellen Bislang habe ich das traditionelle Event-Modell des Level 0 und das neue des Standards DOM Level 2 vorgestellt. Um abwärtskompatibel zu sein, unterstützen Browser, die das Modell des Level 2 unterstützen, auch weiterhin das Event-Modell des Level 0. Das bedeutet, Sie können Event-Modelle innerhalb eines Dokuments mischen. Sie sollten wissen, dass Webbrowser, die das Event-Modell des Level 2 unterstützen, immer ein Event-Objekt an die Event-Handler übergeben – auch wenn die Handler durch Angabe eines HTML-Attributs oder einer JavaScript-Eigenschaft mit dem Modell des Level 0 registriert wurden. Wenn ein Event-Handler mit einem HTML-Attribut definiert wurde, wird er implizit in eine Funktion umgewandelt, die ein Argument namens event entgegennimmt. Ein solcher Event-Handler kann daher den Bezeichner event verwenden, um auf das Event-Objekt zuzugreifen. (Später werden Sie sehen, dass die Verwendung des event-Bezeichners in einem HTML-Attribut auch mit dem IE-Event-Modell kompatibel ist). Der Standard erkennt an, dass das Event-Modell des Level 0 auch weiterhin verwendet wird. Er legt daher fest, dass Implementierungen, die das Modell des Level 0 unterstützen, nach diesem Modell registrierte Handler behandeln, als wären sie mit der Funktion addEventListener( ) registriert worden. Wenn Sie also der Eigenschaft onclick eines
17.2 Fortgeschrittenes Event-Handling mit dem DOM Level 2 |
451
clientseitiges JavaScript
Diese beiden Eigenschaften geben die X- und Y-Koordinaten des Mauszeigers relativ zur Anzeigefläche bzw. zum Browserfenster an. Beachten Sie, dass diese Koordinaten das Scrollen eines Dokuments nicht berücksichtigen: Wenn ein Event am oberen Rand des Fensters eintritt, ist der Wert von clientY immer 0, wie weit auch immer das Dokument im Fenster gescrollt wurde. Leider bietet das Level 2-DOM keine standardisierte Möglichkeit, diese Fensterkoordinaten in Dokumentkoordinaten umzuwandeln. In Browsern außer IE können Sie window.pageXOffset und window.pageYOffset hinzufügen. (Abschnitt 14.3.1 enthält Einzelheiten dazu).
491-0.book Seite 452 Mittwoch, 4. April 2007 9:55 09
e-bol.net Dokumentelements e eine Funktion f zuweisen (oder dem entsprechenden HTML-Attribut onclick), ist dies äquivalent zur Registrierung dieser Funktion in der folgenden Weise: e.addEventListener("click", f, false);
Wenn f( ) aufgerufen wird, wird der Funktion ein Event-Objekt als Argument übergeben, auch wenn sie mit dem Modell des Level 0 registriert wurde.
17.3 Das Event-Modell des Internet Explorers Das von den Browsern Internet Explorer 4, 5, 5.5 und 6 unterstützte Event-Modell stellt eine Zwischenstufe zwischen dem ursprünglichen Modell des Level 0 und dem standardisierten Modell des DOM Level 2 dar. Das Event-Modell des IE besitzt ein Event-Objekt, das nähere Informationen über eingetretene Events bereitstellt. Die Übergabe des EventObjekts an Event-Handler-Funktionen scheint zwar zumindest in einigen Fällen als Kopie stattzufinden, ist aber schlecht dokumentiert.6 Traditionell wird das Event-Objekt in IE stattdessen als eine Eigenschaft des Window-Objekts verfügbar gemacht. Das Modell des IE unterstützt Event-Propagation durch Aufsteigen, nicht aber durch Abfangen, wie das DOM-Modell dies tut (obwohl IE 5 und höhere Versionen eine spezielle Funktionalität haben, um Maus-Events abzufangen). In IE 4 werden Event-Handler in der gleichen Weise registriert wie im ursprünglichen Modell des Level 0. In IE 5 und neueren Versionen dagegen können mehrere Handler mit speziellen (aber nicht standardisierten) Registrierungsfunktionen registriert werden. Die folgenden Abschnitte geben genauere Auskunft über dieses Event-Modell und vergleichen es mit dem ursprünglichen Event-Modell des Level 0 und dem standardisierten Event-Modell des Level 2. Sie sollten diese beiden Event-Modelle verstanden haben, bevor Sie den folgenden Abschnitt lesen.
17.3.1 Das Event-Objekt des IE Wie das standardisierte Event-Modell des DOM Level 2 stellt auch das Event-Modell des IE Informationen über alle eingetretenen Events in den Eigenschaften eines EventObjekts bereit. Die im Standardmodell definierten Event-Objekte wurden tatsächlich dem Event-Objekt des IE nachgebildet, sodass Sie eine Vielzahl von Ähnlichkeiten zwischen den Eigenschaften des Event-Objekts des IE und den Eigenschaften der Objekte Event, UIEvent und MouseEvent des DOM bemerken werden.
6 Siehe hierzu David’s Blog unter http://www.davidflanagan.com/blog/2006_10.html.
452 | Kapitel 17: Events und Event-Handling
491-0.book Seite 453 Mittwoch, 4. April 2007 9:55 09
e-bol.net Die wichtigsten Eigenschaften des Event-Objekts des IE sind: type
srcElement
Das Dokumentelement, an dem das Event eingetreten ist. Diese Eigenschaft ist kompatibel zur target-Eigenschaft des Event-Objekts des DOM. button
Eine ganze Zahl, die die gedrückte Maustaste angibt. Der Wert 1 bezeichnet die linke Taste, 2 die rechte und 4 die mittlere. Wenn mehrere Tasten gedrückt wurden, werden diese Werte addiert, sodass diese Eigenschaft beispielsweise den Wert 3 besitzt, wenn die linke und die rechte Maustaste gedrückt wurden. Vergleichen Sie dies mit der button-Eigenschaft des MouseEvent-Objekts im DOM Level 2, wo derselbe Name für die Eigenschaft verwendet wird, die Interpretation der Eigenschaftswerte sich jedoch unterscheidet. clientX, clientY Diese ganzzahligen Eigenschaften geben die Mauskoordinaten (relativ zur oberen linken Ecke des umgebenden Fensters) zum Zeitpunkt des Events an. Diese Eigenschaften sind zu den gleichnamigen MouseEvent-Eigenschaften des DOM Level 2 kompatibel. Beachten Sie, dass bei Dokumenten, die größer als das Fenster sind, diese Koordinaten nicht der Position im Dokument entsprechen. Um die Fensterkoordinaten zu Dokumentkoordinaten zu konvertieren, müssen Sie den Betrag hinzufügen, um den das Dokument gescrollt wurde. In Abschnitt 14.3.1 wird gezeigt, wie das gemacht wird. offsetX, offsetY Diese ganzzahligen Eigenschaften geben die Position des Mauszeigers relativ zum Quellenelement an. Mit ihnen können Sie beispielsweise feststellen, auf welche Pixel eines Image-Objekts geklickt wurde. Diese Eigenschaften besitzen im Event-Modell des DOM keine Entsprechung. altKey, ctrlKey, shiftKey Diese Booleschen Eigenschaften geben an, ob die Tasten Alt, Strg (Ctrl) oder Umschalt (Shift) gedrückt waren, als das Event eintrat. Diese Eigenschaften sind zu den gleichnamigen Eigenschaften des MouseEvent-Objekts im DOM kompatibel. Beachten Sie jedoch, dass das Event-Objekt des IE keine Eigenschaft metaKey besitzt. keyCode
Diese ganzzahlige Eigenschaft gibt den Tastaturcode bei keydown- und keyup-Events bzw. das Unicode-Zeichen bei keypress-Events an. Mit der Methode String. fromCharCode( ) können Sie die Zeichencodes in Strings umwandeln. Tasten-Events werden weiter unten in diesem Kapitel ausführlicher beschrieben.
17.3 Das Event-Modell des Internet Explorers |
453
clientseitiges JavaScript
Ein String, der den Typ des eingetretenen Events angibt. Der Wert dieser Eigenschaft ist der Name des Event-Handlers ohne die Vorsilbe »on« (z.B. »click« oder »mouseover«). Diese Eigenschaft ist kompatibel zur type-Eigenschaft des EventObjekts des DOM.
491-0.book Seite 454 Mittwoch, 4. April 2007 9:55 09
e-bol.net fromElement, toElement fromElement gibt bei mouseover-Events das Dokumentelement an, über dem die Maus sich zuvor befand. toElement gibt bei mouseout-Events das Dokumentelement an, über dem sich die Maus anschließend befindet. Dies ist mit der Eigenschaft relatedTarget des MouseEvent-Objekts im DOM vergleichbar. cancelBubble
Diese Boolesche Eigenschaft verhindert, dass das aktuelle Event die Hierarchie der umgebenden Objekte weiter hinaufsteigt, wenn ihr der Wert true zugewiesen wird. Sie ist mit der Methode stopPropagation( ) des Event-Objekts im DOM vergleichbar. returnValue
Eine Boolesche Eigenschaft, der der Wert false zugewiesen werden kann, um den Browser an der Ausführung der vordefinierten Aktion zu hindern, die mit dem Event verbunden ist. Dies ist eine Alternative zur traditionellen Technik, bei der der Event-Handler den Wert false zurückgibt. Sie ist mit der preventDefault( )Methode des Event-Objekts im DOM vergleichbar. Eine vollständige Dokumentation des Event-Objekts in IE finden Sie in Teil IV.
17.3.2 Das Event-Objekt des IE als globale Variable Obwohl das Event-Modell des IE Informationen über das Event in einem Event-Objekt bereitstellt, gibt der IE Event-Objekte nur an Handler weiter, die mit der nicht-standardisierten Methode attachEvent() registriert sind (siehe den folgenden Abschnitt »Registrierung von Event-Handlern im IE«). Andere Event-Handler werden ohne Argumente aufgerufen. Anstatt das Event-Objekt als Argument an den Handler weiterzureichen, stellt IE es als die Eigenschaft event des globalen Window-Objekts zur Verfügung. Daher kann eine Funktion zum Event-Handling in IE auf dieses Event-Objekt als window.event oder einfach als event zugreifen. Wenn es auch merkwürdig erscheint, eine globale Variable anstelle eines Funktionsarguments zu verwenden, funktioniert das Schema des IE, da das Event-gesteuerte Programmiermodell implizit davon ausgeht, dass zu jedem Zeitpunkt immer nur ein Event verarbeitet werden muss. Da zwei Events niemals gleichzeitig behandelt werden, kann eine globale Variable für die Speicherung der Informationen über das aktuell zu verarbeitende Event verwendet werden. Die Tatsache, dass das Event-Objekt als globale Variable implementiert ist, unterscheidet IE vom standardisierten Event-Modell des DOM Level 2. Mit einer einzelnen Programmzeile kann man diese Inkompatibilität jedoch beseitigen. Wenn Sie eine Event-HandlerFunktion schreiben möchten, die mit beiden Event-Modellen funktioniert, schreiben Sie die Funktion derart, dass sie ein Argument entgegennimmt, und initialisieren das Argument mit der globalen Variablen, falls kein Argument übergeben wurde. Beispielsweise: function portableEventHandler(e) { if (!e) e = window.event; // Beschaffe in IE Informationen über das Event // Hier folgt der Body des Event-Handlers }
454 | Kapitel 17: Events und Event-Handling
491-0.book Seite 455 Mittwoch, 4. April 2007 9:55 09
e-bol.net Ein weiterer üblicher Ausdruck, dem Sie vielleicht begegnen werden, verwendet das Zeichen || zur Rückgabe seines ersten definierten Arguments: function portableEventHandler(event) { var e = event || window.event; // der Body des Event-Handlers steht hier }
In IE 4 werden Event-Handler in der gleichen Weise wie im ursprünglichen Event-Modell des Level 0 registriert: indem sie als HTML-Attribute angegeben werden oder indem den Event-Handler-Eigenschaften der Dokumentelemente Funktionen zugewiesen werden. Seit IE 5 gibt es die Methoden attachEvent( ) und detachEvent( ), mit denen mehrere Handler-Funktionen für einen gegebenen Event-Typ bei einem gegebenen Objekt registriert werden können. Ein mit attachEvent() registrierter Event-Handler wird mit einer Kopie des globalen window.event-Event-Objekts aufgerufen. Sie können mit attachEvent( ) einen Event-Handler folgendermaßen registrieren: function hervorheben( ) { /* Hier folgt der Code des Event-Handlers */ } document.getElementById("meinEl").attachEvent("onmouseover", hervorheben);
Die
Methoden attachEvent( ) und detachEvent( ) funktionieren genau addEventListener( ) und removeEventListener( ), mit den folgenden Ausnahmen:
wie
• Da das Event-Modell des IE das Abfangen von Events nicht unterstützt, erwarten attachEvent( ) und detachEvent( ) nur zwei Argumente: den Event-Typ und die Handler-Funktion. • Die an die IE-Methode übergebenen Namen der Event-Handler sollten das Präfix »on« enthalten. Verwenden Sie zum Beispiel »onclick« mit attachEvent( ) statt »click« mit addEventListener( ). • Funktionen, die mit attachEvent( ) registriert sind, werden als globale Funktionen aufgerufen und nicht als Methoden des Dokumentelements, an dem das Event aufgetreten ist. Wenn also ein mit attachEvent( ) registrierter Event-Handler ausgeführt wird, verweist das this-Schlüsselwort nicht auf das Zielelement des Events, sondern auf das Window-Objekt. • Mit attachEvent( ) kann die gleiche Event-Handler-Funktion mehrfach registriert werden. Wenn ein Event des angegebenen Typs stattfindet, wird die registrierte Funktion so oft aufgerufen, wie sie registriert wurde.
17.3.4 Event-Bubbling im IE Das Event-Modell des IE kennt im Gegensatz zu dem des DOM Level 2 das Konzept des Capturing von Events nicht. Allerdings steigen Events die Hierarchie der umgebenden Elemente im Modell des IE genau wie in dem Modell des Level 2 hinauf. Wie im Modell
17.3 Das Event-Modell des Internet Explorers |
455
clientseitiges JavaScript
17.3.3 Registrierung von Event-Handlern im IE
491-0.book Seite 456 Mittwoch, 4. April 2007 9:55 09
e-bol.net des Level 2 steigen nur »rohe« Eingabe-Events auf (in erster Linie Maus- und TastaturEvents), nicht aber höhere semantische Events. Der Hauptunterschied zwischen dem Bubbling von Events in den Event-Modellen des IE und des DOM Level 2 besteht in der Art, wie das Bubbling abgebrochen wird. Das Event-Objekt des IE besitzt im Gegensatz zu dem des DOM Level 2 keine Methode stopPropagation( ). Um zu verhindern, dass ein Event aufsteigt bzw. dass es über den aktuellen Knoten in der Hierarchie weiter aufsteigt, muss ein Event-Handler in IE der Eigenschaft cancelBubble des Event-Objekts den Wert true zuweisen: window.event.cancelBubble = true;
Beachten Sie, dass die Zuweisung an cancelBubble sich nur auf das aktuelle Event bezieht. Wenn ein neues Event erzeugt wird, wird window.event ein neues Event-Objekt und cancelBubble der voreingestellte Wert false zugewiesen.
17.3.5 Abfangen von Maus-Events Um eine beliebige Benutzerschnittstelle zu implementieren, in der die Maus gezogen werden soll (wie z.B. bei Pulldown-Menüs oder Drag-and-drop), ist es wichtig, dass MausEvents abgefangen werden können, damit das Ziehen der Maus richtig durchgeführt werden kann, unabhängig davon, über was der Benutzer hinwegzieht. Im Event-Modell des DOM kann das durch das Abfangen des Event-Handlers erreicht werden. In IE 5 und höher wird das mit den Methoden setCapture( ) und releaseCapture( ) erreicht. Die Methoden setCapture( ) und releaseCapture( ) sind bei allen HTML-Elementen vorhanden. Beim Aufruf von setCapture( ) auf einem Element werden alle anschließenden Maus-Events an dieses Element geleitet. Der Handler dieses Elements kann die Events bearbeiten, bevor sie aufsteigen. Beachten Sie, dass dies nur für Maus-Events zutrifft und auf alle Events, die mit der Maus zu tun haben: mousedown, mouseup, mousemove, mouseover, mouseout, click und dblclick. Beim Aufruf von setCapture( ) werden Maus-Events auf spezielle Weise weitergeleitet, bis Sie releaseCapture( ) aufrufen oder bis das Abfangen unterbrochen wird. Das Abfangen der Maus wird z.B. unterbrochen, wenn Ihr Webbrowser den Fokus verliert, ein alert( )-Dialog erscheint oder ein Systemmenü angezeigt wird. Tritt eine dieser Situationen ein, erhält das Element, an dem setCapture( ) aufgerufen wurde, ein onlosecapture-Event, um es darauf hinzuweisen, dass es keine weiteren abgefangenen Maus-Events mehr erhält. Im üblichsten Szenario wird setCapture( ) als Antwort auf ein mousedown-Event aufgerufen, womit sichergestellt wird, dass nachfolgende mousemove-Events vom gleichen Element empfangen werden. Das Element führt seinen Ziehvorgang als Antwort auf mousemove-Events aus und ruft releaseCapture( ) als Antwort auf ein (abgefangenes) mouseup-Event auf. Beispiel 17-4 verwendet setCapture( ) und releaseCapture( ).
456 | Kapitel 17: Events und Event-Handling
491-0.book Seite 457 Mittwoch, 4. April 2007 9:55 09
e-bol.net
17.3.6 attachEvent( ) und das Schlüsselwort this
Wenn Sie einen generischen Event-Handler schreiben wollen, der auf einem beliebigen Element registriert werden kann, und dieser Handler wissen muss, auf welchem Event er registeriert ist, können Sie attachEvent( ) nicht zur Handler-Registrierung verwenden. Sie müssen den Handler entweder über das Level 0-Event-Modell registrieren oder eine Wrapperfunktion um den Handler definieren und diese Wrapperfunktion registrieren: // Hier sind ein Event-Handler und ein Element, an dem wir ihn registrieren wollen function generischerHandler( ) { /* Code, der this verwendet */ } var element = document.getElementById("meinelement"); // Wir können diesen Handler mit der Level 0 API registrieren element.onmouseover = generischerHandler; // Oder wir können einen Wrapper verwenden element.attachEvent("onmouseover", function( ) { // Handler als Methode des Elements aufrufen generischerHandler.call(element, event); });
Das Problem mit der Level 0 API ist, dass sie keine Registrierung mehrfacher Handlerfunktionen ermöglicht. Das Problem bei der Verwendung von Wrappern ist, dass sie in IE zu Speicherlecks führen. Im nächsten Abschnitt gibt es Details dazu.
17.3.7 Event-Handler und Speicherlecks Wie in Abschnitt 8.8.4.2 bereits gesagt wurde, ist Internet Explorer (bis Version 6, in Version 7 scheint das Problem behoben zu sein) anfällig für eine Klasse von Speicherlecks, die auftreten können, wenn Sie eingebettete Funktionen als Event-Handler verwenden. Sehen Sie sich den folgenden Code an: // Einen Validierungs-Event-Handler zu einem Formular hinzufügen function addValidationHandler(formular) { formular.attachEvent("onsubmit", function( ) { return validate( ); }); }
Wenn diese Funktion aufgerufen wird, versieht sie das angegebene Formularelement mit einem Event-Handler. Der Handler wird als eingebettete Funktion definiert. Obwohl die Funktion selbst nicht auf irgendwelche Formularelemente verweist, tut das ihr Geltungs-
17.3 Das Event-Modell des Internet Explorers |
457
clientseitiges JavaScript
Wie bereits erwähnt, werden Event-Handler, die mit attachEvent( ) registriert sind, als globale Funktionen aufgerufen und nicht als Methoden des Elements, an dem sie registriert sind. Das bedeutet, dass sich das Schlüsselwort this auf das globale WindowObjekt bezieht. An sich ist das kein großes Problem. Es wird allerdings dadurch verschlimmert, dass das Event-Objekt von IE keine Eigenschaft hat, die der currentTargetEigenschaft von DOM entspricht. srcElement gibt das Element an, das das Event erzeugte, aber wenn das Event inzwischen aufgestiegen ist, ist das Element eventuell nicht mehr das, das das Event bearbeitet.
491-0.book Seite 458 Mittwoch, 4. April 2007 9:55 09
e-bol.net bereich, der als Teil des Wrappers mit einbezogen wird. Im Ergebnis verweist ein Formularelement auf ein JavaScript-Funktionsobjekt, und dieses Objekt (über seine Geltungsbereichskette) verweist zurück auf das Formularobjekt. Das ist die Art zirkuläre Referenz, die Speicherlecks in IE verursacht. Eine Lösung dieses Problem ist, eingebettete Funktionen vollkommen zu vermeiden, wenn man für IE programmiert. Eine andere Lösung besteht darin, sorgfältig alle EventHandler als Antwort auf ein onunload( )-Event zu entfernen. Der im nächsten Abschnitt gezeigte Code geht die zweite Route.
17.3.8 Beispiel: Event-Modell-Kompatibilität für IE Dieser Abschnitt hat eine Anzahl von Inkompatibilitäten zwischen dem IE-Event-Modell und dem standardisierten DOM Level 2-Modell aufgezeigt. Beispiel 17-2 ist ein CodeModul, das viele dieser Inkompatibilitäten löst. Es definiert zwei Funktionen, Handler.add( ) und Handler.remove( ), zum Hinzufügen und Entfernen von Event-Handlern an einem angegebenen Element. Auf Plattformen, die addEventListener( ) unterstützen, sind diese Funktionen triviale Wrapper um diese Standardmethoden. Unter IE 5 und höher definiert Beispiel 17-2 diese Methoden aber so, dass sie die folgenden Inkompatibilitäten beseitigen: • Event-Handler werden als Methoden des Elements aufgerufen, an dem sie registriert sind. • Event-Handlern wird ein simuliertes Event-Objekt übergeben, das so weit wie möglich dem DOM-Standard-Event-Objekt gleicht. • Eine zweite Registrierung von Event-Handlern wird ignoriert. • Beim Entladen des Dokuments aus dem Browser werden alle Handler deregistriert, um Speicherlecks in IE zu verhindern. Um Event-Handler mit dem korrekten Wert des this-Schlüsselworts aufzurufen und ein simuliertes Event-Objekt zu übergeben, muss Beispiel 17-2 die angegebene HandlerFunktion in einer anderen Funktion verpacken, die sie richtig aufruft. Der schwierigste Teil dieses Beispiels ist der Code, der die an Handler.add( ) übergebene Handler-Funktion auf die Wrapper-Funktion abbildet, die tatsächlich mit attachEvent( ) registriert wird. Diese Abbildung muss aufrechterhalten werden, damit Handler.remove( ) die richtige Wrapper-Funktion entfernen kann und die Handler beim Entladen des Dokuments gelöscht werden können. Beispiel 17-2: Ein Event-Kompatibilitäts-Layer für IE /* * Handler.js -- Portable Event-Handler-Registrierungsfunktionen * * Dieses Modul definiert die Event-Handler-(De-)Registrierungsfunktionen * Handler.add( ) und Handler.remove( ). Beide Funktionen nehmen drei Argumente entgegen:
458 | Kapitel 17: Events und Event-Handling
491-0.book Seite 459 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-2: Ein Event-Kompatibilitäts-Layer für IE (Fortsetzung)
// In DOM-standardkonformen Browsern sind unsere Funktionen triviale Wrapper um // addEventListener( ) und removeEventListener( ). if (document.addEventListener) { Handler.add = function(element, eventType, handler) { element.addEventListener(eventType, handler, false); };
17.3 Das Event-Modell des Internet Explorers |
459
clientseitiges JavaScript
* Element: das DOM-Element, Dokument oder Fenster, für das der Handler * hinzugefügt oder entfernt werden soll. * * eventType: ein String, der den Event-Typ angibt, für den der * Handler aufgerufen werden soll. DOM-Standard-Typennamen verwenden, die * kein "on"-Präfix enthalten. Beispiele: "click", "load", "mouseover". * * Handler: Die aufzurufende Funktion, wenn ein Event des angegebenen Typs * am angegebenen Element auftritt. Diese Funktion wird als * Methode des Elements aufgerufen, an dem sie registriert wurde. * Das "this"-Schlüsselwort bezieht sich auf dieses Element. Der Handler-Funktion wird * ein Event-Objekt als einziges Argument übergeben. Dieses event-Objekt ist * entweder ein DOM-Standard-Event oder ein simuliertes Objekt. Wenn ein * simuliertes Event-Objekt übergeben wird, hat es die folgenden DOM* konformen Eigenschaften: type, target, currentTarget, relatedTarget, * eventPhase, clientX, clientY, screenX, screenY, altKey, ctrlKey, * shiftKey, charCode, stopPropagation( ) und preventDefault( ) * * Handler.add( ) und Handler.remove( ) haben keinen Rückgabewert. * * Handler.add( ) ignoriert eine zweite Registrierung des gleichen Handlers bei * Übereinstimmung von Event-Typ und -Element. Handler.remove( ) macht nichts, wenn sie zum * Entfernen eines Handlers aufgerufen wird, der nicht registriert ist. * * Implementierungshinweise: * * Bei Browsern, die die Event-Registrierungsfunktionen addEventListener( ) und * removeEventListener( ) des DOM-Standards unterstützen, rufen Handler.add( ) und * Handler.remove( ) einfach diese Funktionen auf und übergeben false als * drittes Argument (was bedeutet, dass die Event-Handler nie als * abfangende Event-Handler registriert sind). * * Versionen des Internet Explorers, die attachEvent( ) unterstützen, verwenden Handler.add( ) * und Handler.remove() die Funktionen attachEvent( ) und detachEvent( ). Um * die Handler-Funktion mit dem richtigen this-Schlüsselwort aufzurufen, wird ein Wrapper * verwendet. Da diese Art Wrapper in IE Speicherlecks verursachen, * registriert Handler.add( ) automatisch einen onunload-Handler, um * alle Event-Handler zu deregistrieren, wenn für die Seite entladen wird. Zum Verwalten * der registrierten Handler erzeugt Handler.add( ) eine Eigenschaft namens _allHandlers * am Window-Objekt und eine namens _handlers an jedem Element, auf * dem ein Handler registriert ist. */ var Handler = {};
491-0.book Seite 460 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-2: Ein Event-Kompatibilitäts-Layer für IE (Fortsetzung) Handler.remove = function(element, eventType, handler) { element.removeEventListener(eventType, handler, false); }; } // In IE 5 und neuer verwenden wir attachEvent( ) und detachEvent( ) mit einigen // Hacks, um sie addEventListener- und removeEventListener-kompatibel zu machen. else if (document.attachEvent) { Handler.add = function(element, eventType, handler) { // Erlaube keine mehrfachen Handler-Registrierungen // _find( ) ist eine private Utility-Funktion, die weiter unten definiert wird. if (Handler._find(element, eventType, handler) != -1) return; // Um die Handler-Funktion als Methode des Elements // aufzurufen, müssen wir diese eingebettete Funktion anstelle der Handler// Funktion selbst definieren und registrieren. var wrappedHandler = function(e) { if (!e) e = window.event; // Erzeuge ein synthetisches Event-Objekt mit teilweiser Kompatibilität // mit DOM-Events. var event = { _event: e, // Falls wir wirklich das Event-Objekt von IE möchten type: e.type, // Event-Typ target: e.srcElement, // Wo das Event stattfand currentTarget: element, // Wo wir es bearbeiten relatedTarget: e.fromElement?e.fromElement:e.toElement, eventPhase: (e.srcElement==element)?2:3, // Mauskoordinaten clientX: e.clientX, clientY: e.clientY, screenX: e.screenX, screenY: e.screenY, // Tasten-Status altKey: e.altKey, ctrlKey: e.ctrlKey, shiftKey: e.shiftKey, charCode: e.keyCode, // Event-Management-Funktionen stopPropagation: function( ) {this._event.cancelBubble = true;}, preventDefault: function( ) {this._event.returnValue = false;} } // // // if
Rufe die Handler-Funktion als Methode des Elements auf und übergib das synthetische Event-Objekt als einziges Argument. Verwende Function.call( ), sofern sie definiert ist; ansonsten einen Hack (Function.prototype.call) handler.call(element, event); else { // Wenn Function.call nicht vorhanden ist, dann täusche sie wie folgt vor. element._currentHandler = handler; element._currentHandler(event);
460 | Kapitel 17: Events und Event-Handling
491-0.book Seite 461 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-2: Ein Event-Kompatibilitäts-Layer für IE (Fortsetzung) element._currentHandler = null; } };
// // // //
clientseitiges JavaScript
// Registriere jetzt diese eingebettete Funktion als unseren Event-Handler. element.attachEvent("on" + eventType, wrappedHandler); Jetzt müssen wir uns merken, dass die vom Benutzer angegebene Handler-Funktion zu der sie aufrufenden eingebetteten Funktion gehört. Das ist für die Deregistrierung des Handlers über die remove( )-Methode und beim Seitenentladen notwendig.
// Speichere alle Informationen über diesen Handler in einem Objekt. var h = { element: element, eventType: eventType, handler: handler, wrappedHandler: wrappedHandler }; // Stelle fest, zu welchem Dokument dieser Handler gehört. // Wenn das Element keine document-Eigenschaft enthält, ist es // kein Window- oder Document-Element. Also muss es das Document// Objekt selbst sein. var d = element.document || element; // Hole jetzt das Fenster, das zu diesem Dokument gehört. var w = d.parentWindow; // Wir müssen diesen Handler mit dem Fenster assoziieren, // damit wir es entfernen können, wenn das Fenster entladen wird. var id = Handler._uid( ); // Eindeutigen Eigenschaftsnamen erzeugen if (!w._allHandlers) w._allHandlers = {}; // Erzeuge ein Objekt, falls nötig w._allHandlers[id] = h; // Speichere die Handler-Informationen in diesem Objekt // id der Handler-Informationen ebenfalls mit diesem Element assoziieren. if (!element._handlers) element._handlers = []; element._handlers.push(id); // Sofern kein onunload-Handler mit dem Fenster assoziiert ist, // registriere jetzt einen. if (!w._onunloadHandlerRegistered) { w._onunloadHandlerRegistered = true; w.attachEvent("onunload", Handler._removeAllHandlers); } }; Handler.remove = function(element, eventType, handler) { // Suche diesen Handler im element._handlers[]-Array. var i = Handler._find(element, eventType, handler); if (i == -1) return; // Wenn der Handler nicht registriert ist, dann mache nichts
17.3 Das Event-Modell des Internet Explorers |
461
491-0.book Seite 462 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-2: Ein Event-Kompatibilitäts-Layer für IE (Fortsetzung) // Hole das Fenster dieses Elements. var d = element.document || element; var w = d.parentWindow; // Suche die eindeutige id dieses Handlers. var handlerId = element._handlers[i]; // Verwende sie zur Suche nach den Handler-Informationen. var h = w._allHandlers[handlerId]; // Mit diesen Informationen können wir den Handler vom Element lösen. element.detachEvent("on" + eventType, h.wrappedHandler); // Entferne ein Element aus dem element._handlers-Array. element._handlers.splice(i, 1); // Lösche die Handler-Informationen aus dem _allHandlers-Objekt des Fensters. delete w._allHandlers[handlerId]; }; // Eine Utility-Funktion zum Finden eines Handlers im element._handlers-Array // Gib einen Array-Index zurück oder -1, wenn kein passender Handler gefunden wurde Handler._find = function(element, eventType, handler) { var handlers = element._handlers; if (!handlers) return -1; // Wenn keine Handler registriert sind, wurde // nichts gefunden // Hole das Fenster dieses Elements var d = element.document || element; var w = d.parentWindow; // Durchlaufe die Handler, die mit diesem Element assoziiert sind, und suche // nach einem mit richtigem Typ und der richtigen Funktion. // Wir suchen rückwärts, da der zuletzt registrierte Handler // höchstwahrscheinlich als erster entfernt wird. for(var i = handlers.length-1; i >= 0; i--) { var handlerId = handlers[i]; // hole die Handler-id var h = w._allHandlers[handlerId]; // hole die Handler-Informationen // Wenn Handler-Info auf Typ und Handler-Funktion passt, haben wir ihn gefunden. if (h.eventType == eventType && h.handler == handler) return i; } return -1; // Nichts Passendes gefunden }; Handler._removeAllHandlers = function( ) { // Diese Funktion ist als onunload-Handler registriert, mit // attachEvent. Das bedeutet, dass sich das this-Schlüsselwort auf das // Fenster bezieht, in dem das Event stattfand. var w = this; // Iteriere durch alle registrierten Handler for(id in w._allHandlers) {
462 | Kapitel 17: Events und Event-Handling
491-0.book Seite 463 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-2: Ein Event-Kompatibilitäts-Layer für IE (Fortsetzung)
clientseitiges JavaScript
// Hole die Handler-Info für diese Handler-Id var h = w._allHandlers[id]; // Löse den Handler mit Hilfe dieser Informationen h.element.detachEvent("on" + h.eventType, h.wrappedHandler); // Lösche die Handler-Informationen aus dem Fenster delete w._allHandlers[id]; } } // Private Utility zur Erzeugung eindeutiger Handler-ids Handler._counter = 0; Handler._uid = function( ) { return "h" + Handler._counter++; }; }
17.4 Maus-Events Nachdem wir jetzt die drei Event-Modelle kennen, sehen wir uns etwas praktischen Event-Handling-Code an. Dieser Abschnitt bespricht Maus-Events ausführlicher.
17.4.1 Mauskoordinaten konvertieren Tritt ein Maus-Event auf, so enthalten die Eigenschaften clientX und clientY des EventObjekts die Position des Mauszeigers. Diese Position wird in Fensterkoordinaten angegeben: Sie beziehen sich auf die linke obere Ecke des »Sichtfensters« im Browser und berücksichtigen das Scrollen des Dokuments nicht. Sie müssen diese Werte wahrscheinlich oft in Dokumentkoordinaten konvertieren: Um beispielsweise ein Tooltip-Fenster neben dem Mauszeiger anzuzeigen, brauchen Sie die Dokumentkoordinaten zur Positionierung des Tooltips. Beispiel 17-3 erweitert den Tooltip-Code aus Beispiel 16-4. Beispiel 16-4 zeigte einfach, wie Sie ein Tooltip-Fenster an den von Ihnen festgelegten Dokumentkoordinaten anzeigen. Das jetzige Beispiel erweitert dieses Beispiel und fügt die Methode Tooltip.schedule( ) hinzu, die einen Tooltip an Koordinaten anzeigt, die einem MausEvent entnommen werden. Da das Maus-Event die Position der Maus in Fensterkoordinaten angibt, konvertiert die schedule( )-Methode sie mit Hilfe der in Beispiel 14-2 definierten Geometriemodul-Methoden in Dokumentkoordinaten. Beispiel 17-3: Tooltips mit Maus-Events positioniert // Die folgenden Werte werden von schedule( ) verwendet. // Sie werden wie Konstanten verwendet, aber Sie können // diese voreingestellten Werte auch überschreiben. Tooltip.X_OFFSET = 25; // Pixel rechts vom Mauszeiger Tooltip.Y_OFFSET = 15; // Pixel unter dem Mauszeiger Tooltip.DELAY = 500; // Millisekunden nach mouseover
17.4 Maus-Events |
463
491-0.book Seite 464 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-3: Tooltips mit Maus-Events positioniert (Fortsetzung) /** * Diese Methode plant die Anzeige eines Tooltips über dem angegebenen * Zielelement in Tooltip.DELAY Millisekunden. Das Argument e sollte * das Event-Objekt eines mouseover-Events sein. Diese Methode extrahiert die * Mauskoordinaten des Events, konvertiert sie von Fenster- in * Dokumentkoordinaten und addiert die oben angegebenen Offsets. * Sie bestimmt den Text, der im Tooltip angezeigt werden soll, durch Abfragen * des tooltip-Attributs im Zielelement. Diese Methode * registriert und deregistriert automatisch einen onmouseout-Event-Handler, * um den Tooltip zu verstecken oder seine kommende Anzeige abzubrechen. */ Tooltip.prototype.schedule = function(target, e) { // Hole den Anzeigetext. Gibt es keinen, machen wir nichts. var text = target.getAttribute("tooltip"); if (!text) return; // Das Event-Objekt enthält die Mausposition in Fensterkoordinaten. // Mit dem Geometrie-Modul konvertieren wir sie in Dokumentkoordinaten. var x = e.clientX + Geometry.getHorizontalScroll( ); var y = e.clientY + Geometry.getVerticalScroll( ); // Füge die Offsets hinzu, damit der Tooltip nicht direkt unter der Maus erscheint. x += Tooltip.X_OFFSET; y += Tooltip.Y_OFFSET; // Plane die Anzeige des Tooltips. var self = this; // Wird für die eingebetteten Funktionen unten gebraucht var timer = window.setTimeout(function( ) { self.show(text, x, y); }, Tooltip.DELAY); // Einen onmouseout-Handler zum Verstecken eines Tooltips oder Abbrechen // der anstehenden Anzeige eines Tooltips registrieren. if (target.addEventListener) target.addEventListener("mouseout", mouseout, false); else if (target.attachEvent) target.attachEvent("onmouseout", mouseout); else target.onmouseout = mouseout; // Hier kommt die Implementierung des Event-Listeners function mouseout( ) { self.hide( ); // Verstecke den Tooltip, wenn er zu sehen ist, window.clearTimeout(timer); // Brich evtl. anstehende Anzeige ab, // und entferne uns, damit wir nur einmal aufgerufen werden if (target.removeEventListener) target.removeEventListener("mouseout", mouseout, false); else if (target.detachEvent) target.detachEvent("onmouseout",mouseout); else target.onmouseout = null; } }
464 | Kapitel 17: Events und Event-Handling
491-0.book Seite 465 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-3: Tooltips mit Maus-Events positioniert (Fortsetzung) // Definiere ein einziges globales Tooltip-Objekt zur allgemeinen Verwendung Tooltip.tooltip = new Tooltip( );
clientseitiges JavaScript
/* * Diese statische Version der schedule( )-Methode verwendet den globalen Tooltip, * und zwar so: * * David Flanagans Blog */ Tooltip.schedule = function(target, e) { Tooltip.tooltip.schedule(target, e); }
17.4.2 Beispiel: Ziehen von Dokumentelementen Jetzt kennen wir sowohl die Event-Propagation als auch die Registrierung von EventHandlern und die verschiedenen Event-Objekt-Interfaces für DOM Level 2 und für die Event-Modelle von IE. Also ist es jetzt Zeit, das alles in einem praktischen Beispiel zusammenzufügen. Beispiel 17-4 zeigt eine JavaScript-Funktion drag( ). Wenn sie von einem mousedown-Event-Handler aufgerufen wird, kann ein absolut positioniertes Dokumentelement vom Benutzer gezogen werden. drag( ) funktioniert sowohl mit DOM als auch den Event-Modellen von IE. drag( ) nimmt zwei Argumente entgegen. Das erste ist das zu ziehende Element. Dies kann das Element sein, an dem das mousedown-Event eingetreten ist, oder ein umgebendes
Element (z.B. könnten Sie dem Benutzer erlauben, die Titelleiste eines Fensters zu ziehen, um das gesamte Fenster zu bewegen). In jedem Fall muss das Argument aber auf ein mit dem CSS-Attribut position absolut positioniertes Dokumentelement verweisen. Das zweite Argument ist das mit dem auslösenden mousedown-Event assoziierte Event-Objekt. drag( ) speichert die Position des mousedown-Events und registriert Event-Handler für die folgenden mousemove- und mouseup-Events. Der Handler für das mousemove-Event ist für das Verschieben des Dokumentelements zuständig, der Handler für das mouseup-Event für die Deregistrierung seiner selbst und des mousemove-Handlers. Beachten Sie, dass die Handler für die mousemove- und mouseup-Events als abfangende Event-Handler registriert sind, da der Benutzer die Maus schneller bewegen könnte, als das Dokumentelement folgen kann, und so einige dieser Events außerhalb des ursprünglichen Zielelements eintreten können. Ohne Abfangen werden die Events eventuell nicht dem richtigen Handler zugeteilt. Beachten Sie außerdem, dass die Funktionen moveHandler( ) und upHandler( ), die zur Behandlung dieser Events registriert werden, als innere Funktionen von drag( ) definiert werden. Da sie in diesem geschachtelten Geltungsbereich definiert sind, können sie die Argumente und lokalen Variablen von drag( ) verwenden, wodurch sich die Implementierung dieser Funktionen stark vereinfacht.
17.4 Maus-Events |
465
491-0.book Seite 466 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-4: Dokumentelemente ziehen /** * Drag.js: absolut positionierte HTML-Elemente ziehen. * * Dieses Modul definiert eine drag( )-Funktion, die von * einem onmousedown-Event-Handler aufgerufen wird. Anschließende mousemove-Events * verschieben das angegebene Element. Ein mouseup-Event beendet das Ziehen. * Wird das Element aus dem Bildschirm gezogen, scrollt das Fenster nicht mit. * Diese Implementierung funktioniert sowohl mit dem Event-Modell des DOM Level 2 als auch * mit dem Event-Modell von IE. * * Argumente: * * elementToDrag: das Element, das das mousedown-Event empfangen hat, oder * ein umgebendes Element. Es muss absolut positioniert sein. Seine * Werte style.left und style.top ändern sich mit der benutzergesteuerten * Zugbewegung. * * event: das Event-Objekt für das mousedown-Event. **/ function drag(elementToDrag, event) { // Die Mausposition (in Fensterkoordinaten), // an der das Ziehen beginnt var startX = event.clientX, startY = event.clientY; // Die Originalposition (in Dokumentkoordinaten) des // zu ziehenden Elements. Da elementToDrag // absolut positioniert ist, gehen wir davon aus, dass sein offsetParent der // Document-Body ist. var origX = elementToDrag.offsetLeft, origY = elementToDrag.offsetTop; // Obwohl die Koordinaten in unterschiedlichen Koordinatensystemen // berechnet werden, können wir den Unterschied zwischen ihnen ermitteln // und ihn in der moveHandler( )-Funktion verwenden. Das funktioniert, weil // sich die Bildlaufleistenposition während des Ziehens nie ändert. var deltaX = startX - origX, deltaY = startY - origY; // Registriere die Event-Handler, die auf die mousemove-Events und das // mouseup-Event reagieren, das diesem mousedown-Event folgt. if (document.addEventListener) { // Event-Modell des DOM Level 2 // Registriere abfangende Event-Handler document.addEventListener("mousemove", moveHandler, true); document.addEventListener("mouseup", upHandler, true); } else if (document.attachEvent) { // Event-Modell des IE 5+ // Im Event-Modell von IE fangen wir Events durch den Aufruf von // setCapture( ) am Element ab. elementToDrag.setCapture( ); elementToDrag.attachEvent("onmousemove", moveHandler); elementToDrag.attachEvent("onmouseup", upHandler);
466 | Kapitel 17: Events und Event-Handling
491-0.book Seite 467 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-4: Dokumentelemente ziehen (Fortsetzung) // Behandle Verlust des Maus-Abfangens als mouseup-Event. elementToDrag.attachEvent("onlosecapture", upHandler);
clientseitiges JavaScript
} else { // Event-Modell des IE 4 // In IE 4 funktionieren attachEvent( ) und setCapture( ) nicht, also setzen wir // Event-Handler direkt am Document-Objekt und hoffen, dass die // benötigten Maus-Events aufsteigen werden. var oldmovehandler = document.onmousemove; // von upHandler( ) verwendet var olduphandler = document.onmouseup; document.onmousemove = moveHandler; document.onmouseup = upHandler; } // Wir haben dieses Ereignis behandelt. Gib es an niemanden weiter. if (event.stopPropagation) event.stopPropagation( ); // DOM Level 2 else event.cancelBubble = true; // IE // Unterbinde vordefinierte Aktionen. if (event.preventDefault) event.preventDefault( ); else event.returnValue = false;
// DOM Level 2 // IE
/** * Dieser Handler fängt die mousemove-Events ab, wenn ein Element * gezogen wird. Er ist für das Verschieben des Elements zuständig. **/ function moveHandler(e) { if (!e) e = window.event; // Event-Modell des IE // Verschiebe das Element an die aktuelle Mausposition, wobei ein ggf. // notwendiger Offset des initialen Mausklicks berücksichtigt wird. elementToDrag.style.left = (e.clientX - deltaX) + "px"; elementToDrag.style.top = (e.clientY - deltaY) + "px"; // Wir zeigen dieses Ereignis niemandem sonst. if (e.stopPropagation) e.stopPropagation( ); // DOM Level 2 else e.cancelBubble = true; // IE } /** * Dieser Handler fängt das mouseup-Event ab, das am Ende des Ziehens * eintritt. **/ function upHandler(e) { if (!e) e = window.event; // Event-Modell des IE // Deregistriere die abfangenden Event-Handler if (document.removeEventListener) { // Event-Modell des DOM document.removeEventListener("mouseup", upHandler, true); document.removeEventListener("mousemove", moveHandler, true); }
17.4 Maus-Events |
467
491-0.book Seite 468 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-4: Dokumentelemente ziehen (Fortsetzung) else if (document.detachEvent) { // Event-Modell des IE 5+ elementToDrag.detachEvent("onlosecapture", upHandler); elementToDrag.detachEvent("onmouseup", upHandler); elementToDrag.detachEvent("onmousemove", moveHandler); elementToDrag.releaseCapture( ); } else { // Event-Modell des IE 4 // Ursprüngliche Handler, sofern vorhanden, wiederherstellen document.onmouseup = olduphandler; document.onmousemove = oldmovehandler; } // Und verteile das Event nicht weiter. if (e.stopPropagation) e.stopPropagation( ); // DOM Level 2 else e.cancelBubble = true; // IE } }
Der folgende Code zeigt, wie Sie drag( ) in einer HTML-Datei verwenden können (es handelt sich um eine vereinfachte Version von Beispiel 16-3, bei der das Ziehen neu hinzugekommen ist): background-color: white; border: solid black;"> Zieh mich
Dies ist ein Test. Test, eins, zwei, eins.
Dies ist ein Test.
Test.
Der entscheidende Punkt ist hier das Attribut onmousedown des inneren -Elements. Obwohl drag( ) intern die DOM- und IE-Event-Modelle verwendet, wird das Attribut hier aus Bequemlichkeitsgründen unter Verwendung des Level 0-Modells registriert. Hier ist ein weiteres einfaches Beispiel für die Verwendung von drag( ): Es definiert ein Bild, das der Benutzer ziehen kann, wenn er die Umschalt-Taste gedrückt hält:
468 | Kapitel 17: Events und Event-Handling
491-0.book Seite 469 Mittwoch, 4. April 2007 9:55 09
e-bol.net
17.5 Tasten-Events
Trotz der Schwierigkeiten lassen sich nützliche Skripten zum Umgang mit Tasten-Events schreiben, die zumindest in Firefox und IE funktionieren. Dieser Abschnitt zeigt ein paar einfache Skripten und führt dann eine etwas allgemeinere Keymap-Klasse zum Abbilden von Tastatur-Events auf JavaScript-Handlerfunktionen ein.
17.5.1 Tasten-Event-Typen Es gibt drei Tasten-Event-Typen: keydown, keypress und keyup; sie entsprechen den onkeydown-, onkeypress- und onkeyup-Event-Handlern. Ein typischer Tastendruck erzeugt alle drei Events: keydown, keypress und anschließend keyup, wenn die Taste losgelassen wird. Wenn eine Taste gedrückt gehalten wird und automatisch das Signal wiederholt, kann es mehrere keypress-Events zwischen keydown und keyup geben, aber das ist betriebssystem- und browserabhängig und man kann sich nicht darauf verlassen. Von den drei Event-Typen sind die keypress-Events am benutzerfreundlichsten: das Event-Objekt, das mit ihnen assoziiert ist, enthält den Code des tatsächlich erzeugten Zeichens. Die keydown- und keyup-Events stehen auf einer niederen Ebene; ihre TastenEvents beinhalten einen »virtuellen Tastencode«, der mit den von der Tastatur erzeugten Hardware-Codes zu tun hat. Für alphanumerische Zeichen im ASCII-Zeichensatz passen diese virtuellen Tastencodes zu den ASCII-Codes, werden aber nicht vollständig bearbeitet. Wenn Sie die Umschalt-Taste gedrückt halten und die Taste 2 drücken, sagt Ihnen das keydown-Event, dass der Tastendruck »shift-2« aufgetreten ist. Das keypress-Event interpretiert das für Sie und lässt Sie wissen, dass dieser Tastendruck das druckbare Zeichen »@« erzeugt hat. (Diese Zuordnung kann bei anderen Tastaturlayouts anders aussehen). Nicht-druckbare Funktionstasten, wie beispielsweise Löschen, Enter, Escape, die Pfeiltasten und F1 bis F12, erzeugen keydown- und keyup-Events. In einigen Browsern erzeugen sie auch keypress-Events. In IE treten keypress-Events aber nur dann auf, wenn der Tastendruck einen ASCII-Code hat – d.h., wenn es sich um ein druckbares Zeichen oder ein Steuerzeichen handelt. Nicht druckbare Funktionstasten haben ebenso wie druckbare Tasten virtuelle Tastencodes, und diese stehen über das Event-Objekt zur Verfü-
17.5 Tasten-Events |
469
clientseitiges JavaScript
Wie Sie bereits wissen, sind Events und Event-Handling der Gegenstand vieler Browserinkompatibilitäten. Und Tasten-Events sind noch inkompatibler als die meisten anderen: Sie sind im DOM Level 2 Event-Modul nicht standardisiert, und IE und Mozilla-basierte Browser gehen mit ihnen etwas unterschiedlich um. Leider reflektiert das einfach den Stand der Technik im Umgang mit Tastatureingaben. Die Betriebs- und FenstersystemAPIs, auf denen die Browser aufgebaut werden, sind üblicherweise komplex und verwirrend. Die Bearbeitung von Texteingaben ist auf vielen Ebenen kompliziert, von Hardware-Tastaturlayouts bis zur Eingabemethodenbearbeitung für Sprachen mit komplexen Schriftzeichen.
491-0.book Seite 470 Mittwoch, 4. April 2007 9:55 09
e-bol.net gung, das mit dem keydown-Event verbunden ist. Zum Beispiel erzeugt die linke Pfeiltaste einen Tastencode von 37 (zumindest beim standardmäßigen U.S.-Tastaturlayout und ähnlichen Layouts, wie z.B. einer deutschen Tastatur). Als Faustregel können Sie sich merken, dass das keydown-Event bei Funktionstasten am nützlichsten ist, und das keypress-Event bei druckbaren Tasten.
17.5.2 Tasten-Event-Details Die Event-Objekte, die an keydown-, keypress- und keyup-Event-Handler übergeben werden, sind bei allen drei Event-Typen dieselben, aber die Interpretation bestimmter Eigenschaften dieser Objekte hängt vom Event-Typ ab. Die Event-Objekte sind natürlich auch browserabhängig und haben in Firefox und IE unterschiedliche Eigenschaften. Wenn die Alt-, Ctrl- oder Shift-Tasten gedrückt gehalten werden, während eine andere Taste gedrückt wird, wird das durch den Zustand der altKey-, ctrlKey- und shiftKeyEigenschaften des Event-Objekts angezeigt. Diese Eigenschaften sind übrigens portabel: Sie funktioneren sowohl in Firefox als auch in IE und für alle Typen von Tasten-Events. (Eine Ausnahme bestätigt die Regel: Alt-Tastenkombinationen werden von IE als nicht druckbar angesehen und erzeugen daher kein keypress-Event). An den Tastencode oder Zeichencode eines Tasten-Events zu kommen, ist allerdings weniger portabel. Firefox definiert zwei Eigenschaften. keyCode enthält den virtuellen Tastencode niederer Ebene einer Taste und wird dem keydown-Event mitgegeben. charCode enthält die Codierung des druckbaren Zeichens, das durch Drücken dieser Taste erzeugt wird, und wird dem keypress-Event beigefügt. In Firefox erzeugen Funktionstasten ein keypress-Event; in diesem Fall ist charCode 0 und der keyCode enthält den virtuellen Tastencode. In IE gibt es nur die keyCode-Eigenschaft, und ihre Interpretation hängt vom Event-Typ ab. Bei keydown-Events ist keyCode ein virtueller Tastencode; bei keypress-Events ist keyCode ein Zeichencode. Zeichencodes können mit der statischen Funktion String.fromCharCode( ) in Zeichen konvertiert werden. Um Tastencode korrekt zu verarbeiten, müssen Sie nur wissen, welche Tasten welche Tastencodes erzeugen. Beispiel 17-6 am Ende dieses Abschnitts enthält eine Zuordnung von Tastencodes zu den Funktionstasten, die sie repräsentieren (zumindest auf einem standardmäßigen U.S.-Tastaturlayout o.Ä.).
17.5.3 Tastatureingaben filtern Tasten-Event-Handler können mit - und -Elementen zum Filtern der Benutzereingaben verwendet werden. Nehmen wir zum Beispiel an, Sie möchten die Benutzereingaben zwingend in Großschreibung konvertieren: Nachname:
470 | Kapitel 17: Events und Event-Handling
491-0.book Seite 471 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Ein komplexeres Beispiel für Tasten-Event-Filterung verwendet den onkeypress-Handler, um die Benutzereingabe auf eine bestimmte Untermenge von Zeichen zu beschränken. Beispielsweise möchten Sie einen Benutzer davon abhalten, Buchstaben in ein für Ziffern vorgesehenes Feld einzugeben. Beispiel 17-5 ist ein unaufdringliches Modul mit JavaScript-Code, das genau diese Art Filterung ermöglicht. Es sucht nach Tags, die ein zusätzliches (nicht standardisiertes) Attribut namens allowed haben. Das Modul registriert einen keypress-Event-Handler auf jedem solchen Textfeld, um die Eingabe auf Zeichen zu beschränken, die im Wert des allowed-Attributs vorkommen. Der Eingangskommentar am Anfang von Beispiel 17-5 enthält etwas Beispiel-HTML, das das Modul verwendet. Beispiel 17-5: Benutzereingaben auf eine bestimmte Zeichenmenge beschränken /** * InputFilter.js: Unauffälliges Filtern von Tastendrücken für -Tags * * Dieses Modul findet alle -Elementes im Dokument, die * ein nicht standardisiertes Attribut names "allowed" haben. Es registriert einen * onkeypress-Event-Handler für alle solchen Elemente, um die Benutzereingabe * auf Zeichen im Wert des allowed-Attributs zu beschränken. * Wenn das -Element auch noch ein "messageid"-Attribut hat, * wird der Wert dieses Attributs als id eines anderen Dokument* elements interpretiert. Wenn der Benutzer ein verbotenes Zeichen tippt, wird das messageid* Element sichtbar gemacht. Wenn der Benutzer ein erlaubtes Zeichen eintippt, * wird das messageid-Element versteckt. Dieses messageid-Element soll * dem Benutzer eine Erklärung für den verweigerten Tastendruck geben. Es * sollte üblicherweise mit CSS so gestylt werden, dass es anfangs unsichtbar ist. * * Hier ist etwas Beispiel-HTML, das dieses Modul verwendet. * Postleitzahl: * * Nur Ziffern * * In Browsern wie IE, die addEventListener( ) nicht unterstützen, * überschreibt der hier registrierte keypress-Handler alle anderen keypress-Handler, * die in HTML definiert werden.
17.5 Tasten-Events |
471
clientseitiges JavaScript
Ein -Element hängt das getippte Zeichen an seine value-Eigenschaft an, nachdem das keypress-Event auftritt. Bis das keyup-Event eintrifft, ist die value-Eigenschaft daher auf dem neuesten Stand, und Sie können sie einfach komplett in Großbuchstaben konvertieren. Das funktioniert unabhängig davon, wo der Cursor im Textfeld positioniert ist, und Sie können es mit dem DOM Level 0-Event-Modell erledigen. Sie müssen nicht wissen, welche Taste gedrückt wurde, und müssen deshalb nicht auf das mit dem Event assoziierte Event-Objekt zugreifen. (Beachten Sie, dass der onkeyup-Event-Handler nicht ausgelöst wird, wenn der Benutzer Text mit der Maus in das Feld kopiert. Um mit diesem Fall klarzukommen, werden Sie wahrscheinlich auch einen onchange-Handler registrieren wollen. Siehe Kapitel 18 für zusätzliche Details zu Formularelementen und ihren EventHandlern).
491-0.book Seite 472 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-5: Benutzereingaben auf eine bestimmte Zeichenmenge beschränken (Fortsetzung) * * Dieses Modul ist völlig unauffällig: es definiert keine Symbole im * globalen Namensraum. */ (function( ) { // Das gesamte Modul steht in einer anonymen Funktion // Nach dem Laden die unten stehende init( )-Funktion aufrufen if (window.addEventListener) window.addEventListener("load", init, false); else if (window.attachEvent) window.attachEvent("onload", init); // Suche alle -Tags, die einen Event-Handler brauchen function init( ) { var inputtags = document.getElementsByTagName("input"); for(var i = 0 ; i < inputtags.length; i++) { // Tags durchlaufen var tag = inputtags[i]; if (tag.type != "text") continue; // Wir wollen nur Textfelder var allowed = tag.getAttribute("allowed"); if (!allowed) continue; // und nur, wenn sie ein allowed-Attribut haben // Registriere unsere Event-Handler-Funktion an diesem Input-Tag if (tag.addEventListener) tag.addEventListener("keypress", filter, false); else { // Wir verwenden attachEvent nicht, da es die Handler-Funktion // nicht mit dem richtigen Wert des this-Schlüsselworts aufruft. tag.onkeypress = filter; } } } // Das ist der keypress-Handler, der die Benutzereingabe filtert function filter(event) { // Hole das Event-Objekt und den Zeichencode in einer portablen Form var e = event || window.event; // Tasten-Event-Objekt var code = e.charCode || e.keyCode; // Welche Taste wurde gedrückt? // if if if
Wenn dieser Tastendruck eine beliebige Funktionstaste ist, nicht filtern (e.charCode == 0) return true; // Funktionstaste (nur unter Firefox) (e.ctrlKey || e.altKey) return true; // Strg oder Alt gedrückt (code < 32) return true; // ASCII-Steuerzeichen
// Suche jetzt die Informationen, die wir von diesem Input-Element brauchen var allowed = this.getAttribute("allowed"); // Gültige Zeichen var messageElement = null; // zu versteckende/anzuzeigende Meldung var messageid = this.getAttribute("messageid"); // Message-ID, falls vorhanden if (messageid) // Element holen, wenn eine Message-ID vorhanden ist messageElement = document.getElementById(messageid); // Konvertiere den Zeichencode in ein Zeichen var c = String.fromCharCode(code); // Prüfe, ob das Zeichen in der Menge der erlaubten Zeichen ist
472 | Kapitel 17: Events und Event-Handling
491-0.book Seite 473 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-5: Benutzereingaben auf eine bestimmte Zeichenmenge beschränken (Fortsetzung)
clientseitiges JavaScript
if (allowed.indexOf(c) != -1) { // Wenn c ein gültiges Zeichen ist, dann verstecke ggf. die Meldung if (messageElement) messageElement.style.visibility = "hidden"; return true; // und akzeptiere das Zeichen } else { // Wenn c nicht in der Menge der erlaubten Zeichen ist, Meldung anzeigen if (messageElement) messageElement.style.visibility = "visible"; // und lehne dieses keypress-Event ab if (e.preventDefault) e.preventDefault( ); if (e.returnValue) e.returnValue = false; return false; } } })( ); // Beende die anonyme Funktion, und rufe sie auf.
17.5.4 Tastenkürzel mit einer Keymap Grafische Programme, die auf dem Desktop eines Benutzers laufen, definieren in der Regel Tastaturabkürzungen für Befehle, die auch über Ausklappmenüs, Werkzeugleisten, usw. aufgerufen werden können. Webbrowser (und HTML) sind ziemlich mausorientiert, und Webanwendungen unterstützen zumindest standardmäßig keine Tastaturabkürzungen. Das sollten sie aber. Wenn Sie DHTML verwenden, um Ausklappmenüs für Ihre Webanwendung zu simulieren, sollten Sie für diese Menüs auch Tastaturabkürzungen unterstützen. Beispiel 17-6 zeigt, wie Sie das erreichen können. Es definiert eine Keymap-Klasse, die Tastendruck-Bezeichner wie z.B. »Escape«, »Delete«, »Alt_Z« und »alt_ctrl_shift_F5« JavaScript-Funktionen zuordnet, die als Antwort auf diese Tastendrücke aufgerufen werden. Tastenanbindungen übergeben Sie an den Keymap( )-Konstruktor in der Form eines JavaScript-Objekts, dessen Eigenschaftsnamen Tastendruckbezeichner und Eigenschaftswerte Handler-Funktionen sind. Bindungen fügen Sie mit der bind( )-Methode hinzu und entfernen sie mit der unbind( )-Methode. Eine Keymap installieren Sie an einem HTMLElement (das oft das Document-Objekt ist) mit der install( )-Methode. Bei der Installation einer Keymap an einem Element werden sowohl der onkeydown-Event-Handler als auch der onkeypress-Event-Handler an diesem Element registriert, um sowohl Funktionstasten als auch druckbare Zeichen abzufangen. Beispiel 17-6 beginnt mit einem langen Kommentar, der das Modul ausführlicher erklärt. Ein besonders relevanter Teil dieses Kommentars ist der Abschnitt »Beschränkungen«. Beispiel 17-6: Eine Keymap-Klasse für Tastaturabkürzungen /* * Keymap.js: Tasten-Events an Handler-Funktionen binden. * * Dieses Modul definiert eine Keymap-Klasse. Eine Instanz dieser Klasse ordnet * Tasten-Bezeichnern (unten definiert) Handler-Funktionen zu. Eine
17.5 Tasten-Events |
473
491-0.book Seite 474 Mittwoch, 4. April 2007 9:55 09
Keymap kann an einem HTML-Element installiert werden und dessen keydown- und keypressEvents bearbeiten. Tritt ein solches Event auf, wird über die Zuordnung in der Keymap die passende Handler-Funktion aufgerufen. Bei der Erzeugung einer Keymap übergeben Sie ein JavaScript-Objekt, das die Anfangsanbindungen für die Keymap repräsentiert. Die Eigenschaftsnamen dieses Objekts sind Tasten-Bezeichner und die Eigenschaftswerte sind die Handler-Funktionen. Nach der Erzeugung einer Keymap können Sie neue Anbindungen durch Übergeben von Tasten-Bezeichner, und Handler-Funktion an bind( ) hinzufügen. Eine Bindung entfernen Sie, indem Sie einen Tasten-Bezeichner an die unbind( )-Methode übergeben. Sie verwenden eine Keymap durch Aufruf ihrer install( )-Methode mit einem HTML-Element, wie z.B. dem Document-Objekt. Die install( )-Methode installiert onkeypress- und onkeydownEvent-Handler am angegebenen Objekt und ersetzt alle Handler, die ggf. vorher über dieser Eigenschaften gesetzt wurden. Werden diese Handler aufgerufen, so bestimmen sie den Tastenbezeichner des Tasten-Events und rufen die ggf. vorhandene Handler-Funktion auf, die an diesen Tastenbezeichner gebunden ist. Ist für das Event keine Zuordnung vorhanden, wird die Default-Handler-Funktion (siehe unten) verwendet, falls sie definiert ist. Eine einzige Keymap kann auf mehreren HTML-Elementen installiert werden. Tastenbezeichner Ein Tastenbezeichner ist eine Stringrepräsentation (groß- oder kleingeschrieben) einer Taste mit ggf. gleichzeitig gedrückten Modifikationstasten. Der Tastenname ist der Name der Taste, d.h., oft der Text, der tatsächlich auf der Taste einer englischen Tastatur steht. Gültige Tastennamen sind z.B. "A", "7", "F2", "PageUp", "Left", "Delete", "/", "~". Bei druckbaren Tasten ist der Tastenname einfach das Zeichen, das die Taste erzeugt. Bei nicht-druckbaren Tasten sind die Namen aus den von Firefox definierten KeyEvent.DOM_VK_-Konstanten abgeleitet. Das sind lediglich die Konstantennamen, wobei "DOM_VK_" und ggf. vorhandene Unterstriche entfernt sind. Beispielsweise wird die KeyEvent-Konstante DOM_VK_BACK_SPACE zu BACKSPACE. Das Keymap.keyCodeToFunctionKey-Objekt in diesem Modul führt alle Namen auf. Ein Tastenbezeichner kann auch Modifikationstastenpräfixe enthalten. Diese Präfixe sind Alt_, Ctrl_ und Shift_. Groß- und Kleinschreibung sind hier unwichtig, sind aber mehrere vorhanden, müssen sie in alphabetischer Reihenfolge stehen. Tastenbezeichner, die Modifikationstasten enthalten sind z.B. "Shift_A", "ALT_F2" und "alt_ctrl_delete". Beachten Sie, dass "ctrl_alt_delete" ungültig ist, da die Tasten nicht alphabetisch geordnet sind. Umgeschaltete Sonderzeichentasten werden normalerweise als die entsprechenden Zeichen zurückgegeben. Shift-4 erzeugt beispielsweise den Tastenbezeichner "$". Wenn aber zusätzlich Alt oder Strg gedrückt werden, wird stattdessen das nicht umgeschaltete Zeichen verwendet. Beispielsweise erhalten wir den Tastenbezeichner Strg_Shift_4 statt Strg_$.
474 | Kapitel 17: Events und Event-Handling
491-0.book Seite 475 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-6: Eine Keymap-Klasse für Tastaturabkürzungen (Fortsetzung)
// Das ist die Konstruktorfunktion function Keymap(bindings) { this.map = {}; // Definiere die Zuweisung Bezeichner->Handler if (bindings) { // Kopiere Anfangsanbindungen, und konvertiere zu Kleinschreibung for(name in bindings) this.map[name.toLowerCase( )] = bindings[name]; } } // Binde den angegebenen Tastenbezeichner an die angegebene Handler-Funktion Keymap.prototype.bind = function(key, func) { this.map[key.toLowerCase( )] = func; }; // Lösche die Bindung für den angegebenen Tastenbezeichner Keymap.prototype.unbind = function(key) { delete this.map[key.toLowerCase( )]; }; // Installiere diese Keymap am angegebenen HTML-Element Keymap.prototype.install = function(element) { // Das ist die Event-Handler-Funktion var keymap = this; function handler(event) { return keymap.dispatch(event); } // Installiere sie jetzt if (element.addEventListener) { element.addEventListener("keydown", handler, false);
17.5 Tasten-Events |
475
clientseitiges JavaScript
* Handler-Funktionen * * Wird eine Handler-Funktion aufgerufen, werden ihr drei Argumente übergeben: * 1) das HTML-Element, an dem das Tasten-Event stattfand * 2) der Tastenbezeichner der Taste, die gedrückt wurde * 3) das Event-Objekt für das keydown-Event * * Default-Handler * * Der reservierte Tastenname "defaulthandler" kann einer Handler-Funktion zugewiesen werden. * Diese Funktion wird aufgerufen, wenn keine andere tastenspezifische Anbindung besteht. * * Beschränkungen * * Eine Handler-Funktion kann nicht an alle Tasten gebunden werden. Das Betriebssystem * fängt manche Tastenabfolgen (z.B. Alt-F4) ab. Und der Browser * selbst fängt eventuell andere ab (z.B. Strg-S). Dieser Code hängt von Browser, OS * und Locale ab. Funktionstasten und modifizierte Funktionstasten funktionieren gut. * Nicht-modifizierte, druckbare Tasten funktionieren ebenfalls gut. Die Kombination von * Strg und Alt mit druckbaren Zeichen – und insbesondere mit Sonderzeichen – ist * weniger robust. */
491-0.book Seite 476 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-6: Eine Keymap-Klasse für Tastaturabkürzungen (Fortsetzung) element.addEventListener("keypress", handler, false); } else if (element.attachEvent) { element.attachEvent("onkeydown", handler); element.attachEvent("onkeypress", handler); } else { element.onkeydown = element.onkeypress = handler; } }; // Dieses Objekt erzeugt Bezeichner aus keyCode-Werten für normale nicht-druckbare // Funktionstasten. IE und Firefox verwenden für diese Tasten i.d.R. kompatible keyCodes. // Beachten Sie aber, dass diese keyCodes geräteabhängig sein können und verschiedene // Tastatur-Layouts unterschiedliche Werte haben können. Keymap.keyCodeToFunctionKey = { 8:"backspace", 9:"tab", 13:"return", 19:"pause", 27:"escape", 32:"space", 33:"pageup", 34:"pagedown", 35:"end", 36:"home", 37:"left", 38:"up", 39:"right", 40:"down", 44:"printscreen", 45:"insert", 46:"delete", 112:"f1", 113:"f2", 114:"f3", 115:"f4", 116:"f5", 117:"f6", 118:"f7", 119:"f8", 120:"f9", 121:"f10", 122:"f11", 123:"f12", 144:"numlock", 145:"scrolllock" }; // Dieses Objekt bildet keydown-keyCode-Werte auf Bezeichner ab, für druckbare // Zeichen. Alphanumerische Zeichen haben ihren ASCII-Code, aber // Sonderzeichen nicht. Beachten Sie, dass das locale-abhängig sein kann // und auf internationalen Tastaturen evtl. nicht richtig funktioniert. Keymap.keyCodeToPrintableChar = { 48:"0", 49:"1", 50:"2", 51:"3", 52:"4", 53:"5", 54:"6", 55:"7", 56:"8", 57:"9", 59:";", 61:"=", 65:"a", 66:"b", 67:"c", 68:"d", 69:"e", 70:"f", 71:"g", 72:"h", 73:"i", 74:"j", 75:"k", 76:"l", 77:"m", 78:"n", 79:"o", 80:"p", 81:"q", 82:"r", 83:"s", 84:"t", 85:"u", 86:"v", 87:"w", 88:"x", 89:"y", 90:"z", 107:"+", 109:"-", 110:".", 188:",", 190:".", 191:"/", 192:"`", 219:"[", 220:"\\", 221:"]", 222:"\"" }; // Diese Methode leitet Tasten-Events je nach keymap-Anbindung weiter. Keymap.prototype.dispatch = function(event) { var e = event || window.event; // IE-Event-Modell berücksichtigen // Wir beginnen ohne Modifikationstasten und ohne Bezeichner var modifiers = "" var keyname = null; if (e.type == "keydown") { var code = e.keyCode; // Ignoriere keydown-Events für Shift, Strg und Alt if (code == 16 || code == 17 || code == 18) return;
476 | Kapitel 17: Events und Event-Handling
491-0.book Seite 477 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-6: Eine Keymap-Klasse für Tastaturabkürzungen (Fortsetzung) // Hole den Tastenbezeichner aus unserer Zuordnung keyname = Keymap.keyCodeToFunctionKey[code];
// // // if
clientseitiges JavaScript
// Wenn das keine Funktionstaste war, aber die strg- oder alt-Tasten gedrückt // sind, wollen wir es wie eine Funktiontaste behandeln if (!keyname && (e.altKey || e.ctrlKey)) keyname = Keymap.keyCodeToPrintableChar[code]; Hat sich ein Bezeichner für die Taste gefunden, brauchen wir die Modifikationstasten. Wenn nicht, einfach zurückkehren und keydown-Event ignorieren. (keyname) { if (e.altKey) modifiers += "alt_"; if (e.ctrlKey) modifiers += "ctrl_"; if (e.shiftKey) modifiers += "shift_";
} else return; } else if (e.type == "keypress") { // Wenn strg oder alt gedrückt sind, haben wir die Taste bereits behandelt. if (e.altKey || e.ctrlKey) return; // Unter Firefox erhalten wir keypress-Events auch für nicht-druckbare Tasten. // In diesem Fall einfach zurückkehren und so tun, als wäre nichts passiert if (e.charCode != undefined && e.charCode == 0) return; // Firefox gibt uns druckbare Tasten in e.charCode, IE in e.keyCode var code = e.charCode || e.keyCode; // Der Code ist ein ASCII-Code, konvertiere ihn in einen String. keyname=String.fromCharCode(code); // Großgeschriebene Tastenbezeichner machen wir klein und fügen Shift hinzu // Damit können wir mit CAPS LOCK umgehen, das Großbuchstaben sendet, // ohne dass dabei der Shift-Modifier gesetzt ist. var lowercase = keyname.toLowerCase( ); if (keyname != lowercase) { keyname = lowercase; // Verwende den kleingeschriebenen Namen, modifiers = "shift_"; // und füge den Shift-Modifikator an. } } // Modifikatoren und Tastenbezeichner sind bestimmt - jetzt suchen wir nach // einer Handler-Funktion für die Tasten-Modifikatorenkombination var func = this.map[modifiers+keyname]; // Wenn wir keine gefunden haben, Default-Handler verwenden, wenn vorhanden if (!func) func = this.map["defaulthandler"]; if (func) {
// Wenn ein Handler für diese Taste vorhanden ist, benutze ihn
17.5 Tasten-Events |
477
491-0.book Seite 478 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-6: Eine Keymap-Klasse für Tastaturabkürzungen (Fortsetzung) // Bestimme, an welchem Element das Event stattfand var target = e.target; // DOM-Standard-Event-Modell if (!target) target = e.srcElement; // IE-Event-Modell // Rufe die Handler-Funktion auf func(target, modifiers+keyname, e); // Halte das Event von der Ausbreitung ab, und unterdrücke die Standardaktion für // das Event. Beachte, dass preventDefault normalerweise // Browserbefehle der obersten Ebene, z.B. F1 für Hilfe, nicht verhindert. if (e.stopPropagation) e.stopPropagation( ); // DOM-Modell else e.cancelBubble = true; // IE-Modell if (e.preventDefault) e.preventDefault( ); // DOM else e.returnValue = false; // IE return false; // Legacy-Event-Modell } };
17.6 Das onload-Event JavaScript-Code, der das Dokument verändert, in dem er enthalten ist, darf normalerweise erst laufen, wenn das Dokument vollständig geladen ist (das wird in Abschnitt 13.5.7 ausführlicher erläutert). Nach dem Abschließen des Ladevorgangs löst der Webbrowser ein onload-Event am Window-Objekt aus, und dieses Event wird oft verwendet, um Code auszuführen, der auf das gesamte Dokument zugreifen können muss. Enthält Ihre Webseite mehrere unabhängige Module, die Code als Antwort auf das onload-Event laufen lassen müssen, so ist eventuell eine plattformübergreifende Utility-Funktion nützlich für Sie, wie die in Beispiel 17-7 gezeigte. Beispiel 17-7: Portable Event-Registrierung für onload-Event-Handler /* * * * * * * * * * * * * * * * *
runOnLoad.js: portable Registrierung für onload-Event-Handler. Dieses Modul definiert eine einzige runOnLoad( )-Funktion für das portable Registrieren von Funktionen, die erst nach vollständigem Laden des Dokuments sicher aufgerufen werden können, wenn das DOM vorhanden ist. An Funktionen, die mit runOnLoad( ) registriert sind, werden beim Aufruf keine Argumente übergeben. Sie werden nicht als Methode eines bestimmten Objekts aufgerufen, und this sollte nicht verwendet werden. Funktionen, die mit runOnLoad( ) registriert wurden, werden in der Reihenfolge aufgerufen, in der sie registriert wurden. Es gibt keine Möglichkeit, mit runOnLoad( ) registrierte Funktionen zu deregistrieren. In alten Browsern, die addEventListener( ) und attachEvent( ) nicht unterstützen, braucht diese Funktion die DOM Level 0-window.onload-Eigenschaft und funktioniert nicht richtig, wenn sie in Dokumenten verwendet wird, die das onload-Attribut ihrer - oder -Tags setzen.
478 | Kapitel 17: Events und Event-Handling
491-0.book Seite 479 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-7: Portable Event-Registrierung für onload-Event-Handler (Fortsetzung) */ function runOnLoad(f) { if (runOnLoad.loaded) f( ); // Wenn bereits geladen, rufe f( ) jetzt einfach auf. else runOnLoad.funcs.push(f); // Ansonsten speichere sie }
clientseitiges JavaScript
runOnLoad.funcs = []; // Das Array der nach dem Laden aufzurufenden Funktionen runOnLoad.loaded = false; // Die Funktionen wurden noch nicht ausgeführt. // Alle registrierten Funktionen in der Reihenfolge der Registrierung ausführen. // Es ist sicher, runOnLoad.run( ) mehrfach aufzurufen: Aufrufe, die dem ersten Aufruf // folgen, haben keine Auswirkung. Eine Initialisierungsfunktion kann // runOnLoad( ) zur Registrierung einer weiteren Funktion sicher aufrufen. runOnLoad.run = function( ) { if (runOnLoad.loaded) return; // Mache nichts, wenn die Ausführung bereits stattfand for(var i = 0; i < runOnLoad.funcs.length; i++) { try { runOnLoad.funcs[i]( ); } catch(e) { /* Eine Ausnahme in einer Funktion sollte den Rest nicht anhalten */ } } runOnLoad.loaded = true; // Ausführung vermerken. delete runOnLoad.funcs; // Die eigentlichen Funktionen nicht speichern, delete runOnLoad.run; // einschließlich dieser Funktion! }; // Registriere runOnLoad.run( ) als den onload-Event-Handler für das Fenster if (window.addEventListener) window.addEventListener("load", runOnLoad.run, false); else if (window.attachEvent) window.attachEvent("onload", runOnLoad.run); else window.onload = runOnLoad.run;
17.7 Synthetische Events Sie können sowohl mit dem DOM Level 2-Event-Modell als auch mit dem IE-EventModell synthetische Event-Objekte erzeugen und sie an Event-Handler leiten, die an Dokumentelementen registriert sind. Im Grunde dient diese Technik dazu, Browser zum Aufruf der an einem Element registrierten Event-Handler zu bringen (und, im Fall von aufsteigenden Events, die an den übergeordneten Elementen registrierten Handler aufzurufen). Beim Level 0-Event-Modell sind synthetische Events nicht notwendig, da EventHandler über die verschiedenen Event-Handler-Eigenschaften zur Verfügung stehen. In den fortgeschrittenen Event-Modellen lassen sich aber die Handler, die mit addEventListener oder attachEvent registriert sind, nicht abfragen. Sie können nur mit den in diesem Abschnitt gezeigten Techniken aufgerufen werden.
17.7 Synthetische Events |
479
491-0.book Seite 480 Mittwoch, 4. April 2007 9:55 09
e-bol.net Im DOM-Event-Modell erzeugen Sie ein synthetisches Event mit Document. createEvent( ), initialisieren das Event mit Event.initEvent( ), UIEvent.initUIEvent( ) oder MouseEvent.initMouseEvent( ) und leiten das Event dann mit der dispatchEventMethode des Knotens weiter, an den es gesendet werden soll. Unter IE erzeugen Sie ein neues Event-Objekt mit Document.createEventObject und leiten es dann mit der fireEvent( )-Methode des Zielelements weiter. Beispiel 17-8 führt diese Methoden vor. Es definiert eine plattformübergreifende Funktion zum Versenden synthetischer dataavailable-Events und eine Funktion zur Registrierung von Event-Handlern für Events dieses Typs. Es ist wichtig zu verstehen, dass synthetische Events, die mit dispatchEvent( ) und fireEvent( ) ausgelöst werden, nicht in eine Schlange eingereiht und asynchron bearbeitet werden. Vielmehr werden sie sofort ausgelöst, und ihre Handler werden synchron aufgerufen, bevor der Aufruf von dispatchEvent( ) oder fireEvent( ) zurückkehrt. Das bedeutet, dass der Versand von synthetischen Events keine Technik ist, mit der man die Ausführung von Code verzögern kann, bis der Browser alle anstehenden Events ausgeführt hat. Um das zu erreichen, müssen Sie setTimeout( ) mit einem Timeout-Wert von 0 Millisekunden aufrufen. Rohe Events auf niedriger Ebene, wie z.B. Maus-Events, können synthetisiert und weitergeleitet werden, aber es ist nicht umfassend geregelt, wie Dokumentelemente auf diese Events reagieren müssen. Meist ist es nützlicher, diese Funktionalität für sematische Events auf höherer Ebene zu verwenden, für die der Browser keine Standardantwort hat. Aus diesem Grund verwendet Beispiel 17-8 den Event-Typ dataavailable. Beispiel 17-8: Versenden synthetischer Events /** * DataEvent.js: versende und empfange ondataavailable-Events. * * Dieses Modul definiert zwei Funktionen: DataEvent.send( ) und DataEvent.receive( ) * zum Versand synthetischer dataavailable-Events und zur Registrierung von Event* Handlern für diese Events. Der Code ist so geschrieben, dass er unter Firefox und anderen * DOM-standardkonformen Browsern sowie unter IE funktioniert. * * Das DOM-Event-Modell lässt synthetische Events aller Art zu, aber das IE-Modell * unterstützt nur synthetische Events vordefinierter Typen. dataavailable-Events sind der * allgemeinste vordefinierte Typ, den IE unterstützt, und sie werden hier verwendet. * * Beachten Sie, dass mit DataEvent.send( ) versendete Events nicht in eine Warteschlange * kommen, wie das bei echten Events passiert. Stattdessen werden registrierte Handler * sofort aufgerufen. */ var DataEvent = {}; /** * Sende ein synthetisches ondataavailable-Event an das angegebene Ziel. * Das Event-Objekt enthält Eigenschaften namens datatype und data * mit den angegebenen Werten. Es wird erwartet, dass datatype ein String
480 | Kapitel 17: Events und Event-Handling
491-0.book Seite 481 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 17-8: Versenden synthetischer Events (Fortsetzung)
clientseitiges JavaScript
* oder ein anderer einfacher Wert (bzw. Null) ist, der den Typ dieser Mitteilung * identifiziert, und data kann ein beliebiger JavaScript-Wert sein, auch ein Objekt * oder Array. */ DataEvent.send = function(target, datatype, data) { if (typeof target == "string") target = document.getElementById(target); // Erzeuge ein Event-Objekt. Wenn das nicht klappt, still aufgeben. if (document.createEvent) { // DOM-Event-Modell // Erzeuge das Event und gib den Namen des Event-Moduls an. // Für ein Maus-Event würden wir "MouseEvents" verwenden. var e = document.createEvent("Events"); // Initialisiere das Event-Objekt mit einer modulspezifischen Init-Methode. // Hier geben wir den Event-Typ als aufsteigend und nicht-abbrechbar an. // Vergleiche Event.initEvent, MouseEvent.initMouseEvent und UIEvent.initUIEvent e.initEvent("dataavailable", true, false); } else if (document.createEventObject) { // IE-Event-Modell // Im IE-Event-Modell rufen wir nur diese einfache Methode auf var e = document.createEventObject( ); } else return; // Mache nichts in anderen Browsern // Hier fügen wir dem Event-Objekt einige maßgeschneiderte Eigenschaften hinzu. // Zusätzlich könnten wir bereits bestehende Eigenschaften setzen. e.datatype = datatype; e.data = data; // Versende das Event an das angegebene Ziel. if (target.dispatchEvent) target.dispatchEvent(e); // DOM else if (target.fireEvent) target.fireEvent("ondataavailable", e); // IE }; /** * Registriere einen Event-Handler für ein ondataavailable-Event am angegebenen * Zielelement. */ DataEvent.receive = function(target, handler) { if (typeof target == "string") target = document.getElementById(target); if (target.addEventListener) target.addEventListener("dataavailable", handler, false); else if (target.attachEvent) target.attachEvent("ondataavailable", handler); };
17.7 Synthetische Events |
481
491-0.book Seite 482 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Chapter 1
KAPITEL 18
Formulare und Formularelemente
Wie viele Beispiele in diesem Buch zeigen, sind HTML-Formulare ein wichtiger Bestandteil vieler clientseitiger JavaScript-Programme. In diesem Kapitel erläutern wir die Einzelheiten der Programmierung mit Formularen in JavaScript. Es wird vorausgesetzt, dass Sie bereits ein wenig mit der Erstellung von HTML-Formularen und den in ihnen enthaltenen Eingabeelementen vertraut sind. Falls dies nicht der Fall ist, sollten Sie ein gutes Buch über HTML zurate ziehen.1 Wenn Sie bereits mit serverseitiger Programmierung im Zusammenhang mit der Benutzung von Formularen vertraut sind, werden Sie feststellen, dass es einige Unterschiede zur Verwendung von Formularen in JavaScript gibt. Im serverseitigen Modell wird ein Formular mit den in ihm enthaltenen Daten auf einen Rutsch abgeschickt, also an den Webserver gesandt. Der Schwerpunkt liegt auf der Bearbeitung eines vollständigen Satzes von Eingabedaten und der dynamischen Erzeugung einer neuen Webseite im Gegenzug. Das Programmiermodell von JavaScript unterscheidet sich davon erheblich. In JavaScriptPogrammen steht nicht das Abschicken eines Formulars im Vordergrund, sondern das Behandeln von Events. Ein Formular und alle in ihm enthaltenen Eingabeelemente besitzen Event-Handler, die JavaScript verwenden kann, um auf Benutzereingaben im Formular zu reagieren. Wenn der Benutzer beispielsweise auf eine Checkbox klickt, kann ein JavaScript-Programm eine Benachrichtigung durch einen Event-Handler erhalten und als Reaktion z.B. den in einem anderen Element des Formulars angezeigten Wert verändern. Bei serverseitigen Programmen kann ein HTML-Formular nur sinnvoll verwendet werden, wenn es einen Submit-Button enthält (oder nur ein einzelnes Texteingabefeld, bei dem der Benutzer die Enter-Taste anstelle eines solchen Buttons zum Abschicken drücken kann). Bei JavaScript ist ein Submit-Button nie zwingend notwendig (obwohl er nützlich sein kann). Ein Formular kann in JavaScript eine beliebige Anzahl von Buttons mit Event-Handlern besitzen, die verschiedene Aktionen ausführen, wenn sie gedrückt werden (einschließlich des Abschickens eines Formulars). 1 Beispielsweise HTML – Das umfassende Referenzwerk von Chuck Musciano und Bill Kennedy (O’Reilly Verlag).
482 |
491-0.book Seite 483 Mittwoch, 4. April 2007 9:55 09
e-bol.net
18.1 Das Form-Objekt Das Form-Objekt in JavaScript entspricht einem HTML-Formular. Wie in Kapitel 15 erklärt wurde, sind Formularobjekte als Elemente des forms[]-Arrays zugänglich, das eine Eigenschaft des Document-Objekts ist. Die Formulare erscheinen in diesem Array in der gleichen Reihenfolge wie im Dokument. document.forms[0] verweist also auf das erste Formular in einem Dokument; auf das letzte Formular eines Dokuments können Sie wie folgt zugreifen: document.forms[document.forms.length-1]
Die interessanteste Eigenschaft des Form-Objekts ist das Array elements[]. Es enthält JavaScript-Objekte unterschiedlichen Typs, die die verschiedenen Eingabeelemente des Formulars darstellen. Auch diese Elemente erscheinen im Array in der gleichen Reihenfolge wie im Dokument. Sie können folgendermaßen auf das dritte Element des zweiten Formulars im Dokument des aktuellen Fensters zugreifen: document.forms[1].elements[2]
Die verbleibenden Eigenschaften des Form-Objekts sind weniger wichtig. Die Eigenschaften action, encoding, method und target entsprechen unmittelbar den Attributen action, encoding, method und target des -Tags. Diese Eigenschaften und Attribute werden verwendet, um das Versenden von Daten an den Webserver zu steuern und anzugeben, wo die Ergebnisse angezeigt werden sollen. Sie sind nur von Nutzen, wenn das Formular tatsächlich an ein serverseitiges Programm übergeben wird. Eine ausführliche Beschreibung dieser Attribute finden Sie in Büchern über HTML oder serverseitige Webprogrammierung. Beachtenswert ist, dass alle diese Eigenschaften von Formularen lesund schreibbare Strings sind, sodass ein JavaScript-Programm die Werte dynamisch zuweisen kann, um das Verfahren zu ändern, mit dem das Formular versandt wird. Früher, bevor es JavaScript gab, wurden Formulare mit einem speziellen Submit-Button abgesandt; auf ihren Anfangswert zurückgesetzt wurden die Formularelemente mit einem speziellen Reset-Button. Das Form-Objekt in JavaScript unterstützt nun zwei Methoden, submit( ) und reset( ), die demselben Zweck dienen. Durch den Aufruf der submit( )-Methode eines Formulars wird dieses abgeschickt, ein Aufruf von reset( ) setzt die Werte der Formularelemente zurück.
18.1 Das Form-Objekt |
483
clientseitiges JavaScript
Die Beispiele in diesem Buch zeigen auch, dass Event-Handler oft das zentrale Element eines JavaScript-Programms sind. Zu den gebräuchlichsten Event-Handlern zählen diejenigen, die bei Formularen oder Formularelementen verwendet werden. In diesem Kapitel werden das Form-Objekt von JavaScript sowie die verschiedenen JavaScript-Objekte für Formularelemente vorgestellt. Das Kapitel endet mit einem Beispiel, in dem JavaScript benutzt wird, um Eingaben eines Benutzers auf der Clientseite zu überprüfen, bevor das Formular an ein auf dem Webserver laufendes serverseitiges Programm geschickt wird.
491-0.book Seite 484 Mittwoch, 4. April 2007 9:55 09
e-bol.net Als Ergänzung der Methoden submit( ) und reset( ) stellt das Form-Objekt die EventHandler onsubmit und onreset bereit. Letzterer wird vor dem Zurücksetzen der Formularwerte aufgerufen. Der Event-Handler onsubmit wird aufgerufen, unmittelbar bevor das Formular abgesandt wird; er kann das Versenden verhindern, indem er den Wert false zurückgibt. Dadurch ist es einem JavaScript-Programm möglich, die Eingaben des Benutzers auf Fehler zu überprüfen und zu verhindern, dass unvollständige oder ungültige Daten über das Netz zu einem CGI-Programm geschickt werden. Sie werden ein Beispiel dafür am Ende dieses Abschnitts sehen. Beachten Sie, dass der Event-Handler onsubmit nur bei einem Klick auf den Button Submit aufgerufen wird. Wenn das Formular durch einen Aufruf der Methode submit( ) eines Formulars abgeschickt wird, wird der EventHandler nicht ausgelöst. Der Event-Handler onreset ähnelt onsubmit. Er wird aufgerufen, kurz bevor die Formulareinträge gelöscht werden, und kann die Löschung verhindern, indem er den Wert false zurückgibt. Dadurch kann ein JavaScript-Programm eine Bestätigung des Löschens verlangen, was insbesondere bei langen oder ausführlichen Formularen eine gute Idee sein kann. Sie können eine derartige Bestätigung mit einem Event-Handler wie dem folgenden verlangen:
Wie der Event-Handler onsubmit wird auch onreset nur durch den Reset-Button ausgelöst, nicht aber bei einem Aufruf der Methode reset( ).
18.2 Definition von Formularelementen Mit HTML-Formularelementen können Sie einfache Benutzerschnittstellen für Ihre JavaScript-Programme bauen. Abbildung 18-1 zeigt ein komplexes Formular, in dem mindestens eines der grundlegenden Formularelemente enthalten ist. Für den Fall, dass Sie nicht bereits mit HTML-Formularelementen vertraut sind, enthält das Formular eine Legende, in der die einzelnen Elemente benannt sind. Wir beenden diesen Abschnitt mit einem Beispiel (Beispiel 18-1), das den HTML- und den JavaScript-Code enthält, mit dem das Formular in Abbildung 18-1 erzeugt wurde, und in dem die Event-Handler an die Formularelemente gebunden werden. Tabelle 18-1 ist eine Zusammenstellung aller Formularelemente, die HTML-Designern und JavaScript-Programmierern zur Verfügung stehen. In der ersten Spalte finden Sie den Typ des Formularelements, in der zweiten die HTML-Tags, die zur Definition der Elemente verwendet werden. Die dritte Spalte enthält den Wert des Attributs type für jeden Typ von Formularelement. Wie bereits gezeigt, hat jedes Form-Objekt ein elements[]Array mit den Objekten, die die Elemente des Formulars repräsentieren. Jedes Element hat ein type-Attribut, um zwischen den verschiedenen Elementtypen zu unterscheiden.
484 | Kapitel 18: Formulare und Formularelemente
491-0.book Seite 485 Mittwoch, 4. April 2007 9:55 09
e-bol.net
clientseitiges JavaScript
Abbildung 18-1: HTML-Formularelemente
Indem es dieses Attribut untersucht, kann das JavaScript-Programm den Typ des Elements ermitteln und damit feststellen, was es mit diesem Element anfangen kann. Die vierte Spalte schließlich beschreibt die einzelnen Elemente kurz und nennt ihre am häufigsten benötigten Event-Handler. Beachten Sie, dass die Namen Button, Checkbox usw. in der ersten Spalte der Tabelle 18-1 nicht unbedingt einem tatsächlichen JavaScript-Objekt auf der Clientseite entsprechen. Die vollständigen Einzelheiten über die verschiedenen Elementtypen finden Sie in Teil IV unter den Einträgen Input, Option, Select und Textarea. Diese Formularelemente werden weiter unten in diesem Kapitel ausführlicher besprochen. Tabelle 18-1: HTML-Formularelemente Objekt
HTML-Tag
type-Attribut
Beschreibung und Events
Button
oder
"button"
Ein Button; onclick.
Checkbox
"checkbox"
Ein nicht-exklusiver Schalter; onclick.
File
"file"
Ein Eingabefeld für den Namen einer Datei, die auf einen Webserver geladen werden soll; onchange.
18.2 Definition von Formularelementen |
485
491-0.book Seite 486 Mittwoch, 4. April 2007 9:55 09
e-bol.net Tabelle 18-1: HTML-Formularelemente (Fortsetzung) Objekt
HTML-Tag
type-Attribut
Beschreibung und Events
Hidden
"hidden"
Für den Benutzer unsichtbare Daten, die mit dem Formular verschickt werden; keine Event-Handler.
Option
keine
Ein einzelnes Element innerhalb eines SelectObjekts; Event-Handler beziehen sich auf das Select-Objekt, nicht auf einzelne Option-Objekte.
Password
"password"
Ein Eingabefeld für Passwörter – die eingegebenen Zeichen werden nicht angezeigt; onchange.
Radio
"radio"
Ein exklusiver Schalter – nur einer kann ausgewählt werden; onclick.
Reset
oder
"reset"
Ein Button, mit dem ein Formular zurückgesetzt werden kann; onclick.
Select
"select-one"
Eine Liste oder ein Menü, aus der bzw. dem ein Eintrag ausgewählt werden kann; onchange. Siehe auch das Option-Objekt.
Select
"select-multiple"
Eine Liste, aus der mehrere Elemente ausgewählt werden können; onchange. Siehe auch das Option-Objekt.
Submit
oder
"submit"
Ein Button, mit dem ein Formular abgeschickt wird; onclick.
Text
"text"
Ein einzeiliges Texteingabefeld; onchange.
Textarea
"textarea"
Ein mehrzeiliges Texteingabefeld; onchange.
Nachdem wir uns die verschiedenen Typen von Formularelementen und die zu ihrer Erzeugung verwendeten HTML-Tags angesehen haben, wenden wir uns in Beispiel 18-1 dem HTML-Code zu, der das in Abbildung 18-1 abgebildete Formular erzeugt hat. Das Beispiel besteht hauptsächlich aus HTML-Code, enthält aber auch den JavaScript-Code, mit dem die Event-Handler für jedes Formularelement definiert werden. Beachten Sie, dass die Event-Handler nicht als HTML-Attribute definiert werden, sondern als JavaScript-Funktionen, die den Eigenschaften der Objekte im Array elements[] des Formulars zugewiesen werden. Alle Event-Handler rufen die Funktion protokolliere( ) auf, die Code enthält, der mit den verschiedenen Formularelementen funktioniert. Im nächsten Abschnitt erfahren Sie alles, was Sie wissen müssen, um die Funktionsweise der Funktion protokolliere( ) zu verstehen. Beispiel 18-1: Ein HTML-Formular, das sämtliche Formularelemente enthält
Benutzername:[1] name="benutzername" size="15">
name="passwort" size="15">
491-0.book Seite 487 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 18-1: Ein HTML-Formular, das sämtliche Formularelemente enthält (Fortsetzung)
// Diese generische Funktion protokolliert die Events in der großen Textarea // im obigen Formular. Sie wird von verschiedenen Event-Handlern aufgerufen.
18.2 Definition von Formularelementen |
487
491-0.book Seite 488 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 18-1: Ein HTML-Formular, das sämtliche Formularelemente enthält (Fortsetzung) function protokolliere(element, event) { if ((element.type == "select-one") || (element.type == "select-multiple")){ wert = " "; for(var i = 0; i < element.options.length; i++) if (element.options[i].selected) wert += element.options[i].value + " "; } else if (element.type == "textarea") wert = "..."; else wert = element.value; var msg = event + ": " + element.name + ' (' + value + ')\n'; var t = element.form.textarea; t.value = t.value + msg; } // Diese Funktion gibt jedem Element des Formulars ein paar Event-Handler. // Sie kümmert sich nicht darum, ob das Element den Event-Handler unterstützt. // Sie fügt einfach alle hinzu. // Jeder Handler ruft die Funktion protokolliere() auf. // Wir definieren die Event-Handler, indem wir den Eigenschaften von // JavaScript-Objekten Funktionen zuweisen, anstatt den Attributen von // HTML-Elementen Strings zuzuweisen. function definiereHandler(f) { // Durchlaufe alle Elemente des Formulars for(var i = 0; i < f.elements.length; i++) { var e = f.elements[i]; e.onclick = function( ) { protokolliere(this, 'Click'); } e.onchange = function( ) { protokolliere(this, 'Change'); } e.onfocus = function( ) { protokolliere(this, 'Focus'); } e.onblur = function( ) { protokolliere(this, 'Blur'); } e.onselect = function( ) { protokolliere(this, 'Select'); } } // Definiere spezielle Handler für die drei Buttons: f.loeschbutton.onclick = function( ) { this.form.textarea.value=''; protokolliere(this,'Click'); } f.submitbutton.onclick = function ( ) { protokolliere(this, 'Click'); return false; } f.resetbutton.onclick = function( ) { this.form.reset( ); protokolliere(this, 'Click'); return false; } } // Wir aktivieren das Formular, indem wir alle möglichen Handler definieren! definiereHandler(document.alles);
488 | Kapitel 18: Formulare und Formularelemente
491-0.book Seite 489 Mittwoch, 4. April 2007 9:55 09
e-bol.net
18.3 Formularelemente skripten
18.3.1 Formulare und Formularelemente benennen Jedes Formularelement besitzt ein name-Attribut, das im HTML-Tag definiert werden muss, wenn das Formular an ein serverseitiges Programm übergeben werden soll. Wenn auch das Versenden von Formularen für JavaScript-Programme nicht unbedingt fürchterlich interessant ist, gibt es einen anderen Grund dafür, dieses name-Attribut anzugeben, wie wir bald sehen werden. Das -Tag besitzt ebenfalls ein Attribut name, das Sie angeben können. Dieses Attribut hat nichts mit dem Verschicken von Formularen zu tun; wie bereits in Kapitel 15 beschrieben, existiert es, um JavaScript-Programmierern die Arbeit zu erleichtern. Wird ein benanntes Formular erzeugt, indem für ein -Tag das name-Attribut vergeben wird, so wird dieses wie gewöhnlich im Array forms[] des Document-Objekts gespeichert. Zusätzlich wird jedoch eine neue Eigenschaft des Document-Objekts erzeugt, die den durch das name-Attribut angegebenen Namen erhält. In Beispiel 18-1 wurde beispielsweise ein Formular mit diesem Tag definiert:
Dadurch können Sie wie folgt auf das Formular zugreifen: document.alles
Dies ist häufig angenehmer als die Array-Schreibweise: document.forms[0]
Außerdem wird Ihr Programm durch die Benennung des Formulars positionsunabhängig: Es funktioniert auch, wenn das Dokument umstrukturiert wird und die enthaltenen Formulare dadurch in eine andere Reihenfolge gebracht werden. Tags wie und besitzen ebenfalls alle ein Attribut name, das in der gleichen Weise funktioniert wie das Attribut name des -Tags. Diese Art der Benennung geht bei Formularen jedoch noch einen Schritt weiter, da alle in Formularen enthaltenen Elemente ein name-Attribut besitzen. Wenn Sie einem Formularelement einen Namen zuweisen, erzeugen Sie eine neue Eigenschaft des Form-Objekts, die auf dieses Element verweist. Der Name dieser Eigenschaft entspricht dem Wert des Attributs. Sie können also beispielsweise auf ein Element »plz« in einem Formular namens »adresse« folgendermaßen zugreifen: document.adresse.plz
18.3 Formularelemente skripten |
489
clientseitiges JavaScript
Im letzten Abschnitt wurden alle von HTML bereitgestellten Formularelemente beschrieben, und es wurde gezeigt, wie sie in HTML-Dokumente eingebettet werden. Dieser Abschnitt geht einen Schritt weiter und zeigt, wie Sie mit diesen Elementen in Ihren JavaScript-Programmen arbeiten können.
491-0.book Seite 490 Mittwoch, 4. April 2007 9:55 09
e-bol.net Wenn die Namen vernünftig gewählt werden, ist diese Schreibweise viel eleganter als die Variante, die auf fest eingebaute (und positionsabhängige) Array-Indizes zugreift: document.forms[1].elements[4]
Damit in einem HTML-Formular in einer Gruppe von sogenannten Radio-Buttons jeweils nur ein Schalter gedrückt sein kann, müssen diese alle denselben Namen tragen. In Beispiel 18-1 werden beispielsweise drei solcher Schalter definiert, deren Attribut name den Wert »browser« trägt. Bei nicht-exklusiven Schaltern, sogenannten Checkboxes, ist eine gleiche Benennung innerhalb einer Gruppe zwar nicht notwendig, aber durchaus üblich. Haben mehrere Elemente in einem Formular das gleiche name-Attribut, dann stellt JavaScript diese Elemente einfach in ein Array mit dem angegebenen Namen. Die Elemente stehen in diesem Array in der gleichen Reihenfolge, wie sie im Dokument erscheinen. In Beispiel 18-1 können Sie auf die Radio-Buttons daher wie folgt zugreifen: document.alles.browser[0] document.alles.browser[1] document.alles.browser[2]
18.3.2 Eigenschaften von Formularelementen Alle (oder zumindest die meisten) Formularelemente besitzen die folgenden Eigenschaften. Manche Elemente habe weitere spezielle Eigenschaften, die weiter unten in diesem Kapitel beschrieben werden, genauer gesagt dort, wo die verschiedenen Arten von Formularelementen einzeln behandelt werden: type
Ein nur-lesbarer String, der den Typ des Formularelements angibt. Die dritte Spalte in Tabelle 18-1 führt für jedes Formularelement den Wert dieser Eigenschaft auf. form
Eine nur-lesbare Referenz auf das Form-Objekt, in dem das Element enthalten ist. name
Ein nur-lesbarer String, der durch das HTML-Attribut name angegeben wurde. value
Ein les- und schreibbarer String, der den im Formularelement enthaltenen bzw. von ihm dargestellten Wert enthält. Dieser String wird an den Webserver übergeben, wenn das Formular abgeschickt wird; er ist nur manchmal für JavaScript-Programme interessant. Bei Text- und Textarea-Elementen enthält diese Eigenschaft den vom Benutzer eingegebenen Text. Bei Buttons gibt sie den Text an, der auf dem Button angezeigt werden soll; manchmal werden Sie diesen Text durch ein Skript ändern wollen. Bei Radio- und Checkbox-Elementen dagegen wird die value-Eigenschaft im Allgemeinen nicht bearbeitet und dem Benutzer auch nicht angezeigt. Sie enthält einfach nur einen String, der durch das HTML-Attribut value angegeben wird; dies wird an den Webserver übergeben, wenn das Dokument abgeschickt
490 | Kapitel 18: Formulare und Formularelemente
491-0.book Seite 491 Mittwoch, 4. April 2007 9:55 09
e-bol.net wird. Die value-Eigenschaft wird in den Abschnitten über die unterschiedlichen Kategorien von Formularelementen weiter unten in diesem Kapitel ausführlicher besprochen.
18.3.3 Event-Handler von Formularelementen onclick
Wird ausgelöst, wenn der Benutzer das Element mit der Maus anklickt. Dieser EventHandler ist insbesondere für Buttons und verwandte Formularelemente nützlich. onchange
Wird ausgelöst, wenn der Benutzer den von dem Element dargestellten Wert beispielsweise durch Eingabe von Text oder Auswahl einer Option verändert. Buttons und ähnliche Elemente unterstützen diesen Event-Handler üblicherweise nicht, da sie keinen bearbeitbaren Wert besitzen. Beachten Sie, dass dieser Handler nicht sofort aufgerufen wird, wenn der Benutzer z.B. ein Zeichen in ein Textfeld eingibt. Er wird erst dann ausgelöst, wenn der Benutzer den Wert eines Elements ändert und anschließend den Eingabefokus an ein anderes Formularelement weitergibt. Der Aufruf dieses Event-Handlers signalisiert also eine abgeschlossene Änderung. onfocus
Wird ausgelöst, wenn das Formularelement den Eingabefokus erhält. onblur
Wird ausgelöst, wenn das Formularelement den Eingabefokus verliert. Beispiel 18-1 definierte Event-Handler für Formularelemente, indem die Event-HandlerEigenschaft auf eine JavaScript-Funktion gesetzt wurde. Das Beispiel ist so ausgelegt, dass auftretende Events in einem großen Textarea-Element protokolliert werden. Sie können mit diesem Formular experimentieren, um herauszufinden, welches Formularelement wann welchen Event-Handler auslöst. Wichtig ist, dass sich das Schlüsselwort this innerhalb des Codes eines Event-Handlers auf das Element eines Dokuments bezieht, das das Event ausgelöst hat. Da jedes Formularelement eine Eigenschaft form besitzt, die sich auf das umgebende Formular bezieht, können die Event-Handler eines Elements immer mit this.form auf das Form-Objekt zugreifen. Einen Schritt weiter gedacht bedeutet dies, dass ein Formularelement auf ein benachbartes Formularelement namens x mit dem Ausdruck this.form.x zugreifen kann. Beachten Sie, dass die vier genannten Event-Handler für Formularelemente die für diese Elemente wichtigsten sind. Darüber hinaus unterstützen Formularelemente weitere Event-Handler (wie beispielsweise onmousedown), die von nahezu allen HTML-Elementen unterstützt werden. In Kapitel 17 werden Events und Event-Handler in allen Einzelheiten beschrieben. Beispiel 17-5 in diesem Kapitel zeigt die Verwendung von Tastatur-EventHandlern mit Formularelementen.
18.3 Formularelemente skripten |
491
clientseitiges JavaScript
Die meisten Formularelemente unterstützen fast alle der folgenden Event-Handler:
491-0.book Seite 492 Mittwoch, 4. April 2007 9:55 09
e-bol.net
18.3.4 Button-Schaltflächen Das Button-Formularelement ist eines der am häufigsten verwendeten Elemente, da es dem Benutzer deutlich zeigt, dass er hiermit eine Aktion auslösen kann. Das Button-Element besitzt zunächst kein eigenes vordefiniertes Verhalten und ist daher in einem Formular nur dann von Nutzen, wenn es einen onclick-Event-Handler (oder einen anderen) besitzt. Die Eigenschaft value eines Button-Elements gibt an, welcher Text auf dem Button erscheinen soll. Sie können dieser Eigenschaft einen Wert (nur einfachen Text, kein HTML) zuweisen, um den Wert zu ändern, der auf dem Button angezeigt werden soll. Dies kann mitunter nützlich sein. Beachten Sie, dass Hypertext-Verweise ebenfalls den Event-Handler onclick unterstützen und jedes Button-Objekt durch einen Verweis ersetzt werden kann, der die gleiche Aktion auslöst, wenn er angeklickt wird. Verwenden Sie einen Button, wenn das Element wie ein solcher aussehen soll; einen Link sollten Sie verwenden, wenn sich der Benutzer die durch den onclick-Handler ausgelöste Aktion eher wie das Verfolgen eines Links vorstellen soll. Die Elemente Submit und Reset gleichen Button-Elementen, besitzen jedoch vordefinierte Aktionen, nämlich das Absenden bzw. Zurücksetzen eines Formulars. Daher können diese Elemente auch ohne einen onclick-Event-Handler nützlich sein. Andererseits sind sie genau aus diesem Grund in Formularen, die an einen Webserver geschickt werden sollen, hilfreicher als in reinen clientseitigen JavaScript-Programmen. Wenn der Event-Handler onclick den Wert false zurückgibt, wird die vordefinierte Aktion nicht ausgeführt. Sie können den onclick-Handler eines Submit-Elements verwenden, um ein Formular vor dem Versenden auf Korrektheit zu überprüfen; es ist jedoch üblich, diese Aufgabe vom onsubmit-Handler des Form-Objekts erledigen zu lassen. Sie können Button-Schaltflächen, einschließlich Submit- und Reset-Buttons, mit dem Tag statt des traditionellen -Tags erstellen. Das -Tag ist flexibler, da es nicht nur einfachen Text anzeigen kann, der als Wert des Attributs value angegeben wird, sondern auch beliebigen HTML-Inhalt (formatierten Text sowie Bilder), der zwischen den Tags und angegeben wird. Das -Tag kann an einer beliebigen Stelle in einem HTML-Dokument verwendet werden und muss nicht in einem -Tag stehen. Die durch das -Tag erzeugten Buttons unterscheiden sich technisch von solchen, die durch das Tag erzeugt wurden, besitzen jedoch im Feld type denselben Wert und verhalten sich auch ansonsten weitestgehend gleich. Der Hauptunterschied besteht darin, dass Sie das Aussehen eines mit dem -Tag erzeugten Buttons nicht durch Zuweisung eines Werts an die Eigenschaft value ändern können, da das Attribut value für das Aussehen des Buttons keine Rolle spielt.
492 | Kapitel 18: Formulare und Formularelemente
491-0.book Seite 493 Mittwoch, 4. April 2007 9:55 09
e-bol.net Teil IV enthält keinen Eintrag für Button. Einzelheiten zu allen Formularelement-Schaltflächen, einschließlich derjenigen, die mit dem -Tag erzeugt werden, finden Sie unter dem Eintrag Input.
18.3.5 Schalter
document.alles.extras
Um auf ein einzelnes Checkbox-Element zu verweisen, indizieren Sie das Array: document.alles.extras[0]
// Das erste Formularelement names "extras"
Sowohl Radio- als auch Checkbox-Elemente definieren eine Eigenschaft checked. Dies ist ein les- und schreibbarer Boolescher Wert, der angibt, ob das Element derzeit ausgewählt ist. Die Eigenschaft defaultChecked ist ein Boolescher Wert; sie enthält den Wert des HTML-Attributs checked und gibt an, ob das Element beim erstmaligen Laden der Seite ausgewählt ist. Radio- und Checkbox-Elemente zeigen selbst keinen Text an; sie werden meist neben HTML-Text gesetzt (oder mit einem -Tag versehen). Daher können Sie das Aussehen eines Checkbox- oder Radio-Elements nicht dadurch ändern, dass Sie seine valueEigenschaft setzen. Das geht nur bei Button-Elementen, die mit einem -Tag erzeugt wurden. Sie können value einen Wert zuweisen; dadurch ändern Sie jedoch nur den String, der beim Abschicken des Formulars an den Webserver versandt wird. Wenn der Benutzer einen solchen Schalter anklickt, löst das Radio- oder Checkbox-Element seinen Event-Handler onclick aus, um das JavaScript-Programm von der Zustandsänderung zu benachrichtigen. Neuere Webbrowser lösen bei diesen Elementen außerdem den onchange-Handler aus. Beide Event-Handler stellen also die gleiche Information bereit; der onclick-Handler funktioniert jedoch auch in älteren Browsern.
18.3 Formularelemente skripten |
493
clientseitiges JavaScript
Die Elemente Checkbox und Radio sind Schalter, die zwei visuell unterscheidbare Zustände besitzen: Sie können ausgewählt sein oder nicht. Der Benutzer kann den Zustand eines solchen Schalters ändern, indem er ihn anklickt. Radio-Elemente sind dazu gedacht, in Gruppen verwandter Elemente benutzt zu werden, deren HTML-Attribut name denselben Wert besitzt. Auf diese Weise erzeugte Radio-Elemente schließen sich gegenseitig aus, d.h., es kann immer nur eines von ihnen ausgewählt sein – ähnlich den Stationstasten eines Radios. Checkbox-Elemente werden ebenfalls häufig in Gruppen verwendet, die ein gemeinsames Attribut name besitzen. Wenn Sie auf diese Elemente über ihren Namen zugreifen, müssen Sie daran denken, dass Sie auf ein Array gleichnamiger Elemente zugreifen. Beispiel 18-1 enthält drei Checkbox-Elemente mit dem Namen »extras«. Sie können auf ein Array mit diesen Elementen folgendermaßen zugreifen:
491-0.book Seite 494 Mittwoch, 4. April 2007 9:55 09
e-bol.net
18.3.6 Textfelder Das Text-Element ist vermutlich das am häufigsten in HTML-Formularen und JavaScript-Programmen verwendete Element. Es ermöglicht dem Benutzer die Eingabe eines kurzen, einzeiligen Texts. Die value-Eigenschaft stellt den vom Benutzer eingegebenen Text dar. Sie können dieser Eigenschaft einen Wert zuweisen, der in dem Feld angezeigt werden soll. Der Event-Handler onchange wird ausgelöst, wenn der Benutzer neuen Text eingibt oder den vorhandenen Text bearbeitet und das Ende der Bearbeitung dadurch anzeigt, dass er den Eingabefokus aus dem Textfeld entfernt. Das Element Textarea ähnelt dem Text-Element, ermöglicht dem Benutzer jedoch die Eingabe von Text in mehreren Zeilen (und Ihrem JavaScript-Programm entsprechend die Ausgabe von mehrzeiligem Text). Textarea-Elemente werden mit dem Tag erzeugt. Die Syntax dieses Tags unterscheidet sich wesentlich von der des -Tags, das Text-Elemente erzeugt. (Vergleiche den Textarea-Eintrag in Teil IV.) Trotzdem verhalten sich die beiden Elementtypen recht ähnlich. Sie können die value-Eigenschaft und den onchange-Event-Handler eines Textarea-Elements genauso verwenden, wie Sie dies bei einem Text-Element tun. Das Element Password ist ein modifiziertes Text-Element, das Sterne anzeigt, wenn der Benutzer hier etwas eingibt. Wie der Name andeutet, ist dieser Typ nützlich, wenn der Benutzer ein Passwort eingeben soll, ohne dass jemand dieses vom Bildschirm ablesen kann. Beachten Sie, dass das Password-Element die Eingabe des Benutzers vor neugierigen Augen verbirgt; wenn das Formular jedoch verschickt wird, werden diese Daten in keiner Weise verschlüsselt (es sei denn, sie werden über eine sichere HTTPS-Verbindung versandt), sodass sie während der Übertragung ausspioniert werden können. Das File-Element schließlich dient dazu, den Benutzer den Namen einer Datei eingeben zu lassen, die auf einen Webserver übertragen werden soll. Es handelt sich dabei im Wesentlichen um ein Text-Element, das mit einem Button kombiniert wurde, über den ein Dialog zur Dateiauswahl geöffnet wird. File besitzt wie Text-Elemente einen EventHandler onchange. Im Gegensatz zu Text-Elementen kann die value-Eigenschaft eines file-Elements jedoch nur gelesen werden. Dadurch wird verhindert, dass bösartige JavaScript-Programme den Benutzer dazu bringen, Dateien zu übertragen, die nicht für die Öffentlichkeit bestimmt sind. Das W3C hat bisher noch keinen Standard für Event-Handler oder Event-Objekte für die Tastatureingabe definiert. Trotzdem definieren moderne Browser die Event-Handler onkeypress, onkeydown und onkeyup. Diese Handler können für beliebige DocumentObjekte angegeben werden, sind aber am nützlichsten, wenn sie bei Text- und ähnlichen Formularelementen angegeben werden, die tatsächlich Tastatureingaben akzeptieren. Die Event-Handler onkeypress und onkeydown können den Wert false zurückgeben, damit die vom Benutzer gedrückte Taste nicht angezeigt wird. Das kann z.B. dann sinnvoll sein, wenn Sie den Benutzer zwingen wollen, nur Zahlen in ein bestimmtes Texteingabefeld einzugeben. Beispiel 17-5 veranschaulicht diese Technik.
494 | Kapitel 18: Formulare und Formularelemente
491-0.book Seite 495 Mittwoch, 4. April 2007 9:55 09
e-bol.net
18.3.7 Select- und Option-Elemente
Ein mit »select-multiple« versehenes Element ähnelt einer Gruppe von Checkbox-Elementen, ein mit »select-one« versehenes Element einer Gruppe von Radio-Elementen. Das Select-Element unterscheidet sich von den Schaltern dadurch, dass ein einzelnes Select-Element eine ganze Menge von Optionen darstellt, die in HTML durch das -Tag angegeben werden und in JavaScript durch Option-Objekte repräsentiert werden, die im Array options[] des Select-Elements gespeichert sind. Da ein Select-Element eine Auswahl zwischen verschiedenen Werten ermöglicht, besitzt es im Gegensatz zu allen anderen Formularelementen keine Eigenschaft value. Wie wir gleich sehen werden, definieren vielmehr die im Select-Element enthaltenen Option-Objekte jeweils eine Eigenschaft value. Wenn der Benutzer eine Option auswählt oder abwählt, löst das Select-Element seinen Event-Handler onchange aus. Bei mit »select-one« versehenen Elementen gibt die les- und schreibbare selectedIndex-Eigenschaft die Nummer der derzeit ausgewählten Option an. Bei mit »select-multiple« versehenen Elementen reicht die einfache Eigenschaft selectedIndex nicht aus, um eine ganze Menge von ausgewählten Optionen darzustellen. Um in diesem Fall herausfinden zu können, welche Optionen ausgewählt sind, müssen Sie die Elemente des options[]-Arrays durchlaufen und die selected-Eigenschaft eines jeden Option-Objekts betrachten. Zusätzlich zu seiner selected-Eigenschaft besitzt das Option-Element eine text-Eigenschaft, die den (einfachen) Text angibt, der in dem Select-Element für diese Option angezeigt werden soll. Sie können dieser Eigenschaft einen Wert zuweisen, um den angezeigten Text zu ändern. Die value-Eigenschaft ist ebenfalls ein les- und schreibbarer String; er gibt den Text an, der beim Versenden des Formulars an den Webserver geschickt werden soll. Auch wenn Sie ein ausschließlich auf der Clientseite laufendes Programm schreiben und Ihr Formular niemals abgeschickt wird, kann die Eigenschaft value (bzw. das ihr entsprechende HTML-Attribut value) ein guter Ort für die Speicherung von Daten sein, die Sie benötigen, wenn der Benutzer eine bestimmte Option auswählt. Beachten Sie, dass das Option-Element keine Event-Handler definiert, die sich auf das Formular beziehen; dafür ist der Event-Handler onchange des umgebenden Select-Elements zuständig.
18.3 Formularelemente skripten |
495
clientseitiges JavaScript
Das Select-Element stellt eine (durch Option-Elemente repräsentierte) Auswahlliste dar, aus der sich der Benutzer bedienen kann. Die meisten Browser zeigen Select-Elemente in einem Menü oder einer Listbox an. Ein Select-Element kann eine von zwei sehr unterschiedlichen Funktionen wahrnehmen, die durch den Wert der Eigenschaft type festgelegt wird. Wenn das -Tag das multiple-Attribut besitzt, kann der Benutzer mehrere Optionen auswählen; die type-Eigenschaft besitzt in diesem Fall den Wert »select-multiple«. Ist dieses Attribut nicht vergeben, kann nur ein einzelnes Element gewählt werden; die Eigenschaft type besitzt dann den Wert »select-one«.
491-0.book Seite 496 Mittwoch, 4. April 2007 9:55 09
e-bol.net Die in einem Select-Element angezeigten Optionen können Sie außer durch Zuweisung eines Werts an die text-Eigenschaft eines Option-Objekts auch auf andere Weise dynamisch ändern. Sie können das Array der Option-Elemente kürzen, indem Sie options. length auf die gewünschte Anzahl von Optionen setzen, und Sie können alle OptionObjekte entfernen, indem Sie options.length auf 0 setzen. Nehmen wir an, Sie haben ein Select-Objekt namens »land« in einem Formular namens »adresse«. Sie können dann alle Optionen dieses Elements mit folgender Programmzeile entfernen: document.adresse.land.options.length = 0;
// Entferne alle Optionen
Sie können ein einzelnes Option-Objekt aus dem Select-Element entfernen, indem Sie an seine Stelle im Array options[] den Wert null schreiben. Dadurch wird das OptionObjekt gelöscht; die Optionen, die sich weiter hinten befinden, rutschen nach, um den leeren Platz zu füllen. // Entferne ein einzelnes Option-Objekt aus dem Select-Element. // Die zuvor in options[11] gespeicherte Option wird nun nach // options[10] verschoben ... document.adresse.land.options[10] = null;
Vergleichen Sie den Option-Eintrag in Teil IV. Vergleichen Sie ebenfalls Select.add( ) als Alternative für das Hinzufügen neuer Optionen in DOM Level 2. Das Option-Element definiert außerdem einen Konstruktor Option( ), den Sie verwenden können, um neue Option-Elemente dynamisch zu erzeugen. Diese können Sie an ein Select-Element anhängen, indem Sie sie an das Ende des Arrays options[] anfügen: Beispielsweise: // Erzeuge ein neues Option-Objekt var zaire = new Option("Zaire", // "zaire", // false, // false); //
Die Die Die Die
Eigenschaft Eigenschaft Eigenschaft Eigenschaft
text value defaultSelected selected
// Zeige das Objekt im Select-Element durch Anhängen an das options-Array an: var laender = document.adress.land; // Beschaffe das Select-Objekt laender.options[laender.options.length] = zaire;
Sie können das Tag verwenden, um eine Gruppe zusammenhängender Optionen innerhalb eines Select-Elements zusammenzufassen. Dieses Tag besitzt ein Attribut label, das den Text festlegt, der im Select-Element angezeigt werden soll. Obwohl sie angezeigt werden, können -Tags nicht vom Benutzer ausgewählt werden; Objekte, die sich auf das -Tag beziehen, werden außerdem nicht in das options[]-Array eingefügt.
18.3.8 Versteckte Elemente Wie der Name schon sagt, werden versteckte Elemente vom Typ Hidden in Formularen nicht angezeigt. Sie ermöglichen den Versand eines beliebigen Texts an den Server und
496 | Kapitel 18: Formulare und Formularelemente
491-0.book Seite 497 Mittwoch, 4. April 2007 9:55 09
e-bol.net
18.3.9 Fieldset-Elemente Zusätzlich zu den oben beschriebenen aktiven Formularelementen können HTML-Formulare auch - und -Tags beinhalten. Diese Tags können für Webdesigner wichtig sein, sind aber unter Skriptsteuerungsgesichtspunkten nicht so interessant, und clientseitige JavaScript-Programmierer verwenden sie normalerweise nicht. Sie müssen sich mit -Tags nur auskennen, weil durch die Aufnahme eines solchen Elements in ein Formular ein entsprechendes Objekt zum elements[]-Array des Formulars hinzugefügt wird. (Das geschieht bei -Tags allerdings nicht). Im Gegensatz zu allen anderen Objekten im elements[]-Array hat das Objekt, das das -Tag repräsentiert, keine type-Eigenschaft. Das kann bei Code, der eine solche Eigenschaft erwartet, problematisch sein.
18.4 Ein Beispiel zur Überprüfung von Formularen Ich schließe die Besprechung von Formularen mit einem ausführlichen Beispiel, das zeigt, wie Sie unauffälliges clientseitiges JavaScript zur Formularüberprüfung verwenden können.2 Beispiel 18-3, das uns später begegnet, ist ein Modul mit unauffälligem JavaScript-Code, der eine automatische clientseitige Formularüberprüfung ermöglicht. Um das Beispiel zu verwenden, fügen Sie es einfach in Ihre HTML-Seite ein, definieren einen CSS-Style, um die Formularfelder zu markieren, bei denen die Überprüfung fehlschlägt, und fügen dann zusätzliche Attribute zu Ihren Formularfeldern hinzu. Um den Benutzer zum Ausfüllen eines Felds zu zwingen, geben Sie dem Feld einfach ein required-Attribut. Um sicherzustellen, dass die Benutzereingabe einem regulären Ausdruck entspricht, setzen Sie das pattern-Attribut auf die gewünschte Regexp. Beispiel 18-2 zeigt, wie Sie dieses Modul verwenden können, und Abbildung 18-2 zeigt, was passiert, wenn Sie versuchen, ein Formular mit einer ungültigen Eingabe einzureichen.
2 Denken Sie daran, dass die Formularüberprüfung auf der Clientseite nur der Bequemlichkeit der Benutzer dient: Durch sie können Eingabefehler festgestellt werden, bevor ein Formular an den Server übergeben wird. Es gibt aber keine Garantie dafür, dass die Validierung auf der Clientseite stattfindet, da manche Benutzer JavaScript deaktiviert haben. Außerdem kann ein böswilliger Benutzer die Überprüfung auf der Clientseite auf einfache Art untergraben. Aus diesen Gründen ist die Validierung auf der Clientseite nie ein Ersatz für eine robuste Überprüfung auf der Serverseite.
18.4 Ein Beispiel zur Überprüfung von Formularen |
497
clientseitiges JavaScript
werden von serverseitigen Programmen dazu verwendet, Zustandsinformationen zu speichern, die sie mit dem Formular zurückgeschickt bekommen. Da versteckte Elemente nicht angezeigt werden, können sie keine Events erzeugen und besitzen keine EventHandler. Mit der Eigenschaft value können Sie den zu einem solchen Element gehörigen Text lesen und schreiben; abgesehen davon werden diese Elemente in der clientseitigen JavaScript-Programmierung jedoch selten verwendet.
491-0.book Seite 498 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 18-2: Eine Formularüberprüfung zu Ihren HTML-Formularen hinzufügen /* * Validate.js verlangt von uns die Definition von Styles für die "invalid"-Klasse, damit * ungültige Felder eine auffällige Erscheinung haben, die der Benutzer erkennt. * Optional können wir auch Styles für gültige Felder definieren. */ input.invalid { background: #faa; } /* Rötlicher Hintergrund für ungültige Felder */ input.valid { background: #afa; } /* Grünlicher Hintergrund für gültige Felder */ Name: E-mail: Postleitzahl: Nicht validiert:
Abbildung 18-2: Ein Formular, das durch die Überprüfung fiel
Beispiel 18-3 ist der Code für das Formularüberprüfungsmodul. Durch die Aufnahme dieses Moduls in eine HTML-Datei werden dem globalen Namensraum keine Symbole
498 | Kapitel 18: Formulare und Formularelemente
491-0.book Seite 499 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Beispiel 18-3: Automatische Formularüberprüfung mit unauffälligem JavaScript /** * Validate.js: Unauffällige HTML-Formularüberprüfung. * * Beim Ladevorgang des Dokuments scannt dieses Modul das Dokument nach HTML-Formularen und * Text-Formularelementen. Findet es Elemente mit "required"- oder * "pattern"-Attributen, so fügt es entsprechende Event-Handler für die * Formularüberprüfung auf der Clientseite an. * * Hat ein Formularelement ein "pattern"-Attribut, dann wird der Wert dieses Attributs * in JavaScript als regulärer Ausdruck interpretiert und das Element erhält einen * onchange-Event-Handler, der die Benutzereingabe mit dem Muster vergleicht. * Falls die Eingabe nicht mit dem Muster übereinstimmt, ändert sich die Hintergrundfarbe des * Eingabeelements, damit der Benutzer auf den Fehler aufmerksam wird. * Als Default muss der Wert des Textfeldes einen Substring enthalten, der mit * dem Muster übereinstimmt. Wenn Sie eine genaue Übereinstimmung des ganzen Werts verlangen, * verwenden Sie die Anker ^ und $ am Anfang und Ende des Musters. * * Ein Formularelement mit einem "required"-Attribut muss einen Wert haben. * Das Vorhandensein von "required" ist eine Abkürzung für pattern="\S". Das heißt, es wird * verlangt, dass der Wert ein beliebiges Zeichen enthält, das kein Whitespace ist. * * Wenn ein Formularelement die Überprüfung erfolgreich besteht, wird sein "class"-Attribut * auf "valid" gesetzt. Wenn es die Überprüfung nicht besteht, wird seine Klasse auf * "invalid" gesetzt. * Damit dieses Modul sinnvoll ist, müssen Sie es in Kombination mit * einem CSS-Stylesheet verwenden, das Styles für die "invalid"-Klasse definiert. * Beispielsweise: * * * input.invalid { background: #fa0; } * * Wird ein Formular abgesendet, werden die zu überprüfenden Textfeld-Elemente * noch einmal überprüft. Wenn die Überprüfung fehlschlägt, wird die Übermittlung blockiert, * und dem Benutzer wird ein Dialogfeld angezeigt, das über die Unvollständigkeit oder * Unrichtigkeit des Formulars informiert. *
3 Als dieses Buch geschrieben wurde, behinderte das AutoFill-Feature der Google-Werkzeugleiste die Verwendung von CSS-Styles zum Setzen des Hintergrunds bestimmter Textfelder. Die Browsererweiterung von Google setzt den Hintergrund des Textfeldes auf Hellgelb, um anzuzeigen, dass Werte eventuell automatisch in das Feld eingegeben werden können.
18.4 Ein Beispiel zur Überprüfung von Formularen |
499
clientseitiges JavaScript
hinzugefügt. Das Modul registriert automatisch einen onload-Event-Handler, der alle Formulare im Dokument durchläuft, nach den Attributen required und pattern sucht und je nach Bedarf die Handler onchange und onsubmit hinzufügt. Diese Event-Handler setzen die className-Eigenschaft jedes von ihnen überprüften Formularfelds auf »invalid« oder »valid«. Mit CSS sollten Sie zumindest das Erscheinungsbild der »invalid«-Klasse auffällig gestalten.3
491-0.book Seite 500 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 18-3: Automatische Formularüberprüfung mit unauffälligem JavaScript (Fortsetzung) * Sie können das Modul nicht für die Überprüfung von Formularfeldern oder Formularen * verwenden, an denen Sie Ihre eigenen onchange- oder onsubmit-Event-Handler definieren, * oder an Feldern, für die Sie ein class-Attribut definieren. * * Dieses Modul setzt seinen gesamten Code in eine anonyme Funktion und * definiert keine Symbole im globalen Namensraum. */ (function( ) { // Mache alles in dieser einen anonymen Funktion // Rufe nach dem Laden init( ) auf if (window.addEventListener) window.addEventListener("load", init, false); else if (window.attachEvent) window.attachEvent("onload", init); // Definiere Event-Handler für die Formulare und Formularelemente, die sie brauchen. function init( ) { // Durchlaufe alle Formulare im Dokument for(var i = 0; i < document.forms.length; i++) { var f = document.forms[i]; // das Formular, an dem wir gerade arbeiten // Nehmen wir zunächst an, dass das Formular keine Überprüfung braucht var needsValidation = false; // Durchlaufe jetzt die Elemente in unserem Formular for(j = 0; j < f.elements.length; j++) { var e = f.elements[j]; // das Element, das wir gerade bearbeiten // Uns interessieren nur -Textfelder if (e.type != "text") continue; // Prüfe, ob es Attribute hat, die validiert werden müssen var pattern = e.getAttribute("pattern"); // Wir könnten e.hasAttribute( ) verwenden, aber IE unterstützt das nicht var required = e.getAttribute("required") != null; // Required ist eine Abkürzung für ein einfaches Muster if (required && !pattern) { pattern = "\\S"; e.setAttribute("pattern", pattern); } // Wenn dieses Element überprüft werden muss, if (pattern) { // dann überprüfe das Element nach jeder Änderung e.onchange = validateOnChange; // Denke daran, einen onsubmit-Handler zu diesem Formular hinzuzufügen needsValidation = true; } }
500 | Kapitel 18: Formulare und Formularelemente
491-0.book Seite 501 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 18-3: Automatische Formularüberprüfung mit unauffälligem JavaScript (Fortsetzung) // Wenn mindestens eines der Formularelemente überprüft werden muss, // brauchen wir auch einen onsubmit-Event-Handler für das Formular if (needsValidation) f.onsubmit = validateOnSubmit; } }
clientseitiges JavaScript
// Diese Funktion ist der onchange-Event-Handler für Textfelder, die // überprüft werden müssen. Beachte, dass wir das required-Attribut // in init( ) zu einem pattern-Attribut konvertiert haben. function validateOnChange( ) { var textfield = this; // das Textfeld var pattern = textfield.getAttribute("pattern"); // das Muster var value = this.value; // die Benutzereingabe // Stimmt dieser Wert nicht mit dem Muster überein, setze die Klasse zu "invalid". if (value.search(pattern) == -1) textfield.className = "invalid"; else textfield.className = "valid"; } // Diese Funktion ist der onsubmit-Event-Handler für ein beliebiges Formular, // das überprüft werden muss. function validateOnSubmit( ) { // Bei Übermittlung des Formulars überprüfen wir alle Felder im // Formular noch einmal und prüfen über ihre classNames, ob sie ungültig sind. // Wenn ungültige Felder vorhanden sind, zeige eine Warnung an, und verhindere // die Übermittlung des Formulars. var invalid = false; // Beginne mit der Annahme, dass alle Felder gültig sind // Durchlaufe alle Formularelemente for(var i = 0; i < this.elements.length; i++) { var e = this.elements[i]; // Wenn das Element ein Textfeld ist und unseren onchange-Handler hat, if (e.type == "text" && e.onchange == validateOnChange) { e.onchange( ); // dann rufe den Handler zur erneuten Überprüfung auf // Wenn das Element durchfällt, scheitert die gesamte Formularüberprüfung if (e.className == "invalid") invalid = true; } } // Bei ungültigem Formular Benutzer warnen und Übermittlung blockieren if (invalid) { alert("Das Formular ist unvollständig oder falsch ausgefüllt.\n" + "Bitte korrigieren Sie die markierten Felder, und versuchen Sie es noch einmal."); return false; } } })( );
18.4 Ein Beispiel zur Überprüfung von Formularen |
501
491-0.book Seite 502 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Chapter 1
KAPITEL 19
Cookies und Persistenz auf der Clientseite
Das Document-Objekt besitzt eine Eigenschaft namens cookie, die wir in Kapitel 15 nicht betrachtet haben. Oberflächlich gesehen scheint diese Eigenschaft ein einfacher Stringwert zu sein; die cookie-Eigenschaft ist aber viel mehr als das: Sie versetzt JavaScript-Code in die Lage, Daten dauerhaft auf der Benutzerfestplatte zu speichern und vorher auf diese Weise gespeicherte Daten wieder abzurufen. Persistenz auf der Clientseite ist eine einfache Möglichkeit, Webanwendungen ein Gedächtnis zu geben: Beispielsweise kann eine Webseite Benutzereinstellungen speichern, die wiederverwendet werden können, wenn der Benutzer die Seite erneut besucht. Cookies werden außerdem für serverseitige Skripten verwendet und sind eine standardisierte Erweiterung des HTTP-Protokolls. Alle modernen Webbrowser unterstützen Cookies und lassen sie über die Document.cookie-Eigenschaft per Skript steuern. Neben den Cookies gibt es weitere Persistenzmechanismen auf der Clientseite, die leistungsfähiger, aber weniger weit verbreitet sind. Diese bespreche ich kurz am Ende dieses Kapitels.
19.1 Ein Überblick über Cookies Ein Cookie ist eine kleine benannte Datenmenge, die vom Webbrowser gespeichert wird und einer bestimmten Webseite oder -site zugeordnet ist.1 Cookies dienen dazu, dem Webbrowser eine Art Gedächtnis zu geben, sodass Skripten und serverseitige Programme Daten, die auf einer Seite eingegeben wurden, auch auf einer anderen Webseite verwenden können. Sie ermöglichen auch das Speichern und Abrufen von Voreinstellungen des Benutzers oder von anderen Zustandsvariablen, wenn der Benutzer eine Seite verlässt 1 Der Name »Cookie« besitzt keine tiefere Bedeutung. Er ist aber auch keine Neuschöpfung aus »modernen JavaScript-Zeiten«. In der Frühzeit der Computer-Geschichte bezeichnete der Begriff »Cookie« oder »Magic Cookie« ein kleines Bröckchen von Daten (insbesondere von vertraulichen oder geheimen Daten ähnlich einem Passwort), das zur Identifikation dient oder den Zugang erlaubt. In JavaScript werden Cookies verwendet, um Zustände zu speichern und eine Art von »Identifikation« für einen Webbrowser bereitzustellen. Cookies in JavaScript verwenden allerdings keine Kryptografie und sind auf keine Weise abgesichert (obwohl für ihre Übertragung eine verschlüsselte https:-Verbindung hilfreich ist).
502 |
491-0.book Seite 503 Mittwoch, 4. April 2007 9:55 09
e-bol.net
cookie ist eine String-Eigenschaft, die es Ihnen ermöglicht, Cookies, die sich auf die aktu-
elle Webseite beziehen, zu lesen, zu erzeugen, zu verändern und zu löschen. Obwohl cookie zunächst wie eine normale les- und schreibbare String-Eigenschaft aussieht, ist das Verhalten dieser Eigenschaft tatsächlich komplexer. Wenn Sie den Wert von cookie
lesen, erhalten Sie einen String, der die Namen und Werte aller Cookies enthält, die das Dokument betreffen. Ein einzelner Cookie wird erzeugt, geändert oder gelöscht, indem der Wert der cookie-Eigenschaft mit einer speziellen Syntax gesetzt wird. In den folgenden Abschnitten dieses Kapitels wird genau erklärt, wie dies funktioniert. Um allerdings die Eigenschaft cookie verwenden zu können, benötigen Sie zunächst einige Informationen über Cookies und ihre Funktionsweise. Außer einem Namen und einem Wert besitzt jeder Cookie optionale Attribute, die seine Lebensdauer, seine Sichtbarkeit und den Sicherheitsgrad festlegen. Cookies sind normalerweise vergänglich; die gespeicherten Werte bleiben für die Dauer der Webbrowser-Sitzung erhalten, werden aber gelöscht, sobald der Benutzer den Browser beendet. Wenn Sie einen Cookie über die Dauer einer einzelnen Browsersitzung hinaus erhalten wollen, müssen Sie dem Browser sagen, wie lange er den Cookie aufbewahren soll. Die ursprüngliche Vorgehensweise dafür war das Setzen des expires-Attributs auf ein Verfallsdatum in der Zukunft. Das expires-Attribut funktioniert zwar weiterhin, wurde aber vom max-ageAttribut abgelöst, das die Lebensdauer des Cookies in Sekunden angibt. Durch das Festlegen eines der beiden Attribute speichert der Browser den Cookie in einer lokalen Datei und kann dadurch den Cookie in zukünftigen Browsersitzungen abrufen, wenn der Benutzer die Webseite erneut besucht. Wenn das Verfallsdatum abgelaufen ist oder die max-age-Lebensdauer erreicht wird, löscht der Browser den Cookie automatisch aus seiner Cookie-Datei. Ein weiteres wichtiges Cookie-Attribut ist path; durch dieses Attribut wird angegeben, mit welchen Webseiten der Cookie verknüpft ist. Normalerweise ist ein Cookie der Seite zugeordnet, von der er erzeugt wurde. Er ist auch nur für diese sowie für alle anderen Seiten im selben Verzeichnis und in dessen Unterverzeichnissen zugänglich. Wenn beispielsweise die Webseite http://www.beispiel.de/katalog/index.html einen Cookie erzeugt, ist dieser auch für die Seiten http://www.beispiel.de/katalog/bestellung.html und http:// www.beispiel.de/katalog/spielzeug/index.html sichtbar, nicht aber für http://www.beispiel. de/info.html.
19.1 Ein Überblick über Cookies |
503
clientseitiges JavaScript
und später zu ihr zurückkehrt. Cookies wurden ursprünglich für die Programmierung auf der Serverseite entwickelt und sind auf der untersten Ebene als Erweiterung des HTTPProtokolls implementiert. Die Daten eines Cookies werden automatisch zwischen Webbrowser und Webserver ausgetauscht, sodass Skripten auf der Serverseite auf die Werte von Cookies, die auf der Clientseite gespeichert sind, lesend und schreibend zugreifen können. Wie Sie im Folgenden sehen werden, kann auch JavaScript Cookies lesen und schreiben, und zwar über die Eigenschaft cookie des Document-Objekts.
491-0.book Seite 504 Mittwoch, 4. April 2007 9:55 09
e-bol.net Dieses Verhalten ist häufig genau das, was Sie benötigen. Manchmal werden Sie jedoch einen Cookie auch auf allen Seiten einer Website verwenden wollen, unabhängig davon, welche Seite den Cookie erzeugt hat. Wenn beispielsweise der Benutzer seine MailAdresse in ein Formular auf einer Webseite einträgt, könnten Sie diese Adresse speichern und als Voreinstellung verwenden, sobald der Benutzer später auf diese Seite zurückkehrt, aber auch, wenn er in einem Formular auf einer anderen Seite gebeten wird, seine Adresse anzugeben. Um diese Verwendung zu ermöglichen, können Sie für einen Cookie einen path angeben. Dann können alle Webseiten, die auf diesem Server liegen und deren URL den angegebenen Pfad enthält, gemeinsam auf diesen Cookie zugreifen. Wird z.B. der Pfad eines Cookies von der Seite http://www.beispiel.de/katalog/spielzeug/index.html auf den Wert »/katalog« gesetzt, so ist der Cookie auch für die Seite http://www. beispiel.de/katalog/bestellung.html sichtbar. Wenn der Pfad auf den Wert »/« gesetzt wird, ist der Cookie für alle Seiten auf dem Webserver www.beispiel.de sichtbar. Normalerweise können nur Seiten auf einen Cookie zugreifen, die auf demselben Webserver gespeichert sind wie die Seite, die den Cookie gesetzt hat. Größere Sites werden jedoch mitunter auch gemeinsam auf mehreren Servern die gleichen Cookies benutzen wollen. Beispielsweise könnte der Server bestellung.beispiel.de Cookies lesen wollen, die vom Server katalog.beispiel.de definiert wurden. An dieser Stelle kommt das nächste Cookie-Attribut, domain, ins Spiel. Wenn ein Cookie von einer Seite auf katalog. beispiel.de sein path-Attribut auf den Wert »/« und sein domain-Attribut auf den Wert »beispiel.de« setzt, ist der Cookie für alle Seiten auf den Servern katalog.beispiel.de, bestellung.beispiel.de und auf allen anderen Servern in der Domäne beispiel.de verfügbar. Wenn das Attribut domain für einen Cookie nicht gesetzt ist, wird als Voreinstellung der Hostname des Webservers verwendet, von dem die Seite stammt. Beachten Sie, dass Sie die Domäne eines Cookies nur auf die Domäne Ihres eigenen Servers setzen können. Das letzte Cookie-Attribut ist ein Boolesches Attribut namens secure. Es gibt an, wie die Werte des Cookies über das Netzwerk übertragen werden. Normalerweise sind Cookies unsicher, das heißt, dass sie über eine normale, unsichere HTTP-Verbindung übertragen werden. Wenn ein Cookie als sicher gekennzeichnet ist, wird er jedoch nur übertragen, wenn Browser und Server über HTTPS oder ein anderes sicheres Protokoll miteinander verbunden sind. Beachten Sie, dass die Attribute expires, max-age, path, domain und secure eines Cookies keine Objekteigenschaften in JavaScript sind. Wir werden weiter unten in diesem Kapitel sehen, wie Sie diesen Attributen Werte zuweisen. Cookies haben bei vielen Webanwendern einen schlechten Ruf, und zwar aufgrund der hemmungslosen Verwendung von Cookies, die von Drittparteien stammen, d.h. von Cookies, die nicht mit der Webseite selbst, sondern mit den Bildern einer Seite assoziiert sind. Mit Cookies von Drittparteien können Hosting-Firmen zum Beispiel den Benutzer von einer Clientseite zur nächsten verfolgen. Aufgrund der damit verbundenen Datenschutzprobleme deaktivieren manche Benutzer Cookies in ihren Webbrowsern. Vor der
504 | Kapitel 19: Cookies und Persistenz auf der Clientseite
491-0.book Seite 505 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Wenn Sie sich für die vollständigen technischen Einzelheiten zur Funktionsweise von Cookies (auf HTTP-Protokoll-Ebene) interessieren, sollten Sie RFC 2965 unter http://www.ietf.org/rfc/rfc2965.txt zurate ziehen. Cookies wurden ursprünglich von Netscape erfunden, und die Original-Cookie-Spezifikation von Netscape ist immer noch interessant. Obwohl Teile davon inzwischen überholt sind, ist sie um einiges kürzer und leichter zu lesen als der formale RFC. Dieses alte Dokument steht unter http://wp. netscape.com/newsref/std/cookie_spec.html. Die folgenden Abschnitte erläutern, wie Sie in JavaScript die Werte von Cookies zuweisen und abfragen können und wie das Verfallsdatum, der Pfad, die Domäne sowie das Sicherheitsniveau eines Cookies angegeben werden können. Daran schließt sich ein Abschnitt über Cookie-Alternativen an.
19.2 Cookies speichern Um einem Dokument einen vergänglichen Cookie zuzuordnen, kann der cookie-Eigenschaft einfach in der folgenden Form ein String zugewiesen werden: name=wert
Wenn Sie die Eigenschaft cookie später abfragen, wird das entsprechende Paar aus Namen und Wert in die Liste der Cookies für dieses Dokument aufgenommen. Der Wert eines Cookies darf keine Semikola, Kommata und Leerzeichen enthalten. Daher sollten Sie die globale encodeURIComponent( )-Funktion des JavaScript-Sprachkerns zum Codieren des Werts benutzen, bevor Sie ihn im Cookie speichern. Wenn Sie dies tun, müssen Sie die Umkehrfunktion decodeURIComponent( ) verwenden, um den Wert des Cookies lesen zu können. (Die älteren Funktionen escape( ) und unescape( ) werden auch häufig verwendet, sind inzwischen aber veraltet). Ein Cookie, der mit einem einfachen Name/Wert-Paar beschrieben ist, bleibt für die Dauer der aktuellen Websitzung bestehen, wird aber gelöscht, sobald der Benutzer den
19.2 Cookies speichern |
505
clientseitiges JavaScript
Verwendung von Cookies in Ihrem JavaScript-Code empfiehlt es sich, zuerst zu überprüfen, ob sie auch aktiviert sind. Bei den meisten Browsern machen Sie das durch die Überprüfung der navigator.cookieEnabled-Eigenschaft. Steht sie auf true, dann sind Cookies aktiviert. Steht sie auf false, so sind Cookies deaktiviert (obwohl nicht-persistente Cookies, die nur während der aktuellen Sitzung gelten, trotzdem aktiviert sein können). Das ist keine standardisierte Eigenschaft. Wenn Sie feststellen, dass sie in dem Browser, in dem Ihr Code läuft, nicht definiert ist, müssen Sie die Unterstützung für Cookies prüfen, indem Sie versuchen, einen Test-Cookie zu schreiben, zu lesen und zu löschen. Weiter unten im Kapitel erkläre ich die dazu nötige Vorgehensweise, und Beispiel 19-2 enthält Code zum Testen der Cookie-Unterstützung.
491-0.book Seite 506 Mittwoch, 4. April 2007 9:55 09
e-bol.net Browser verlässt. Um einen Cookie zu erzeugen, der über mehrere Browsersitzungen hinweg bestehen bleibt, geben Sie seine Lebensdauer (in Sekunden) mit einem max-age-Attribut an. Sie erreichen dies, indem Sie der cookie-Eigenschaft einen String der folgenden Form zuweisen: name=wert; max-age=sekunden
Um beispielsweise einen Cookie zu erzeugen, der für ein Jahr gültig bleibt, können Sie den folgenden Code verwenden: document.cookie = "version=" + document.lastModified + "; max-age=" + (60*60*24*365);
Sie können die Lebensdauer eines Cookies auch mit dem überholten expires-Attribut festlegen, das auf ein Datum im von Date.toGMTString( ) geschriebenen Format gesetzt werden sollte. Beispielsweise: var naechstesJahr = new Date( ); naechstesJahr.setFullYear(naechstesJahr.getFullYear( ) + 1); document.cookie = "version=" + document.lastModified + "; expires=" + naechstesJahr.toGMTString( );
In ähnlicher Weise können Sie die Attribute path, domain und secure eines Cookies festlegen, indem Sie Strings der folgenden Form an den Cookie-Wert anhängen, bevor er der Eigenschaft cookie zugewiesen wird: ; path=pfad ; domain=domaene ; secure
Um den Wert eines Cookies zu verändern, weisen Sie ihm einfach einen neuen Wert zu und verwenden dabei den gleichen Namen, Pfad und Domain. Die Lebensdauer eines Cookies kann verändert werden, indem Sie seinen Wert durch Angabe eines neuen max-age- oder expires-Attributs ändern. Um einen Cookie zu löschen, setzen Sie ihn noch einmal und verwenden den gleichen Namen, Pfad und Domain, geben aber einen beliebigen (oder leeren) Wert und ein maxage-Attribut von 0 an (oder verwenden Sie das expires-Attribut mit einem bereits abgelaufenen Verfallsdatum). Allerdings bedeutet dies nicht, dass der Browser verfallene Cookies unmittelbar löschen muss, sodass ein Cookie auch nach dem Verfallsdatum noch in der Cookie-Datei des Browsers enthalten sein kann.
19.2.1 Beschränkungen von Cookies Cookies sind für das gelegentliche Speichern kleiner Datenmengen gedacht, nicht als Allzweckmechanismus für die Kommunikation oder Datenübertragung. Verwenden Sie sie daher maßvoll. RFC 2965 ermutigt Browserhersteller, eine unbegrenzte Anzahl von Cookies mit unbegrenzter Größe zu erlauben. Dazu müssen Sie wissen, dass der Standard von Browsern nur verlangt, insgesamt bis zu 300 Cookies oder 20 Cookies pro
506 | Kapitel 19: Cookies und Persistenz auf der Clientseite
491-0.book Seite 507 Mittwoch, 4. April 2007 9:55 09
e-bol.net Webserver aufbewahren zu können (nicht pro Seite oder Site, sondern für den gesamten Server). Auch müssen pro Cookie nicht mehr als 4 Kilobyte an Daten gespeichert werden (zu dieser Menge zählen sowohl der Name als auch der Wert). In der Praxis erlauben moderne Browser viel mehr als insgesamt 300 Cookies, aber die 4 Kilobyte-Grenze wird z.T. weiterhin beibehalten.
Wenn Sie die cookie-Eigenschaft in einem JavaScript-Ausdruck verwenden, wird als Wert ein String zurückgegeben, der alle Cookies enthält, die für das aktuelle Dokument relevant sind. Dieser String besteht aus einer Liste von name=wert-Paaren, die jeweils durch ein Semikolon voneinander getrennt werden. Dabei ist name der Name eines Cookies und wert der von ihm gespeicherte String. Dieser Wert enthält keines der Attribute, die für den Cookie eventuell definiert sind. Um den Wert eines bestimmten benannten Cookies zu ermitteln, können Sie die Methoden String.indexOf( ) und String.substring( ) verwenden oder den String mit der Methode String.split( ) in einzelne Cookies zerteilen. Nachdem Sie den Wert eines Cookies in dieser Weise aus der Eigenschaft cookie ausgelesen haben, müssen Sie ihn auf Basis des Formats bzw. der Codierung interpretieren, die vom Erzeuger des Cookies benutzt wurde. Beispielsweise könnte der Cookie mehrere Datenfelder enthalten, die jeweils durch einen Doppelpunkt voneinander getrennt sind. In diesem Fall müssten Sie die entsprechenden String-Methoden verwenden, um die einzelnen Datenfelder auszulesen. Denken Sie daran, die Funktion decodeURIComponent( ) für den Wert des Cookies zu benutzen, wenn dieser zuvor mit der Funktion encodeURIComponent( ) codiert wurde. Das folgende Programmstück zeigt, wie Sie die Eigenschaft cookie lesen, einen einzelnen Cookie extrahieren und den Wert dieses Cookies verwenden: // Lies die cookie-Eigenschaft. So erhalten wir alle Cookies für dieses Dokument. var alleCookies = document.cookie; // Suche nach dem Anfang des Cookies namens "version" var pos = alleCookies.indexOf("version="); // Wenn wir einen Cookie dieses Namens finden, lesen wir ihn aus // und verwenden seinen Wert if (pos != -1) { var start = pos + 8; // Anfang des Cookie-Werts var ende = alleCookies.indexOf(";", start); // Ende des Cookie-Werts if (ende == -1) ende = alleCookies.length; var wert = alleCookies.substring(start, ende); // Extrahiere den Wert value = decodeURIComponent(value); // Decodiere ihn // Nun haben wir den Wert des Cookies und können ihn verwenden. // In diesem Fall war der Cookie zuvor auf das Änderungsdatum des // Dokuments gesetzt. Mit seiner Hilfe können wir feststellen, ob sich
19.3 Cookies lesen |
507
clientseitiges JavaScript
19.3 Cookies lesen
491-0.book Seite 508 Mittwoch, 4. April 2007 9:55 09
e-bol.net // das Dokument seit dem letzten Besuch dieses Benutzers geändert hat. if (wert != document.lastModified) alert("Dieses Dokument hat sich seit Ihrem letzten Besuch geändert!"); }
Beachten Sie, dass der beim Lesen der cookie-Eigenschaft zurückgegebene String keine Informationen über die einzelnen Attribute des Cookies enthält. Die Eigenschaft cookie ermöglicht es Ihnen, diese Werte festzulegen, nicht aber, sie abzufragen.
19.4 Ein Cookie-Beispiel Wir beenden diese Besprechung von Cookies mit einem nützlichen Utility für den Umgang mit Cookies, das etwas später in Beispiel 19-2 gezeigt wird. Der Cookie( )-Konstruktor liest den Wert eines benannten Cookies. Die store( )-Methode eines Cookies speichert Daten in diesem Cookie mit Hilfe der von Ihnen festgelegten Lebensdauer, des Pfads und der Domain. Die remove( )-Methode eines Cookies löscht den Cookie, indem sie sein max-age-Attribut auf 0 setzt. Die in diesem Beispiel definierte Cookie-Klasse speichert die Namen und Werte von mehreren Statusvariablen in einem einzigen Cookie. Um Daten mit einem Cookie zu assoziieren, setzen Sie einfach die Eigenschaften des Cookie-Objekts. Beim Aufruf der store( )-Methode am Cookie werden die von Ihnen zum Objekt hinzugefügten Eigenschaftsnamen und -werte zu dem Cookie-Wert, der gespeichert wird. Wenn Sie ein neues Cookie-Objekt erzeugen, sucht der Cookie( )-Konstruktor nach einem bereits bestehenden Cookie mit dem von Ihnen angegebenen Namen. Findet er ihn, parst er seinen Wert als Name/Wert-Paare und setzt sie als Eigenschaften des neu erstellten Cookie-Objekts. Damit Sie Beispiel 19-2 besser verstehen, beginnt Beispiel 19-1 mit einer einfachen Webseite, die die Cookie-Klasse verwendet. Beispiel 19-1: Die Cookie-Klasse verwenden // Erzeuge den Cookie zum Speichern des Zustands dieser Seite. var cookie = new Cookie("besucherdaten"); // Zunächst versuchen wir, die im Cookie gespeicherten Daten zu lesen. Wenn der Cookie // noch nicht vorhanden ist (oder nicht die erwarteten Daten enthält), dann frage den Benutzer if (!cookie.name || !cookie.color) { cookie.name = prompt("Ihr Name bitte:", ""); cookie.color = prompt("Ihre Lieblingsfarbe:", ""); } // Zähle, wie oft dieser Benutzer die Seite besucht hat if (!cookie.visits) cookie.visits = 1; else cookie.visits++;
508 | Kapitel 19: Cookies und Persistenz auf der Clientseite
491-0.book Seite 509 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 19-1: Die Cookie-Klasse verwenden (Fortsetzung)
clientseitiges JavaScript
// Speichere die Cookie-Daten, die die neue Besuchsanzahl enthalten. Wir setzen // die Cookie-Lebensdauer auf 10 Tage. Da wir keinen Pfad angeben, // kann auf diesen Cookie von allen Webseiten im gleichen Verzeichnis oder // "darunter" zugegriffen werden. Deshalb sollten wir sicher sein, dass der Cookie-Name // "besucherdaten" in diesen Seiten eindeutig ist. cookie.store(10); // Jetzt können wir die Daten verwenden, die wir vom Cookie (oder vom // Benutzer) erhalten haben, um einen Benutzer mit Namen und Lieblingsfarbe zu grüßen. document.write('' + 'Hallo ' + cookie.name + '!' + '' + '
Sie waren schon ' + cookie.visits + '-mal hier.' + 'Vergiss mich');
Die Cookie-Klasse selbst ist in Beispiel 19-2 aufgelistet. Beispiel 19-2: Eine Cookie-Utility-Klasse /** * Das ist die Cookie( )-Konstruktorfunktion. * * Dieser Konstruktor sucht nach einem Cookie mit dem angegebenen Namen für das aktuelle * Dokument. Falls ein solcher vorhanden ist, parst er seinen Wert in eine Gruppe von * Name/Wert-Paaren und speichert diese Werte als Eigenschaften des neu erzeugten * Objekts. * * Um neue Daten im Cookie zu speichern, setzen Sie einfach die Eigenschaften des * Cookie-Objekts. Vermeiden Sie die Eigenschaftsnamen "store" und "remove", die für * Methodennamen reserviert sind. * * Um Cookie-Daten im lokalen Speicher des Webbrowsers zu speichern, rufen Sie store( ) auf. * Um Cookie-Daten aus dem Browserspeicher zu entfernen, rufen Sie remove( ) auf. * * Die statische Methode Cookie.enabled( ) gibt true aus, wenn Cookies * aktiviert sind, und false, wenn nicht. */ function Cookie(name) { this.$name = name; // Speichere den Namen dieses Cookies // Erzeuge zunächst eine Liste aller Cookies, die zu diesem Dokument gehören. // Wir lesen dazu die Eigenschaft Document.cookie ein. // Sind keine Cookies vorhanden, brauchen wir nichts zu machen. var alleCookies = document.cookie; if (alleCookies == "") return; // Unterteile den String aller Cookies in einzelne Cookie-Strings, // Durchlaufe dann die Cookie-Strings und suche nach unserem Namen. var cookies = alleCookies.split(';'); var cookie = null;
19.4 Ein Cookie-Beispiel |
509
491-0.book Seite 510 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 19-2: Eine Cookie-Utility-Klasse (Fortsetzung) for(var i = 0; i < cookies.length; i++) { // Fängt dieser Cookie-String mit dem richtigen Namen an? if (cookies[i].substring(0, name.length+1) == (name + "=")) { cookie = cookies[i]; break; } } // Wenn wir keinen passenden Cookie fanden, dann brich ab if (cookie == null) return; // Der Cookie-Wert ist der Teil nach dem Gleichheitszeichen var cookieval = cookie.substring(name.length+1); // Wir haben den Wert des gesuchten Cookies gefunden und müssen // diesen nun in einzelne Namen und Werte von Zustandsvariablen // zerlegen. Die Paare von Namen und Werten sind voneinander // durch "&"-Zeichen getrennt, Name und Wert jeweils durch einen // Doppelpunkt. Wir verwenden die split()-Methode, // um alles zu parsen. var a = cookieWert.split('&'); // In ein Array von Name-Wert-Paaren zerlegen. for(var i=0; i < a.length; i++) // Zerlege jedes Paar in ein Array. a[i] = a[i].split(':'); // Nun haben wir den Wert des Cookies analysiert und können alle Namen und Werte // als Eigenschaften dieses Cookie-Objekts setzen. Beachte, dass wir den // Eigenschaftswert decodieren, da ihn die store( )-Methode codiert. for(var i = 0; i < a.length; i++) { this[a[i][0]] = decodeURIComponent(a[i][1]); } } /** * Diese Funktion ist die store( )-Methode des Cookie-Objekts. * * Argumente: * * daysToLive: die Lebensdauer des Cookies in Tagen. Wenn Sie diesen Wert auf * 0 setzen, wird der Cookie gelöscht. Wenn Sie ihn auf null setzen oder * das Argument weglassen, gilt der Cookie nur für die eine Sitzung und wird * nicht gespeichert, wenn der Browser beendet wird. Dieses Argument wird verwendet, um * das max-age-Attribut des Cookies festzulegen. * path: der Wert des path-Attributs des Cookies * domain: der Wert des domain-Attributs des Cookies * secure: wenn true, wird das secure-Attribut des Cookies gesetzt */ Cookie.prototype.store = function(daysToLive, path, domain, secure) { // Durchlaufe zunächst die Eigenschaften des Cookie-Objekts, und // setze den Wert des Cookies zusammen. Da Cookies das Gleichheitszeichen // und Semikola als Trenner verwenden, benutzen wir Doppelpunkte
510 | Kapitel 19: Cookies und Persistenz auf der Clientseite
491-0.book Seite 511 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 19-2: Eine Cookie-Utility-Klasse (Fortsetzung)
clientseitiges JavaScript
// und das "&"-Zeichen für die einzelnen Zustandsvariablen, die // wir in einem einzelnen Cookie-Wert speichern. Beachte, dass wir den Wert // jeder Eigenschaft für den Fall codieren, dass er Sonder- oder andere // unzulässige Zeichen enthält. var cookieWert = ""; for(var eigenschaft in this) { // Ignoriere Eigenschaften, deren Namen mit '$' beginnen, sowie Methoden. if ((eigenschaft.charAt(0) == '$') || ((typeof this[eigenschaft]) == 'function')) continue; if (cookieWert != "") cookieWert += '&'; cookieval += prop + ':' + encodeURIComponent(this[prop]); } // Nachdem wir den Wert des Cookies haben, setzen wir nun den ganzen // Cookie-String zusammen, der auch den Namen und die einzelnen bei der // Erzeugung des Cookies-Objekts angegebenen Attribute enthält. var cookie = this.$name + '=' + cookieWert; if (daysToLive || daysToLive == 0) { cookie += "; max-age=" + (daysToLive*24*60*60); } if (path) cookie += "; path=" + path; if (domain) cookie += "; domain=" + domain; if (secure) cookie += "; secure"; // Nun speichern wir den Cookie durch Zuweisung an die Eigenschaft Document.cookie. document.cookie = cookie; } /** * Diese Funktion ist die remove( )-Methode des Cookie-Objekts; sie löscht die * Eigenschaften des Objekts und entfernt den Cookie aus dem * lokalen Browserspeicher. * * Die Argumente für diese Funktion sind alle optional. Um einen Cookie zu entfernen, * müssen Sie aber dieselben Werte übergeben, die Sie zuvor an store( ) übergeben haben. */ Cookie.prototype.remove = function(path, domain, secure) { // Lösche die Eigenschaften des Cookies for(var eigenschaft in this) { if (prop.charAt(0) != '$' && typeof this[prop] != 'function') delete this[prop]; } // Speichere dann den Cookie mit einer Lebensdauer von 0 this.store(0, path, domain, secure); } /** * Diese statische Methode versucht festzustellen, ob Cookies aktiviert sind.
19.4 Ein Cookie-Beispiel |
511
491-0.book Seite 512 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 19-2: Eine Cookie-Utility-Klasse (Fortsetzung) * Sie gibt true zurück, wenn sie aktiviert erscheinen, und ansonsten false. * Ein Rückgabewert von true garantiert nicht, dass Cookies auch tatsächlich überleben. * Cookies für nicht-persistente Sitzungen können auch dann funktionieren, wenn diese * Methode false ausgibt. */ Cookie.enabled = function( ) { // Verwenden Sie navigator.cookieEnabled, wenn dieser Browser sie definiert if (navigator.cookieEnabled != undefined) return navigator.cookieEnabled; // Wenn wir bereits einen Wert im Cache haben, so verwende diesen Wert if (Cookie.enabled.cache != undefined) return Cookie.enabled.cache; // Erzeuge ansonsten einen Test-Cookie mit einer Lebensdauer document.cookie = "testcookie=test; max-age=10000"; // Setze den Cookie // Überprüfe jetzt, ob der Cookie gespeichert wurde var cookies = document.cookie; if (cookies.indexOf("testcookie=test") == -1) { // Der Cookie wurde nicht gespeichert return Cookie.enabled.cache = false; } else { // Cookie wurde gespeichert, wir müssen ihn also löschen, bevor wir zurückkehren document.cookie = "testcookie=test; max-age=0"; // Lösche den Cookie return Cookie.enabled.cache = true; } }
19.5 Cookie-Alternativen Die Verwendung von Cookies für clientseitige Persistenz hat es ein paar Nachteile: • Sie sind auf eine Datenmenge von 4 KB begrenzt. • Auch wenn Cookies nur für die Skriptsteuerung auf der Clientseite verwendet werden, werden sie trotzdem bei jedem Anfordern einer mit ihnen assoziierten Webseite an den Webserver geschickt. Braucht der Server die Cookies nicht, ist das eine Verschwendung von Bandbreite. Zu Cookies gibt es zwei Alternativen. Sowohl Internet Explorer von Microsoft als auch das Flash-Plug-in von Adobe definieren eigene Mechanismen für clientseitige Persistenz. Obwohl sie nicht standardisiert sind, sind beide weit verbreitetet. In der überwiegenden Mehrheit der Browser ist daher mindestens einer dieser Mechanismen vorhanden. Die Persistenzmechanismen von IE und Flash werden in den folgenden Abschnitten kurz beschrieben. Das Kapitel schließt mit einem fortgeschrittenen Beispiel, das persistenten Speicher über IE, Flash oder Cookies zur Verfügung stellt.
512 | Kapitel 19: Cookies und Persistenz auf der Clientseite
491-0.book Seite 513 Mittwoch, 4. April 2007 9:55 09
e-bol.net
19.5.1 IE userData-Persistenz Internet Explorer ermöglicht clientseitige Persistenz mit einem DHTML-Behavior (Verhalten). Um auf diesen Mechanismus zuzugreifen, wenden Sie ein spezielles Verhalten auf ein Element (wie z.B. ) Ihres Dokuments an. Das können Sie z.B. mit CSS erreichen: clientseitiges JavaScript
.persistent { behavior:url(#default#userData);}
Da behavior nicht dem CSS-Standard entspricht, ignorieren es andere Webbrowser einfach. Sie können behavior auch mit JavaScript an einem Element festlegen: var memory = document.getElementById("memory"); memory.style.behavior = "url('#default#userData')";
Ist ein HTML-Element mit diesem userData-Behavior assoziiert, so werden neue (vom Behavior definierte) Methoden für dieses Element verfügbar.2 Um Daten persistent zu speichern, setzen Sie die Attribute des Elements mit setAttribute( ) und speichern diese Attribute dann mit save( ): var memory = document.getElementById("memory"); // Hole das persistente Element memory.setAttribute("username", username); // Lege die Daten als Attribute fest memory.setAttribute("lieblingsfarbe", lieblingsfarbe); memory.save("meinePersistentenDaten"); // Speichere die Daten
Beachten Sie, dass die save( )-Methode ein String-Argument entgegennimmt: Das ist der (frei gewählte) Name, unter dem die Daten gespeichert werden sollen. Beim Abfragen der Daten müssen Sie den gleichen Namen verwenden. Daten, die mit Hilfe des IE-Persistenzmechanismus gespeichert werden, kann ein Verfallsdatum gegeben werden, wie das auch für Cookie-Daten möglich ist. Dazu legen Sie einfach die expires-Eigenschaft fest und rufen anschließend die save( )-Methode auf. Diese Eigenschaft sollte ein String in dem Format sein, das von Date.toUTCString( ) zurückgegeben wird. Beispielsweise können Sie die folgenden Zeilen zum vorhergehenden Code hinzufügen, um ein Verfallsdatum 10 Tage in der Zukunft festzulegen: var now = (new Date( )).getTime( ); // jetzt, in Millisekunden var expires = now + 10 * 24 * 60 * 60 * 1000; // 10 Tage von jetzt an, in ms memory.expires = (new Date(expires)).toUTCString( ); // in einen String konvertieren
2 Das userData-Behavior ist eine von vier möglichen Verhaltenweisen unter Internet Explorer, die sich auf die Persistenz beziehen. http://msdn.microsoft.com/workshop/author/persistence/overview.asp enthält weitere Einzelheiten über die Persistenz unter IE.
19.5 Cookie-Alternativen |
513
491-0.book Seite 514 Mittwoch, 4. April 2007 9:55 09
e-bol.net Um persistente Daten abzufragen, drehen Sie diese Schritte um und rufen load( ) auf, um gespeicherte Attribute zu laden, und dann getAttribute( ), um Attributwerte abzufragen: var memory = document.getElementById("memory"); // Hole das persistente Element memory.load("meinePersistentenDaten"); // Gespeicherte Daten über Namen abrufen var user = memory.getAttribute("username"); // Frage die Attribute ab var farbe = memory.getAttribute("lieblingsfarbe");
19.5.1.1 Hierarchische Daten speichern Das userData-Persistenzverhalten beschränkt sich nicht auf das Speichern und Abrufen von Attributwerten. Jedes Element, auf das dieses Behavior angewandt wird, wird mit einem vollständigen XML-Dokument assoziiert. Die Anwendung des Behaviors auf ein HTML-Element erzeugt eine XMLDocument-Eigenschaft am Element. Der Wert dieser Eigenschaft ist ein DOM-Document-Objekt. Sie können DOM-Methoden verwenden (siehe Kapitel 15), um diesem Dokument vor dem Aufruf von save( ) einen Inhalt hinzuzufügen bzw. nach dem Aufruf von load( ) Inhalte auszulesen. Hier ist ein Beispiel: var memory = document.getElementById("memory"); var doc = memory.XMLDocument; var root = doc.documentElement; root.appendChild(doc.createTextNode("Daten hier"));
// // // //
Beschaffe das persistente Element Beschaffe sein Dokument Root-Element des Dokuments Speichere den Text im Dokument
Durch die Verwendung eines XML-Dokuments können hierarchische Daten gespeichert werden; beispielsweise können Sie einen Datenbaum aus JavaScript-Objekten in einen Datenbaum aus XML-Elementen konvertieren.
19.5.1.2 Speicherlimits Mit dem Persistenzmechanismus von IE kann eine viel größere Datenmenge gespeichert werden als mit Cookies. Jede Seite kann bis zu 64 KB speichern und für jeden Webserver sind insgesamt 640 KB erlaubt. Für Seiten eines vertrauenswürdigen Intranets sind noch größere Mengen erlaubt. Es existiert keine Dokumentation darüber, wie ein Endbenutzer diese Speicherbegrenzungen ändern oder den Persistenzmechanismus völlig deaktivieren kann.
19.5.1.3 Persistente Daten gemeinsam benutzen Genau wie Cookies sind die mit dem IE-Persistenzmechanismus gespeicherten Daten für alle Webseiten im gleichen Verzeichnis zugänglich. Im Unterschied zu Cookies kann eine Webseite aber nicht über IE auf persistente Daten zugreifen, die von Seiten in ihren übergeordneten Verzeichnissen gespeichert wurden. Außerdem hat der IE-Persistenzmechanismus kein Äquivalent zu den Cookie-Attributen path und domain, sodass es keine Möglichkeit gibt, persistente Daten über eine größere Anzahl von Seiten gemeinsam zu verwenden. Persistente Daten lassen sich unter IE von verschiedenen Seiten auch nur gemeinsam benutzen, wenn die Seiten im gleichen Verzeichnis stehen und über das glei-
514 | Kapitel 19: Cookies und Persistenz auf der Clientseite
491-0.book Seite 515 Mittwoch, 4. April 2007 9:55 09
e-bol.net che Protokoll geladen wurden. Das bedeutet, dass eine Seite, die mit dem normalen http:-Protokoll geladen wird, nicht auf Daten in einer Seite zugreifen kann, die mit dem https:-Protokoll geladen wurde.
19.5.2 Flash-SharedObject-Persistenz
var so = SharedObject.getLocal("meinePersistentenDaten");
Im Gegensatz zum IE-Persistenzmechanismus definiert die SharedObject-Klasse keine load( )-Methode. Bei der Erstellung eines SharedObject werden die vorher unter dem angegebenen Namen gespeicherten Daten automatisch geladen. Jedes SharedObject hat eine data-Eigenschaft. Diese data-Eigenschaft bezieht sich auf ein reguläres ActionScriptObjekt, und über die Eigenschaften dieses Objekts kann auf die persistenten Daten zugegriffen werden. Um persistente Daten zu lesen oder zu schreiben, lesen oder schreiben Sie einfach die Eigenschaften des data-Objekts: var name = so.data.username; so.data.favoriteColor = "red";
// Beschaffe einige persistente Daten // Lege ein persistentes Feld fest
Die Eigenschaften, die Sie am data-Objekt setzen, müssen nicht unbedingt einfache Typen sein, wie z.B. Zahlen oder Strings. Arrays sind beispielsweise auch erlaubt. Das SharedObject hat auch keine save( )-Methode. Es hat eine flush( )-Methode, die den derzeitigen Status des SharedObjects sofort speichert. Allerdings ist der Aufruf dieser Methode nicht notwendig: Eigenschaften, die im data-Objekt eines SharedObjects festgesetzt sind, werden beim Entladen des Flash-Movies automatisch gespeichert. Beachten Sie, dass SharedObject keine Möglichkeit unterstützt, ein Verfallsdatum oder eine Lebensdauer für die persistenten Daten festzulegen. Denken Sie daran, dass der gesamte in diesem Abschnitt gezeigte Code ActionScriptCode ist, der unter dem Flash-Plug-in läuft, und nicht JavaScript-Code, der im Browser läuft. Wenn Sie den Flash-Persistenzmechanismus in Ihrem JavaScript-Code verwenden wollen, müssen Sie eine Möglichkeit für JavaScript finden, um mit Flash zu kommunizieren. Die Techniken für diesen Zweck werden in Kapitel 23 beschrieben. Beispiel 22-12 3 Vollständige Einzelheiten über die SharedObject-Klasse und Flash-basierte Persistenz finden Sie auf der AdobeWebsite unter http://www.adobe.com/support/flash/action_scripts/local_shared_object/. Ich habe von der Flashbasierten Persistenz durch Brad Neuberg erfahren, der die Pionierarbeit für ihre Verwendung in clientseitigem JavaScript in seinem AMASS-Projekts geleistet hat (http://codinginparadise.org/projects/storage/README. html). Als dieses Buch geschrieben wurde, war dieses Projekt noch in der Entwicklung. Weiterführende Informationen über die clientseitige Persistenz finden Sie unter Umständen auch in Brads Blog (http://codinginparadise.org).
19.5 Cookie-Alternativen |
515
clientseitiges JavaScript
Das Flash-Plug-in der Versionen 6 und höher ermöglicht clientseitige Persistenz über die Objektklasse Shared, die per ActionScript-Code in einem Flash-Movie skriptgesteuert werden kann.3 Dazu erzeugen Sie ein SharedObject mit ActionScript-Code wie z.B. dem folgenden. Beachten Sie, dass Sie einen Namen (entsprechend dem Cookie-Namen) für Ihre persistenten Daten angeben müssen:
491-0.book Seite 516 Mittwoch, 4. April 2007 9:55 09
e-bol.net zeigt die Verwendung der ExternalInterface-Klasse (die in Flash 8 und höher enthalten ist), die den Aufruf von ActionScript-Methoden von JavaScript aus spielend einfach macht. Die Beispiele 19-3 und 19-4 weiter unten in diesem Kapitel verwenden einen primitiveren Kommunikationsmechanismus zur Verbindung von JavaScript mit ActionScript. Mithilfe der GetVariable( )- und SetVariable( )-Methoden des Flash-Plug-inObjekts kann JavaScript ActionScript-Variablen abfragen und setzen, und die ActionScript-Funktion fscommand( ) sendet Daten an JavaScript.
19.5.2.1 Speicherlimits In der Standardeinstellung erlaubt der Flash-Player bis zu 100 KB persistente Daten pro Website. Der Benutzer kann diese Beschränkung bis auf 10 KB herunter- oder bis auf 10 MB heraufsetzen. Alternativerweise kann der Benutzer unbegrenzte oder überhaupt keine Speicherkapazität für persistente Daten zulassen. Versucht eine Website, die Beschränkung zu überschreiten, fordert Flash den Benutzer auf, eine erweiterte Speicherkapazität für Ihre Website zuzulassen oder zu verweigern.
19.5.2.2 Persistente Daten gemeinsam benutzen In der Standardeinstellung sind persistente Daten in Flash nur für das Movie zugänglich, das sie erzeugt hat. Es ist aber möglich, diese Einschränkung zu lockern und zuzulassen, dass zwei Movies im gleichen Verzeichnis oder an beliebigen Stellen auf dem gleichen Server Zugang zu den persistenten Daten haben. Das wird ähnlich wie beim path-Attribut eines Cookies gemacht. Wenn Sie ein SharedObjekt mit SharedObject.getLocal( ) erzeugen, können Sie einen Pfad als zweites Argument übergeben. Dieser Pfad muss ein Präfix des tatsächlichen Pfads in der URL des Movies sein. Jedes Movie, das den gleichen Pfad verwendet, kann die von diesem Movie gespeicherten persistenten Daten verwenden. Der folgende Code erzeugt beispielsweise ein SharedObject, das auch von jedem anderen Flash-Movie verwendet werden kann, das vom gleichen Webserver stammt: var so = SharedObject.getLocal("Meine/Gemeinsamen/Persistenten/Daten", // Objektname "/"); // Pfad
Wenn Sie die SharedObject-Klasse per Skript von JavaScript aus steuern, haben Sie wahrscheinlich kein Interesse daran, persistente Daten von mehreren Flash-Movies gemeinsam verwenden zu lassen. Wichtiger wird es für Sie sein, Daten zwischen Webseiten zu teilen, die das gleiche Movie per Skript steuern (siehe Beispiel 19-3 im nächsten Abschnitt).
19.5.3 Beispiel: Persistente Objekte Dieser Abschnitt schließt mit einem ausführlichen Beispiel, das eine gemeinsame API für die drei Persistenzmechanisms definiert, die Sie in diesem Kapitel studiert haben. Beispiel 19-3 definiert eine PObject-Klasse für persistente Objekte. Die PObject-Klasse funktio-
516 | Kapitel 19: Cookies und Persistenz auf der Clientseite
491-0.book Seite 517 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Nachdem Ihr onload-Handler aufgerufen wurde, können Sie die persistenten Daten einfach dadurch verwenden, dass Sie die Eigenschaften von PObject lesen. Das machen Sie wie bei jedem regulären JavaScript-Objekt. Um neue persistente Daten zu speichern, setzen Sie diese Daten als Eigenschaften (des Typs Boolean, Number oder String) des PObject. Rufen Sie dann die save( )-Methode von PObject auf, und geben optional eine Lebensdauer (in Tagen) für die Daten an. Um die persistenten Daten zu löschen, rufen Sie die forget( )-Methode des PObject auf. Die hier definierte PObject-Klasse verwendet die IE-basierte Persistenz, wenn der Code unter IE läuft. Ansonsten sucht sie nach einer passenden Version des Flash-Plug-ins und verwendet die Flash-basierte Persistenz, falls sie zur Verfügung steht. Sind beide Möglichkeiten nicht vorhanden, wird auf Cookies zurückgegriffen.4 Die PObject-Klasse speichert nur einfache Werte und konvertiert Zahlen und Boolesche Werte beim Auslesen in Strings. Array- und Objektwerte können als Strings serialisiert werden. Diese Strings können in Arrays und Objekte zurückgeparst werden (siehe z.B. http://www.json.org), auch wenn dieses Beispiel das nicht macht. Beispiel 19-3 ist lang, aber gut kommentiert und sollte einfach nachvollziehbar sein. Lesen Sie auf jeden Fall den ausführlichen Einführungskommentar, der die PObjectKlasse und ihre API dokumentiert. Beispiel 19-3: PObject.js: Persistente Objekte für JavaScript /** * PObject.js: JavaScript-Objekte, die über mehrere Browsersitzungen hinweg persistent sind * und von Webseiten mit gleichem Verzeichnis und Host gemeinsam verwendet werden können. * * Dieses Modul definiert einen PObject( )-Konstruktor zur Erzeugung eines persistenten * Objekts. * PObject-Objekte haben zwei öffentliche Methoden. save( ) speichert bzw. "persistiert" die * derzeitigen Eigenschaften des Objekts. forget( ) löscht die persistenten * Eigenschaften des Objekts. Um eine persistente Eigenschaft an einem PObject zu definieren, 4 Es besteht auch die Möglichkeit, eine Persistenzklasse zu definieren, die so weit wie möglich Cookies verwendet und auf eine auf IE oder Flash basierende Persistenz zurückgreift, falls Cookies deaktiviert wurden.
19.5 Cookie-Alternativen |
517
clientseitiges JavaScript
niert ähnlich wie die Cookie-Klasse in Beispiel 19-2. Mit dem PObject( )-Konstruktor wird ein persistentes Objekt erzeugt, an das der Name, die Standardwerte und eine onload-Handler-Funktion übergeben werden. Der Konstruktor erzeugt ein neues JavaScript-Objekt und versucht, die bereits unter dem von Ihnen angegebenen Namen gespeicherten persistenten Daten zu laden. Findet er diese Daten, parst er sie in einen Satz von Name/Wert-Paaren und setzt diese Paare als Eigenschaften des neu erstellten Objekts. Findet er keine bereits gespeicherten Daten, verwendet er die Eigenschaften der von Ihnen angegebenen Standardobjekte. In beiden Fällen wird die von Ihnen festgelegte onload-Handler-Funktion asynchron aufgerufen, sobald Ihre persistenten Daten für den Gebrauch bereitstehen.
491-0.book Seite 518 Mittwoch, 4. April 2007 9:55 09
setzen Sie die Eigenschaft am Objekt einfach so, als wäre es ein reguläres JavaScriptObjekt, und rufen dann die save( )-Methode auf, um den derzeitigen Status des Objekts zu speichern. Die Namen "save" und "forget" dürfen Sie nicht als Eigenschaftsnamen verwenden. Eigenschaftsnamen dürfen auch nicht mit $ beginnen. PObject ist für die Verwendung mit Eigenschaftswerten vom Typ String gedacht. Sie können auch Eigenschaften vom Typ Boolean und Number speichern, sie werden aber beim Auslesen zu Strings konvertiert. Wird ein PObject erzeugt, so werden die persistenten Daten gelesen und als reguläre JavaScript-Eigenschaften im neu erzeugten Objekt gespeichert. Das PObject wird genau wie ein reguläres JavaScript-Objekt verwendet. Allerdings sind persistente Eigenschaften nicht immer bereit, wenn der PObject( )-Konstruktor zurückkehrt. Sie sollten deshalb auf eine asynchrone Benachrichtigung warten, indem Sie eine onload-Handler-Funktion an den Konstruktor übergeben. Konstruktor: PObject(name, defaults, onload): Argumente: name
Ein Name, der dieses persistente Objekt identifiziert. Eine einzelne Seite kann mehrere PObject-Objekte enthalten, und PObjects sind allen Seiten im selben Verzeichnis zugänglich. Daher sollte dieser Name innerhalb des Verzeichnisses eindeutig sein. Ist dieses Argument null oder nicht angegeben, so wird der Dateiname (aber nicht das Verzeichnis) verwendet, der die Webseite enthält.
defaults
Ein optionales JavaScript-Objekt. Kann kein gespeicherter Wert für das persistente Objekt gefunden werden (was der Fall ist, wenn ein PObject zum ersten Mal erzeugt wird), werden die Eigenschaften dieses Objekts in das neu erzeugte PObject kopiert.
onload
Die (asynchron) aufzurufende Funktion, wenn persistente Werte in das PObject geladen wurden und bereitstehen. Diese Funktion wird mit zwei Argumenten aufgerufen: einer Referenz auf das PObject und dem PObject-Namen. Diese Funktion wird aufgerufen, *nachdem* der PObject( )-Konstruktor zurückkehrt. PObject -Eigenschaften sollten nicht vor diesem Schritt verwendet werden.
Method PObject.save(lebensdauerInTagen): Speichere die Eigenschaften eines PObjects. Diese Methode speichert die Eigenschaften des PObject und stellt sicher, dass sie mindestens für die angegebene Anzahl an Tagen persistent sind. Method PObject.forget( ): Lösche die Eigenschaften des PObject. Speichere dann das "leere" PObject in den persistenten Speicher und veranlasse, wenn möglich, das Ablaufen desselben.
518 | Kapitel 19: Cookies und Persistenz auf der Clientseite
491-0.book Seite 519 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 19-3: PObject.js: Persistente Objekte für JavaScript (Fortsetzung)
// Das ist die KonstruktorFunktion PObject(name, defaults, onload) { if (!name) { // Wurde kein Name angegeben, verwende die letzte Komponente der URL name = window.location.pathname; var pos = name.lastIndexOf("/"); if (pos != -1) name = name.substring(pos+1); } this.$name = name; // Speichere unseren Namen // Delegiere das einfach an eine private, in der Implementierung definierte $init( )// Methode. this.$init(name, defaults, onload); }
19.5 Cookie-Alternativen |
519
clientseitiges JavaScript
* Implementierungshinweise: * * Dieses Modul definiert eine einzige PObject-API mit drei unterschiedlichen * Implementierungen dieser API. In Internet Explorer wird der IE-spezifische * "UserData"-Persistenzmechanismus verwendet. Auf allen anderen Browsern mit * Adobe-Flash-Plug-in wird der Flash-SharedObject-Persistenzmechanismus * verwendet. Nicht-IE-Browser, die kein Flash haben, greifen auf die * Implementierung mit Cookies zurück. Da die Flash-Implementierung * keine Verfallsdaten für gespeicherte Daten unterstützt, existieren Daten, die mit diesem * Mechanismus gespeichert werden, bis sie gelöscht werden. * * PObjects gemeinsam verwenden: * * Mit einem PObject in einer Seite gespeicherte Daten sind auch anderen Seiten * im gleichen Verzeichnis des gleichen Servers zugänglich. Wird die Cookie* Implementierung verwendet, können Seiten in Unterverzeichnissen die in übergeordneten * Verzeichnissen erzeugten Eigenschaften von PObjects lesen (aber nicht schreiben). Wird die * Flash-Implementierung verwendet, so kann jede Seite auf dem Webserver auf die gemeinsamen * Daten zugreifen, sofern sie mogelt und eine modifizierte Version dieses Moduls verwendet. * * Unterschiedliche Browseranwendungen speichern ihre Cookies getrennt und * persistente Daten, die mit Cookies in einem Browser gespeichert werden, sind mit * einem anderen Browser nicht zugänglich. Wenn zwei Browser allerdings die gleiche * Installation des Flash-Plug-ins verwenden, können diese Browser die mit dieser * Flash-Implementierung gespeicherten persistenten Daten gemeinsam benutzen. * * Sicherheitshinweise: * * Die über ein PObject gespeicherten Daten werden auf der Benutzerfestplatte unverschlüsselt * gespeichert. Auf dem Rechner laufende Anwendungen können auf die Daten zugreifen. PObject * ist also nicht für die Speicherung empfindlicher Informationen geeignet, wie z.B. von * Kreditkartennummern, Passwörtern, und Bankkontonummern. */
491-0.book Seite 520 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 19-3: PObject.js: Persistente Objekte für JavaScript (Fortsetzung) // Speichere den aktuellen Status dieses PObject für mindestens so viele Tage wie angegeben. PObject.prototype.save = function(lebensdauerInTagen) { // Serialisiere die Eigenschaften des Objekts zuerst in einen einzigen String var s = ""; // Beginne mit einem leeren String for(var name in this) { // Durchlaufe die Eigenschaften if (name.charAt(0) == "$") continue; // Überspringe private $-Eigenschaften var wert = this[name]; // Beschaffe den Eigenschaftswert var typ = typeof wert; // Beschaffe den Eigenschaftstyp // Überspringe Eigenschaften vom Typ Object oder Function if (typ == "object" || typ == "function") continue; if (s.length > 0) s += "&"; // Trenne Eigenschaften mit & // Füge den Eigenschaftnamen und codierten Wert hinzu s += name + ':' + encodeURIComponent(wert); } // Delegiere das an eine private, in der Implementierung definierte Methode, die // die eigentliche Speicherung dieses serialisierten Strings durchführt. this.$save(s, lebensdauerInTagen); }; PObject.prototype.forget = function( ) { // Lösche zuerst die serialisierbaren Eigenschaften dieses Objekts mit Hilfe // der gleichen Eigenschaftsauswahlkriterien wie in save( ). for(var name in this) { if (name.charAt(0) == '$') continue; var wert = this[name]; var typ = typeof wert; if (typ == "function" || typ == "object") continue; delete this[name]; // Lösche die Eigenschaft } // Entferne alle vorher gespeicherten Daten, und lasse sie ablaufen, durch Speichern // des leeren Strings mit einer Lebensdauer von 0. this.$save("", 0); }; // Parse den String s in Name/Wert-Paare, und lege sie als Eigenschaften von this fest. // Ist der String null oder leer, kopiere stattdessen die Eigenschaften aus den Defaults. // Diese private Utility-Methode wird von der unten stehenden $init( )// Implementierung verwendet. PObject.prototype.$parse = function(s, defaults) { if (!s) { // Ist kein String vorhanden, so verwende stattdessen die Defaulteigenschaften if (defaults) for(var name in defaults) this[name] = defaults[name]; return; } // Die Name/Wert-Paare werden durch Ampersands voneinander getrennt und // die einzelnen Namen und Werte durch Doppelpunkte. // Wir verwenden die split( )-Methode, um alles zu parsen. var eigsn = s.split('&'); // Unterteile es in ein Array mit Name/Wert-Paaren for(var i = 0; i < eigsn.length; i++) { // Durchlaufe die Name/Wert-Paare
520 | Kapitel 19: Cookies und Persistenz auf der Clientseite
491-0.book Seite 521 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 19-3: PObject.js: Persistente Objekte für JavaScript (Fortsetzung) var eig = eigsn[i]; var a = eig.split(':'); // Unterteile jedes Name/Wert-Paar am Doppelpunkt this[a[0]] = decodeURIComponent(a[1]); // Entschlüssele und speichere die Eigenschaft } };
clientseitiges JavaScript
/* * Den implementierungsspezifischen Teil des Moduls sehen Sie unten. * Für jede Implementierung definieren wir eine $init( )-Methode, die * persistente Daten lädt, und eine $save( )-Methode, die sie speichert. */ // Finde heraus, ob wir in IE sind. Falls nicht, schaue nach, ob wir ein Flash// Plug-in installiert haben und ob seine Version hoch genug ist var istIE = navigator.appName == "Microsoft Internet Explorer"; var hatFlash7 = false; if (!istIE && navigator.plugins) { // Wenn wir die Netscape-Plug-in-Architektur verwenden var flashplayer = navigator.plugins["Shockwave Flash"]; if (flashplayer) { // Wenn wir ein Flash-Plug-in haben // Extrahiere die Versionsnummer var flashversion = flashplayer.description; var flashversion = flashversion.substring(flashversion.search("\\d")); if (parseInt(flashversion) >= 7) hatFlash7 = true; } } if (istIE) { // Wenn wir uns in IE befinden // Der PObject( )-Konstruktor delegiert an diese Initialisierungsfunktion PObject.prototype.$init = function(name, defaults, onload) { // Erzeuge ein unsichtbares Element mit userData-Behavior zur Datenspeicherung var div = document.createElement("div"); // Erzeuge ein -Tag this.$div = div; // Speichere es div.id = "PObject" + name; // Gib ihm einen Namen div.style.display = "none"; // Mache es unsichtbar // Das ist der IE-spezifische Trick, mit dem die Persistenz funktioniert. // Das "userData"-Verhalten fügt diesem -Element die getAttribute( )-, // setAttribute( )-, load( )- und save( )-Methoden hinzu. Wir verwenden sie // weiter unten. div.style.behavior = "url('#default#userData')"; document.body.appendChild(div);
// Füge das Element ins Dokument ein
// Jetzt rufen wir ggf. bereits gespeicherte, persistente Daten ab. div.load(name); // Lade die unter unserem Namen gespeicherten Daten // Die Daten bestehen aus mehreren Attributen. Uns interessiert davon nur ein // Attribut. Der Name "daten" für das Attribut ist frei gewählt. var daten = div.getAttribute("daten");
19.5 Cookie-Alternativen |
521
491-0.book Seite 522 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 19-3: PObject.js: Persistente Objekte für JavaScript (Fortsetzung) // Parse die abgerufenen Daten, und unterteile sie in Objekteigenschaften this.$parse(daten, defaults); // Wenn ein onload-Callback existiert, veranlasse einen asynchronen Aufruf // nach dem Zurückkehren des PObject( )-Konstruktors. if (onload) { var pobj = this; // In der eingebetteten Funktion kann "this" nicht verwendet // werden setTimeout(function( ) { onload(pobj, name);}, 0); } } // Speichere den aktuellen Stand des persistenten Objekts PObject.prototype.$save = function(s, lebensdauerInTagen) { if (lebensdauerInTagen) { // Etwaige Lebensdauer in ein Verfallsdatum konvertieren var jetzt = (new Date( )).getTime( ); var laeuftAb = jetzt + lebensdauerInTagen * 24 * 60 * 60 * 1000; // Lege das Verfallsdatum als Stringeigenschaft des -Tags fest this.$div.laeuftAb = (new Date(laeuftAb)).toUTCString( ); } // Speichere die Daten jetzt als persistente Daten this.$div.setAttribute("daten", s); // Setze Text als Attribut des -Tags this.$div.save(this.$name); // und mache das Attribut persistent }; } else if (hasFlash7) { // Das ist die Flash-basierte Implementierung PObject.prototype.$init = function(name, defaults, onload) { var moviename = "PObject_" + name; // id des -Tags var url = "PObject.swf?name=" + name; // URL der Movie-Datei // Wenn der Flash-Player läuft und unsere Daten bereithält, // benachrichtigt er uns mit einem FSCommand. Wir müssen einen // Handler definieren, der in diesem Fall aufgerufen wird. var pobj = this; // wird von der eingebetteten Funktion verwendet // Flash verlangt, dass wir unsere Funktion mit diesem globalen Symbol benennen window[moviename + "_DoFSCommand"] = function(kommando, args) { // Wir wissen, dass Flash bereit ist. Also fragen wir unsere persistenten Daten ab var daten = pobj.$flash.GetVariable("daten") pobj.$parse(daten, defaults); // Parse Daten oder kopiere Defaults if (onload) onload(pobj, name); // Rufe onload-Handler auf, falls vorhanden }; // Erzeuge ein -Tag zum Speichern unseres Flash// Movies. Die Verwendung eines // Tags entspricht dem Standard besser, scheint aber Probleme beim // Empfang des FSCommand zu machen. Wir werden Flash nie // unter IE verwenden, was die Sache stark vereinfacht. var movie = document.createElement("embed"); // Element, das das Movie enthält
522 | Kapitel 19: Cookies und Persistenz auf der Clientseite
491-0.book Seite 523 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 19-3: PObject.js: Persistente Objekte für JavaScript (Fortsetzung)
movie.setAttribute("id", moviename); // Element-id movie.setAttribute("name", moviename); // und -Name movie.setAttribute("type", "application/x-shockwave-flash"); movie.setAttribute("src", url); // Das ist die URL des Movies // Setze das Movie unauffällig in die rechte obere Ecke movie.setAttribute("width", 1); // Mit einem Wert von 0 funktioniert es nicht movie.setAttribute("height", 1); movie.setAttribute("style", "position:absolute; left:0px; top:0px;"); // Füge das Movie ins Dokument ein // Und speichere es für später
}; PObject.prototype.$save = function(s, lebensdauerInTagen) { // Um die Daten persistent zu machen, setzen wir sie einfach als eine Variable am // Flash-Movie. Der ActionScript-Code im Movie macht die Daten persistent. // Beachte, dass die Flash-Persistenz keine Zeitbegrenzung unterstützt. this.$flash.SetVariable("daten", s); // Fordere Flash auf, den Text zu speichern }; } else { /* Wenn wir weder IE noch Flash 7 haben, nehmen wir Cookies */ PObject.prototype.$init = function(name, defaults, onload) { var alleCookies = document.cookie; // Beschaffe alle Cookies var daten = null; // Annehmen, dass keine Cookie// Daten vorhanden sind var start = alleCookies.indexOf(name + '='); // Suche nach dem Cookie-Start if (start != -1) { // Gefunden start += name.length + 1; // Cookie-Namen überspringen var ende = alleCookies.indexOf(';', start); // Ende des Cookies suchen if (ende == -1) ende = alleCookies.length; daten = alleCookies.substring(start, ende); // Extrahiere die Cookie-Daten } this.$parse(daten, defaults); // Parse den Cookie-Wert in Eigenschaften if (onload) { // Rufe den onload-Handler asynchron auf var pobj = this; setTimeout(function( ) { onload(pobj, name);}, 0); } }; PObject.prototype.$save = function(s, lebensdauerInTagen) { var cookie = this.$name + '=' + s; // Cookie-Name und -Wert if (lebensdauerInTagen != null) // Füge Verfallsdatum hinzu cookie += "; max-age=" + (lebensdauerInTagen*24*60*60); document.cookie = cookie; // Speichere den Cookie }; }
19.5 Cookie-Alternativen |
523
491-0.book Seite 524 Mittwoch, 4. April 2007 9:55 09
e-bol.net 19.5.3.1 ActionScript-Code für Flash-Persistenz Der Code in Beispiel 19-3 ist noch unvollständig. Die Flash-basierte Persistenzimplementierung braucht ein Flash-Movie namens PObject.swf. Das Movie ist nichts anderes als eine kompilierte ActionScript-Datei. Beispiel 19-4 zeigt den ActionScript-Code. Beispiel 19-4: ActionScript-Code für die Flash-basierte Persistenz class PObject { static function main( ) { // SharedObject ist in Flash 6 vorhanden, ist aber noch nicht gegen // Cross-Domain-Scripting geschützt. Also müssen wir die Flash 7 // -Version des Flash-Players haben. var version = getVersion( ); version = parseInt(version.substring(version.lastIndexOf(" "))); if (isNaN(version) || version < 7) return; // Erzeuge ein SharedObject zur Speicherung unserer persistenten Daten. // Der Name des Objekts wird in der Movie-URL wie folgt übergeben: // PObject.swf?name=name _root.so = SharedObject.getLocal(_root.name); // Rufe die ursprünglichen Daten ab, und speichere sie unter _root.data. _root.data = _root.so.data.data; // Beobachte die Datenvariable. Ändert sie sich, dann speichere ihren neuen Wert // persistent. _root.watch("daten", function(eigName, wertAlt, wertNeu) { _root.so.data.daten = wertNeu; _root.so.flush( ); }); // Benachrichtige JavaScript, dass es die persistenten Daten jetzt abrufen kann. fscommand("init"); } }
Der ActionScript-Code ist recht einfach. Er beginnt mit der Erzeugung eines SharedObjects und verwendet einen (von JavaScript) angegebenen Namen im URL-Abfrageteil des Movie-Objekts. Durch die Erzeugung dieses SharedObject werden die persistenten Daten geladen, die in diesem Fall einfach aus einem einzigen String bestehen. Dieser Datenstring wird mit der fscommand( )-Funktion an JavaScript zurückgegeben. Die Funktion ruft den in JavaScript definierten doFSCommand-Handler auf. Der ActionScript-Code legt ebenfalls eine Handler-Funktion fest, die immer dann aufgerufen wird, wenn sich die daten-Eigenschaft des root-Objekts ändert. Der JavaScript-Code verwendet SetVariable( ), um die datenEigenschaft festzulegen, und diese ActionScript-Handler-Funktion wird als Antwort aufgerufen, wodurch die Daten persistent werden.
524 | Kapitel 19: Cookies und Persistenz auf der Clientseite
491-0.book Seite 525 Mittwoch, 4. April 2007 9:55 09
e-bol.net Der in der PObject.as-Datei von Beispiel 19-4 gezeigte ActionScript-Code muss in eine PObject.swf-Datei kompiliert werden, bevor er mit dem Flash-Player verwendet werden kann. Das machen Sie mit dem Open Source-ActionScript-Compiler mtasc (erhältlich unter http://www.mtasc.org). Rufen Sie den Compiler wie folgt auf: mtasc -swf PObject.swf -main -header 1:1:1 PObject.as
19.6 Persistente Daten und Sicherheit Die Dokumentation am Anfang von Beispiel 19-3 zeigt Sicherheitsbedenken auf, die Sie bei der Verwendung clientseitiger Persistenz im Auge behalten sollten. Alle Daten, die auf der Festplatte des Benutzers gespeichert werden, stehen dort in unverschlüsseltem Format. Sie sind daher neugierigen Benutzern zugänglich, die ebenfalls auf den Rechner Zugriff haben, sowie böswilliger Software (wie z.B. Spyware), die auf dem Rechner liegt. Aus diesem Grund sollte keine Art der clientseitigen Persistenz zur Speicherung empfindlicher Informationen verwendet werden, also von Passwörtern, Bankkontonummern usw. Denken Sie daran: Nur weil ein Benutzer etwas in ein Formularfeld eintippt, während er mit Ihrer Website kommuniziert, bedeutet das nicht, dass er diese Werte auf seiner Festplatte speichern möchte. Nehmen wir beispielsweise eine Kreditkartennummer. Das ist eine empfindliche Information, die Leute in ihren Geldbörsen versteckt halten. Wenn Sie diese Informationen als persistente Daten auf der Clientseite speichern, ist es fast so, als würden Sie die Kreditkartennummer auf ein Stück Papier schreiben und es auf die Tastatur des Benutzers kleben. Da Spyware überall eindringt (zumindest auf Windows-Plattformen), können Sie die Nummer praktisch gleich im Internet bekannt geben. Denken Sie auch daran, dass viele Webbenutzer Websites misstrauen, die Cookies oder andere persistente Mechanismen verwenden, die irgendetwas in Richtung »Verfolgung« betreiben. Versuchen Sie die in diesem Kapitel besprochenen Persistenzmechanismen dazu zu verwenden, dem Benutzer auf Ihrer Site ein positives Erlebnis zu verschaffen; verwenden Sie Persistenzmechanismen nicht als Datensammelmechanismus.
19.6 Persistente Daten und Sicherheit |
525
clientseitiges JavaScript
mtasc erstellt eine SWF-Datei, die die PObject.main( )-Methode des ersten Frames im Movie aufruft. Wenn Sie stattdessen die Flash-IDE verwenden, müssen Sie PObject. main( ) ausdrücklich vom ersten Frame aus aufrufen. Die Alternative ist, einfach den Code aus der main( )-Methode zu kopieren und in das erste Frame einzufügen.
491-0.book Seite 526 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Chapter 1
KAPITEL 20
HTTP skripten
Das Hypertext Transfer Protocol (HTTP) legt fest, wie Webbrowser Dokumente von Webservern anfordern und Formularinhalte an diese übertragen und wie Webserver auf diese Anfragen und Übertragungen antworten. Webbrowser bewältigen natürlich jede Menge HTTP. Normalerweise wird HTTP allerdings nicht von Skripten aus kontrolliert, sondern hinter den Kulissen verwendet, wenn der Benutzer einen Link anklickt, ein Formular übermittelt oder eine URL eingibt. Normalerweise, aber nicht immer: JavaScriptCode kann in Skripten mit HTTP arbeiten. HTTP-Requests können initiiert werden, wenn ein Skript die location-Eigenschaft eines Window-Objekts festlegt oder die submit( )-Methode eines Form-Objekts aufruft. In beiden Fällen lädt der Browser eine neue Seite ins Fenster und überschreibt das dort laufende Skript. Diese triviale Art, HTTP per Skript zu betreiben, kann in einer Webseite mit mehreren Frames sinnvoll sein, ist aber nicht das Thema dieses Kapitels. Vielmehr betrachten wir hier, wie JavaScript-Code mit einem Webserver kommunizieren kann, ohne den Webbrowser zu veranlassen, die gerade angezeigte Seite neu zu laden. Die Tags , und haben src-Attribute. Setzt ein Skript diese Eigenschaften auf eine URL, wird ein HTTP GET-Request gestartet, um den Inhalt der URL herunterzuladen. Ein Skript kann also Informationen an einen Webserver übergeben, indem die Information in den Query-String-Teil einer Bild-URL codiert und das srcAttribut eines -Elements zu dieser URL gesetzt wird. Der Webserver muss zwar als Antwort ein Bild zurückgeben, aber das kann unsichtbar sein: beispielsweise ein transparentes Bild, das 1 Pixel hoch und 1 Pixel breit ist.1
1 Bilder dieser Art werden ab und zu Web Bugs genannt. Sie haben einen schlechten Ruf, da Datenschutzprobleme entstehen, wenn Web Bugs verwendet werden, um Informationen an einen anderen Server zu übermitteln als an den, von dem aus die Webseite geladen wurde. Eine übliche und legitime Verwendung des Web Bugs über einen dritten Server ist zur Trefferzählung und Verkehrsanalyse. Wenn das Skript der Webseite die src-Eigenschaft eines Bildes veranlasst, Informationen an den Server zurückzusenden, über den die Seite ursprünglich geladen wurde, brauchen Sie sich über Datenschutzprobleme keine Gedanken zu machen.
526 |
491-0.book Seite 527 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Selbst das -Tag hat ein src-Attribut, das gesetzt werden kann, um einen dynamischen HTTP-Request durchzuführen. Die Verwendung des -Tags zum Durchführen von HTTP-Requests ist besonders attraktiv, da kein Parsen notwendig ist, wenn die Serverantwort aus JavaScript-Code besteht: Der JavaScript-Interpreter führt die Serverantwort einfach aus. Das Steuern von HTTP über die Tags , und ist zwar möglich, aber recht schwierig, wenn das Skript portabel sein soll. Dieses Kapitel zeigt Ihnen eine andere, leistungsfähigere Möglichkeit, dies zu erreichen. Das XMLHttpRequest-Objekt wird von modernen Browsern gut unterstützt und gibt Ihnen vollen Zugang zum HTTPProtokoll. Neben normalen GET-Requests können Sie auch POST- und HEAD-Requests durchführen. XMLHttpRequest kann die Antwort des Webservers synchron oder asynchron zurückgeben und den Inhalt als Text- oder DOM-Dokument zur Verfügung stellen. Trotz seines Namens ist das XML-Objekt HttpRequest nicht auf XML-Dokumente beschränkt: Es kann jede Art von Text-Dokument abrufen. Das XMLHttpRequestObjekt ist der Hauptbaustein einer Webanwendungsarchitektur, die unter dem Namen Ajax bekannt ist. Wir werden Ajax-Anwendungen besprechen, nachdem wir gesehen haben, wie XMLHttpRequest funktioniert. Am Kapitelende werde ich auf das Thema HTTP per -Tags zurückkommen und Ihnen zeigen, wie Sie sie verwenden können, wenn kein XMLHttpRequest-Objekt verfügbar ist.
20.1 Verwendung von XMLHttpRequest HTTP per XMLHttpRequest läuft in drei Schritten ab: • Erzeugung eines XMLHttpRequest-Objekts • den HTTP-Request konfigurieren und ihn an einen Webserver übergeben • die Serverantwort synchron oder asynchron empfangen
20.1 Verwendung von XMLHttpRequest |
527
clientseitiges JavaScript
-Tags gibt es in HTML noch nicht so lange. Sie sind oft vielseitiger als Tags, da der Webserver ein Ergebnis zurückgeben kann, das – anders als eine binäre Bilddatei – durch das Skript gelesen werden kann. Um ein HTTP-Skript mit dem Tag zu schreiben, codiert das Skript zuerst Informationen für den Webserver in eine URL und setzt dann das Attribut src des auf diese URL. Der Server erzeugt ein HTML-Dokument mit der Antwort und sendet dieses an den Webbrowser zurück, der es im anzeigt. Das muss für den Benutzer nicht sichtbar sein. Es kann zum Beispiel mit CSS versteckt werden. Ein Skript hat zur Serverantwort Zugang, indem es das Document-Objekt des parst. Beachten Sie, dass diese Analyse den Beschränkungen der Same Origin Policy unterliegt, die in Abschnitt 13.8.2 beschrieben wird.
491-0.book Seite 528 Mittwoch, 4. April 2007 9:55 09
e-bol.net Die folgenden Abschnitte beschreiben jeden dieser Schritte ausführlich. Die Beispiele in diesem Abschnitt und im Rest des Kapitels sind Teil einer größeren Einheit. Sie definieren Utility-Funktionen im Namensraum HTTP (siehe Kapitel 10). Keines der folgenden Beispiele enthält jedoch den Code, der diesen Namensraum erzeugt. Im herunterladbaren Beispielcode auf der Webseite zu diesem Buch finden Sie die Datei http.js, die den Code enthält, der den Namensraum HTTP erzeugt, und Sie müssen dazu lediglich die Zeile var HTTP = {}; zu den hier gezeigten Beispielen hinzufügen.
20.1.1 Wie komme ich an ein Request-Objekt? Das XMLHttpRequest-Objekt wurde nie standardisiert, und seine Erzeugung unter dem Internet Explorer unterscheidet sich von anderen Plattformen. (Glücklicherweise ist die API zur Verwendung eines XMLHttpRequest-Objekts nach dessen Erstellung aber unter allen Plattformen dieselbe). Bei den meisten Browsern erzeugen Sie ein XMLHttpRequest-Objekt mit einem einfachen Konstruktor-Aufruf: var request = new XMLHttpRequest( );
In Versionen vor Internet Explorer 7 hat IE keine eingebaute Konstruktorfunktion namens XMLHttpRequest( ). Unter IE 5 und 6 ist XMLHttpRequest ein ActiveX-Objekt, das Sie durch die Übergabe des Objektnamens an den Konstruktor ActiveXObject( ) erzeugen müssen: var request = new ActiveXObject("Msxml2.XMLHTTP");
Leider ist der Objektname in verschiedenen Ausgaben der Microsoft XML-HTTP-Library unterschiedlich. Abhängig von der beim Client installierten Library müssen Sie eventuell stattdessen den folgenden Code verwenden: var request = new ActiveXObject("Microsoft.XMLHTTP");
Beispiel 20-1 ist eine plattformübergreifende Utility-Funktion mit dem Namen HTTP.newRequest( ) zur Erzeugung von XMLHttpRequest-Objekten. Beispiel 20-1: Die HTTP.newRequest( ) Utility // Eine Liste mit XMLHttpRequest-Factory-Funktionen zum Durchprobieren HTTP._factories = [ function( ) { return new XMLHttpRequest( ); }, function( ) { return new ActiveXObject("Msxml2.XMLHTTP"); }, function( ) { return new ActiveXObject("Microsoft.XMLHTTP"); } ]; // Wenn wir eine funktionierende Factory finden, speichern wir sie hier. HTTP._factory = null; // Erzeuge ein neues XMLHttpRequest-Objekt, und gib es zurück. // // Beim ersten Aufruf probieren wir die Factory-Funktionen aus, bis
528 | Kapitel 20: HTTP skripten
491-0.book Seite 529 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 20-1: Die HTTP.newRequest( ) Utility (Fortsetzung) // wir eine finden, die einen Wert ungleich null zurückgibt und keine // Exception auslöst. Die funktionierende Factory merken wir uns für später. // HTTP.newRequest = function( ) { if (HTTP._factory != null) return HTTP._factory( );
clientseitiges JavaScript
for(var i = 0; i < HTTP._factories.length; i++) { try { var factory = HTTP._factories[i]; var request = factory( ); if (request != null) { HTTP._factory = factory; return request; } } catch(e) { continue; } } // Kommen wir hier an, dann haben wir keine passende Factory. // Löse jetzt und für alle zukünftigen Aufrufe eine Exception aus. HTTP._factory = function( ) { throw new Error("XMLHttpRequest wird nicht unterstützt"); } HTTP._factory( ); // Exception auslösen }
20.1.2 Einen Request übermitteln Nachdem ein XMLHttpRequest-Objekt erzeugt wurde, besteht der nächste Schritt darin, einen Request an den Webserver zu senden. Das ist wiederum selbst ein mehrstufiger Vorgang. Zuerst rufen Sie die Methode open( ) auf, um die von Ihnen gewünschte URL anzugeben, und dann die HTTP-Methode des Requests. Die meisten HTTP-Requests werden mit der Methode GET durchgeführt, die einfach den Inhalt der URL herunterlädt. Eine andere nützliche Methode ist POST, die von den meisten HTML-Formularen verwendet wird: Mit ihr können Werte von benannten Variablen in den Request aufgenommen werden. HEAD ist ebenfalls eine nützliche HTTP-Methode: Sie weist den Server an, lediglich die mit der URL assoziierten Header zurückzugeben. Dadurch kann beispielsweise das Änderungsdatum eines Dokuments überprüft werden, ohne den Dokumentinhalt selbst herunterzuladen. Geben Sie die Methode und URL Ihrer Anfrage mit der open( )-Methode an: request.open("GET", url, false);
In der Standardeinstellung führt die open( )-Methode einen asynchronen XMLHttpRequest durch. Die Übergabe von false als drittes Argument fordert eine synchrone Antwort vom Server an. Asynchrone Antworten werden im Allgemeinen vorgezogen, aber synchrone Antworten sind etwas einfacher, weswegen wir diesen Fall zuerst besprechen.
20.1 Verwendung von XMLHttpRequest |
529
491-0.book Seite 530 Mittwoch, 4. April 2007 9:55 09
e-bol.net Zusätzlich zum optionalen dritten Argument kann die open( )-Methode einen Namen und ein Passwort als optionale vierte und fünfte Argumente annehmen. Sie werden verwendet, wenn eine URL von einem Server abgefragt wird, der eine Autorisierung benötigt. Die open( )-Methode sendet den Request nicht wirklich an den Webserver. Sie speichert einfach ihre Argumente, um sie später zu verwenden, wenn der Request tatsächlich gesendet wird. Bevor Sie die Abfrage senden, müssen Sie alle notwendigen Request-Header setzen. Hier sehen Sie einige Beispiele:2 request.setRequestHeader("User-Agent", "XMLHttpRequest"); request.setRequestHeader("Accept-Language", "en"); request.setRequestHeader("If-Modified-Since", lastRequestTime.toString( ));
Beachten Sie, dass der Webbrowser automatisch relevante Cookies zu Ihrem Request hinzufügt. Sie müssen einen Cookie-Header nur dann ausdrücklich setzen, wenn Sie einen künstlichen Cookie an den Server senden wollen. Nachdem Sie das Request-Objekt erzeugt, die open( )-Methode aufgerufen und die Header festgelegt haben, senden Sie den Request an den Server: request.send(null);
Das Argument der send( )-Funktion ist der Body des Requests. Bei HTTP GET-Requests ist dieser immer null. Bei POST-Requests sollte er die an den Server zu sendenden Formulardaten enthalten (siehe Beispiel 20-5). Fürs Erste übergeben Sie einfach null. (Beachten Sie, dass das Argument null zwingend notwendig ist. XMLHttpRequest ist ein Objekt auf der Clientseite, und seine Methoden – zumindest unter Firefox – mögen keine ausgelassenen Argumente, anders als Funktionen im JavaScript-Sprachkern.)
20.1.3 Eine synchrone Antwort erhalten Das XMLHttpRequest-Objekt speichert nicht nur die Einzelheiten des durchgeführten HTTP-Requests, sondern repräsentiert auch die Antwort des Servers. Wenn Sie false als drittes Argument an open( ) übergeben, so ist die send( )-Methode synchron: Sie blockiert und gibt nichts zurück, bis die Serverantwort empfangen wurde.3 send( ) gibt keinen Statuscode zurück. Nach der Rückgabe können Sie den vom Server zurückgegebenen HTTP-Statuscode mit der Eigenschaft status des Request-Objekts über-
prüfen. Die möglichen Werte des Codes werden vom HTTP-Protokoll festgelegt. Der Status 200 bedeutet, dass die Anfrage erfolgreich war und die Antwort vorliegt. Der Status 404 zeigt einen »not found«-Fehler an, der auftritt, wenn die URL nicht vorhanden ist.
2 Einzelheiten zum HTTP-Protokoll sprengen den Umfang des Buches. Konsultieren Sie eine HTTP-Referenz für Details zu diesem und weiteren Headern, die bei HTTP-Requests gesetzt werden können. 3 XMLHttpRequest hat unheimlich leistungsfähige Features, aber seine API ist nicht besonders gut gestaltet. Beispielsweise sollte der Boolesche Wert, der synchrones oder asynchrones Verhalten festlegt, eigentlich ein Argument der Methode send( ) sein.
530 | Kapitel 20: HTTP skripten
491-0.book Seite 531 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Ist eine Anfrage synchron, sieht der auf send( ) folgende Code oft ungefähr so aus: if (request.status == 200) { // Wir haben die Serverantwort erhalten. Zeige den Antworttext an. alert(request.responseText); } else { // Etwas ist schiefgelaufen. Zeige Fehlercode und -meldung an. alert("Error " + request.status + ": " + request.statusText); }
Zusätzlich zum Statuscode und dem Antworttext oder -dokument stellt das XMLHttpRequest-Objekt auch den Zugriff auf die vom Webserver zurückgegebenen HTTP-Header bereit. getAllResponseHeaders( ) gibt die Antwort-Header als ungeparsten Textblock zurück, und getResponseHeader( ) gibt den Wert eines angegebenen Headers zurück. Ein Beispiel: if (request.status == 200) { // Stellen Sie sicher, dass es keine Fehler gab // Stellen Sie sicher, dass die Antwort ein XML-Dokument ist if (request.getResponseHeader("Content-Type") == "text/xml") { var doc = request.responseXML; // Machen Sie jetzt etwas mit dem Antwortdokument } }
Bei der synchronen Verwendung von XMLHttpRequest besteht ein ernstes Problem: Wenn der Webserver seine Antwort abbricht, blockiert die send( )-Methode eine lange Zeit. Die Ausführung von JavaScript hält an, und der Webbrowser kann so aussehen, als ob er sich aufgehängt hätte (das hängt natürlich von der Plattform ab). Hängt der Server sich während eines normalen Ladevorgangs auf, kann der Benutzer im Browserfenster einfach auf Stop klicken und es mit einem anderen Link oder einer anderen URL versuchen. Aber für XMLHttpRequest gibt es keine Stop-Schaltflächen. Die Methode send( ) bietet keine andere Möglichkeit an, die maximale Wartezeit anzugeben, und das Ausführungsmodell von JavaScript auf der Clientseite sieht nur einen Thread vor. Das verbietet dem Skript, einen synchronen XMLHttpRequest nach dessen Absenden zu unterbrechen. Diese Probleme lassen sich umgehen, indem Sie XMLHttpRequest asynchron verwenden.
20.1 Verwendung von XMLHttpRequest |
531
clientseitiges JavaScript
Das XMLHttpRequest-Objekt stellt die Serverantwort als String über die Eigenschaft responseText des Request-Objekts zur Verfügung. Wenn die Antwort ein XML-Dokument ist, können Sie auf das Dokument auch als DOM-Document-Objekt über die Eigenschaft responseXML zugreifen. Damit XMLHttpRequest die Antwort an ein Document-Objekt übergeben kann, muss der Server sein XML-Dokument mit dem MIMETyp »text/xml« identifizieren.
491-0.book Seite 532 Mittwoch, 4. April 2007 9:55 09
e-bol.net
20.1.4 Umgang mit einer asynchronen Response Um ein XMLHttpRequest-Objekt im asynchronen Modus zu verwenden, übergeben Sie true als drittes Argument der open( )-Methode (oder übergehen Sie einfach das dritte Argument: true ist der Default). Daduch sendet die send( )-Methode die Anfrage an den Server und kehrt sofort zurück. Wenn die Antwort des Servers ankommt, steht sie über das XMLHttpRequest-Objekt zur Verfügung. Dazu werden die gleichen Eigenschaften verwendet, die oben für die synchrone Verwendung beschrieben wurden. Eine asynchrone Antwort vom Server ist wie ein asynchroner Mausklick vom Benutzer: Wenn sie stattfindet, müssen Sie benachrichtigt werden. Das machen Sie mit einem Event-Handler. Bei XMLHttpRequest wird der Event-Handler über die Eigenschaft onreadystatechange festgelegt. Wie der Name der Eigenschaft schon sagt, wird die EventHandler-Funktion aufgerufen, wenn sich der Wert der Eigenschaft readyState ändert. readyState ist eine ganze Zahl, die den Status der HTTP-Anfrage angibt, und die möglichen Werte sind in Tabelle 20-1 aufgezählt. Das XMLHttpRequest-Objekt definiert keine symbolischen Konstanten für die in der Tabelle aufgeführten fünf Werte. Tabelle 20-1: Werte für XMLHttpRequest.readyState readyState
Bedeutung
0
open( ) wurde bis jetzt noch nicht aufgerufen.
1
open( ) wurde aufgerufen, aber send( ) noch nicht.
2
send( ) wurde aufgerufen, aber der Server hat noch nicht geantwortet.
3
Daten werden vom Server empfangen. readyState 3 unterscheidet sich in Firefox und Internet Explorer etwas; siehe Abschnitt 20.1.4.1.
4
Die Antwort des Servers ist vollständig.
Da XMLHttpRequest nur diesen einen Event-Handler hat, wird er für alle möglichen Events aufgerufen. Ein typischer onreadystatechange-Handler wird erst einmal beim Aufruf von open( ) und dann einmal beim Aufruf von send( ) aufgerufen. Wenn der erste Teil der Serverantwort eintrifft, erfolgt ein weiterer Aufruf, und ein letzter erfolgt, wenn die Antwort vollständig ist. Im Gegensatz zu den meisten Events in JavaScript auf der Clientseite wird an den onreadystatechange-Handler kein Objekt übergeben. Um festzustellen, warum Ihr Event-Handler aufgerufen wurde, müssen Sie sich die readyState-Eigenschaft des XMLHttpRequest-Objekts ansehen. Leider wird das XMLHttpRequest-Objekt auch nicht als Argument des Event-Handlers übergeben. Sie müssen die Event-Handler-Funktion also so definieren, dass sie auf das Request-Objekt zugreifen kann. Ein typischer Event-Handler einer asynchronen Anfrage sieht so aus: // Erzeuge mit der oben definierten Utility einen XMLHttpRequest var request = HTTP.newRequest( ); // Registriere einen Event-Handler für asynchrone Notifikationen. // Dieser Code schreibt vor, was mit der Antwort zu tun ist, und wird in eine
532 | Kapitel 20: HTTP skripten
491-0.book Seite 533 Mittwoch, 4. April 2007 9:55 09
e-bol.net // eingebettete Funktion gestellt, bevor der request.onreadystatechange = function( ) { if (request.readyState == 4) { // if (request.status == 200) // alert(request.responseText); // } }
Request überhaupt gesendet wird. Die Anfrage ist abgeschlossen Sie war erfolgreich Zeige die Antwort des Servers an
clientseitiges JavaScript
// Einen GET-Request für eine bestimmte URL ausführen. Ohne drittes Argument // ist das hier ein asynchroner Request request.open("GET", url); // Wenn nötig, können wir hier zusätzliche Request-Header angeben. // Jetzt den Request senden. Da es ein GET-Request ist, übergeben wir null als // Body. Da er asynchron ist, blockiert send( ) nicht, sondern // kehrt sofort zurück. request.send(null);
20.1.4.1 Hinweise für readyState 3 Das Objekt XMLHttpRequest wurde nie standardisiert und die Browser handhaben readyState 3 unterschiedlich. Beispielsweise ruft Firefox bei großen Downloads den onreadystatechange-Handler mehrmals in readyState 3 auf, um den derzeitigen Stand des Downloads mitzuteilen. Ein Skript kann diese mehrfachen Aufrufe verwenden, um dem Benutzer den Stand des Downloads anzuzeigen. Im Gegensatz dazu interpretiert Internet Explorer den Event-Handler im engeren Sinne und ruft ihn nur auf, wenn sich der readyState-Wert ändert. Das bedeutet, dass er für readyState 3 nur einmal aufgerufen wird, unabhängig davon, wie groß das heruntergeladene Dokument ist. Zusätzlich unterscheiden sich Browser darin, welcher Teil der Serverantwort in readyState 3 zur Verfügung steht. Obwohl Status 3 bedeutet, dass zumindest ein Teil der Antwort vom Server angekommen ist, sagt die Microsoft-Dokumentation für XMLHttpRequest ausdrücklich, dass eine Abfrage von responseText in diesem Status einem Fehler gleichkommt. Bei anderen Browsern scheint es ein undokumentiertes Feature zu sein, dass responseText den Teil der Serverantwort zurückgibt, der schon angekommen ist. Leider hat keiner der bekannten Browseranbieter sein XMLHttpRequest-Objekt ausreichend dokumentiert. Bis zum Erscheinen eines Standards oder zumindest einer eindeutigen Dokumentation ist es am sichersten, den Wert von readyState zu ignorieren, wenn er nicht 4 ist.
20.1.5 XMLHttpRequest Security Aufgrund der Same Origin Policy (siehe Abschnitt 13.8.2) kann das XMLHttpRequestObjekt HTTP-Requests nur an den Server senden, von dem das verwendete Dokument heruntergeladen wurde. Das ist eine vernünftige Einschränkung, die Sie aber zur Not
20.1 Verwendung von XMLHttpRequest |
533
491-0.book Seite 534 Mittwoch, 4. April 2007 9:55 09
e-bol.net umgehen können, indem Sie ein Skript auf der Serverseite als Proxy verwenden, das den Inhalt einer anderen URL für Sie holt. Diese Sicherheitsbeschränkung für XMLHttpRequest hat eine sehr wichtige Auswirkung: XMLHttpRequest führt HTTP-Requests aus und ist nicht mit anderen URL-Modellen kompatibel. Zum Beispiel funktioniert es nicht mit URLs, die das file://-Protokoll verwenden. Das bedeutet, dass Sie XMLHttpRequest-Skripte nicht von Ihrem lokalen Dateisystem aus testen können. Sie müssen das Testskript auf einem Webserver speichern (oder einen Server auf Ihrem Computer laufen lassen). Damit Ihre Testskripte ihre eigenen HTTP-Requests durchführen können, müssen sie über HTTP an Ihren Webbrowser übertragen werden.
20.2 XMLHttpRequest-Beispiele und Utilities Am Anfang dieses Kapitels habe ich Ihnen die Utility-Funktion HTTP.newRequest( ) vorgestellt, die für jeden beliebigen Browser ein XMLHttpRequest-Objekt beschaffen kann. Zusätzlich können Utility-Funktionen den Gebrauch von XMLHttpRequest vereinfachen. Die hier folgenden Unterabschnitte zeigen Beispiele von Utilities.
20.2.1 Einfache GET-Utilities Beispiel 20-2 ist eine sehr einfache Funktion, die den häufigsten Gebrauch von XMLHttpRequest abdecken kann: Übergeben Sie ihr einfach die zu holende URL und die Funktion, an die der Text der URL übergeben werden soll. Beispiel 20-2: Die HTTP.getText( )-Utility /** * Mit XMLHttpRequest holen Sie den Inhalt der angegebenen URL per * HTTP GET-Request. Kommt die Antwort an, übergeben Sie sie (als * Klartext) an die angegebene Callback-Funktion. * * Diese Funktion blockiert nicht und hat keinen Rückgabewert. */ HTTP.getText = function(url, callback) { var request = HTTP.newRequest( ); request.onreadystatechange = function( ) { if (request.readyState == 4 && request.status == 200) callback(request.responseText); } request.open("GET", url); request.send(null); };
Beispiel 20-3 ist eine triviale Variante, die XML-Dokumente holt und ihre geparste Repräsentation an eine Callback-Funktion übergibt.
534 | Kapitel 20: HTTP skripten
491-0.book Seite 535 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 20-3: Die HTTP.getXML( )-Utility
20.2.2 Nur Header holen Ein Feature von XMLHttpRequest ist, dass es Sie die zu verwendende HTTP-Methode aussuchen lässt. Der HTTP HEAD-Request fordert beim Server die Header einer bestimmten URL an, ohne dabei den Inhalt der URL zurückzugeben. Das kann beispielsweise gemacht werden, um das Änderungsdatum einer Ressource vor dem Herunterladen zu überprüfen. Beispiel 20-4 zeigt Ihnen, wie Sie einen HEAD-Request ausführen. Es enthält eine Funktion zur Übergabe der HTTP-Header-Name/Wert-Paare und zum Speichern dieser Paare als Namen und Werte der Eigenschaften eines JavaScript-Objekts. Außerdem führt es eine Fehlerbehandlungsfunktion ein, die aufgerufen wird, wenn der Server 404 oder einen anderen Fehlercode zurückgibt. Beispiel 20-4: Die HTTP.getHeaders( )-Utility /** * Per HTTP HEAD-Request holen Sie sich die Header der angegebenen URL. * Eingehende Header werden mit HTTP.parseHeaders( ) geparst, und das * Rückgabeobjekt wird an die angegebene Callback-Funktion übergeben. * Schickt der Server einen Fehlercode, rufen Sie stattdessen die angegebene * errorHandler-Funktion auf. Ist kein Error-Handler angegeben, übergeben Sie null an die * Callback-Funktion. */ HTTP.getHeaders = function(url, callback, errorHandler) { var request = HTTP.newRequest( ); request.onreadystatechange = function( ) { if (request.readyState == 4) { if (request.status == 200) { callback(HTTP.parseHeaders(request)); } else { if (errorHandler) errorHandler(request.status, request.statusText); else callback(null); } } }
20.2 XMLHttpRequest-Beispiele und Utilities |
535
491-0.book Seite 536 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 20-4: Die HTTP.getHeaders( )-Utility (Fortsetzung) request.open("HEAD", url); request.send(null); }; // Parse die Response-Header eines XMLHttpRequest-Objekts, und // gib die Header-Namen und -Werte als Eigenschaftsnamen und -werte // eines neuen Objekts zurück. HTTP.parseHeaders = function(request) { var headerText = request.getAllResponseHeaders( ); // Text vom Server var headers = {}; // Das ist unser Rückgabewert var ls = /^\s*/; // Regulärer Ausdruck für führende Leerzeichen var ts = /\s*$/; // Regulärer Ausdruck für Leerzeichen am Ende // Brich die Header in Zeilen auf var lines = headerText.split("\n"); // Zeilen durchlaufen for(var i = 0; i < lines.length; i++) { var line = lines[i]; if (line.length == 0) continue; // Leerzeilen überspringen // Jede Zeile am ersten Doppelpunkt trennen und Whitespace entfernen var pos = line.indexOf(':'); var name = line.substring(0, pos).replace(ls, "").replace(ts, ""); var value = line.substring(pos+1).replace(ls, "").replace(ts, ""); // Name/Wert-Paar des Headers in einem JavaScript-Objekt speichern headers[name] = value; } return headers; };
20.2.3 HTTP POST HTML-Formulare werden oft mit der HTTP POST-Methode an Webserver gesendet. Bei POST-Requests werden die Daten nicht in die URL codiert, sondern im Body des Requests an den Server übergeben. Da Request-Parameter in die URL eines GET-Requests codiert werden, ist die GET-Methode nur geeignet, wenn der Request beim Server keine Nebenwirkungen auslöst – also wenn von wiederholten GET-Requests für die gleiche URL mit den gleichen Parametern die Rückgabe der gleichen Ergebnisse erwartet werden kann. Verursacht ein Request Nebeneffekte (z.B. wenn der Server einige der Parameter in einer Datenbank speichert), sollte stattdessen ein POST-Request verwendet werden. Beispiel 20-5 zeigt, wie ein POST-Request mit Hilfe eines XMLHttpRequest-Objekts durchgeführt wird. Die HTTP.post( )-Methode verwendet die HTTP.encodeFormData( )Funktion, um die Eigenschaften eines Objekts in ein Stringformat zu konvertieren, das als Body eines POST-Requests verwendet werden kann. Der String wird dann an die XMLHttpRequest.send( )-Methode übergeben und wird zum Body des Requests. (Der von HTTP.encodeFormData( ) zurückgebene String kann auch an die GET-URL angehängt werden; verwenden Sie einfach ein Fragezeichen, um die URL von den Daten zu trennen.)
536 | Kapitel 20: HTTP skripten
491-0.book Seite 537 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 20-5 verwendet außerdem die Methode HTTP._getResponse( ). Sie parst die Serverantwort abhängig von deren Typ und wird im nächsten Abschnitt implementiert. Beispiel 20-5: Die HTTP.post( )-Utility clientseitiges JavaScript
/** * Sende einen HTTP POST-Request an die angegebene URL. Verwende Namen * und Werte der Eigenschaften des values-Objekts als Body des Requests. * Parse die Serverantwort je nach Content-Type, und übergib das * Ergebnis an die Callback-Funktion. Tritt ein HTTP-Fehler auf, * so rufe die angegebene errorHandler-Funktion auf. * Ist kein Error-Handler vorhanden, übergib null an die Callback-Funktion. /** HTTP.post = function(url, values, callback, errorHandler) { var request = HTTP.newRequest( ); request.onreadystatechange = function( ) { if (request.readyState == 4) { if (request.status == 200) { callback(HTTP._getResponse(request)); } else { if (errorHandler) errorHandler(request.status, request.statusText); else callback(null); } } } request.open("POST", url); // Dieser Header informiert den Server, wie der Body des Requests // interpretiert werden soll. request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); // Codiere die Eigenschaften des values-Objekts, und sende sie als // Body des Requests. request.send(HTTP.encodeFormData(values)); }; /** * Eigenschafts-Name/Wert-Paare eines Objekts so codieren, als ob sie von * einem HTML-Formular stammen, und zwar im Format application/x-www-form-urlencoded */ HTTP.encodeFormData = function(data) { var pairs = []; var regexp = /%20/g; // Ein regulärer Ausdruck für ein codiertes Leerzeichen for(var name in data) { var value = data[name].toString( ); // Erzeuge ein Name/Wert-Paar, aber codiere erst Namen und Wert, // Die globale Funktion encodeURIComponent ist fast perfekt dafür; // sie codiert Leerzeichen aber als %20 statt "+". Wir müssen das // mit String.replace( ) nachbessern
20.2 XMLHttpRequest-Beispiele und Utilities |
537
491-0.book Seite 538 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 20-5: Die HTTP.post( )-Utility (Fortsetzung) var pair = encodeURIComponent(name).replace(regexp,"+") + '=' + encodeURIComponent(value).replace(regexp,"+"); pairs.push(pair); } // Alle Name/Wert-Paare mit & aneinander anhängen return pairs.join('&'); };
Beispiel 21-14 ist ein weiteres Beispiel, das mit einem XMLHttpRequest-Objekt einen POST-Request durchführt. In diesem Beispiel wird ein Webservice aufgerufen, und statt der Übergabe von Formularwerten im Body des Requests wird der Text eines XMLDokuments übergeben.
20.2.4 HTML, XML und JSON-codierte Responses Bei den meisten bisherigen Beispielen wird die Serverantwort auf einen HTTP-Request als Klartextwert behandelt. Das ist durchaus zulässig, und es ist nirgendwo vorgeschrieben, dass Webserver keine Dokumente mit einem Content-Type von »text/plain« zurückgeben dürfen. Ihr JavaScript-Code kann solche Responses mit den verschiedenen String-Methoden parsen und mit ihnen machen, was immer Sie wollen. Sie können die Serverantwort auch dann als Klartext behandeln, wenn sie einen anderen Content-Type aufweist. Wenn der Server beispielsweise ein HTML-Dokument zurückgibt, können Sie dessen Inhalt mit der Eigenschaft responseText abrufen und ihn dann zum Setzen der innerHTML-Eigenschaft eines Dokumentelements verwenden. Sie können die Serverantwort aber auch auf andere Arten verarbeiten. Wie am Anfang dieses Kapitels beschrieben, können Sie eine geparste Darstellung des XML-Dokuments über die responseXML-Eigenschaft abfragen, wenn der Server eine Response mit dem Content-Type »text/xml« sendet. Der Wert dieser Eigenschaft ist ein DOM-DocumentObjekt, das Sie mit DOM-Methoden durchsuchen und durchlaufen können. Beachten Sie jedoch, dass XML als Datenformat nicht immer die beste Lösung ist. Wenn der Server Daten zur Bearbeitung an das JavaSkript-Skript übergeben will, ist es ineffizient, diese Daten auf der Serverseite in XML-Format zu codieren, das XMLHttpRequestObjekt zu veranlassen, diese Daten in einen Baum von DOM-Knoten zu parsen und dann Ihr Script diesen Baum durchlaufen zu lassen, um die Daten wieder zu extrahieren. Es ist einfacher, den Server die Daten mit dem JavaScript-Objekt und Array als Text codieren zu lassen und den JavaScript-Quelltext an den Webbrowser zu übergeben. Dann »parst« das Skript die Antwort einfach, indem sie an die JavaScript-eval( )-Methode übergeben wird.
538 | Kapitel 20: HTTP skripten
491-0.book Seite 539 Mittwoch, 4. April 2007 9:55 09
e-bol.net Die Datencodierung als JavaScript-Objekt- und -Array-Literale wird als JSON oder JavaScript Object Notation4 bezeichnet. Hier sehen Sie XML- und JSON-Codierungen der gleichen Daten:
clientseitiges JavaScript
Wendell Berry The Unsettling of America What are People For? // JSON-codiert { "name": "Wendell Berry", "books": [ "The Unsettling of America", "What are People For?" ] }
Die HTTP.post( )-Funktion, die in Beispiel 20-5 gezeigt ist, ruft die HTTP._getResponse( )Funktion auf, die den Content-Type-Header untersucht, um das Format der Response zu bestimmen. Beispiel 20-6 ist eine einfache Implementierung von HTTP._getResponse( ), die XML-Dokumente als Document-Objekte zurückgibt, JavaScript- bzw. JSON-Dokumente mit eval( ) auswertet und sonstigen Inhalt als Klartext zurückgibt. Beispiel 20-6: HTTP._getResponse( ) HTTP._getResponse = function(request) { // Vom Server zurückgesandten Content-Type prüfen switch(request.getResponseHeader("Content-Type")) { case "text/xml": // Wenn es ein XML-Dokument ist, geparstes Document-Objekt verwenden. return request.responseXML; case case case case
"text/json": "text/javascript": "application/javascript": "application/x-javascript": // Wenn die Response JavaScript-Code oder ein JSON-codierter Wert ist, // den Text an eval( ) senden, um ihn in einen JavaScript-Wert zu parsen. // NB: Machen Sie das nur, wenn Sie dem Server trauen, von dem der JavaScript// Code kommt! return eval(request.responseText);
4 Weitere Einzelheiten zu JSON finden Sie unter http://json.org. Die Idee stammt von Douglas Crockford, und diese Website enthält Verweise auf JSON-Codierer und -Decodierer für verschiedene Programmiersprachen; sie kann zur Datencodierung nützlich sein, selbst wenn Sie JavaScript nicht verwenden.
20.2 XMLHttpRequest-Beispiele und Utilities |
539
491-0.book Seite 540 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 20-6: HTTP._getResponse( ) (Fortsetzung) default: // In allen anderen Fällen: Response als Text ansehen und String zurückgeben. return request.responseText; } };
Die eval( )-Methode zum Parsen von JSON-codierten Daten, wie sie in Beispiel 20-6 gezeigt wird, sollten Sie nicht verwenden, wenn Sie sich nicht sicher sind, dass der Webserver niemals bösartigen ausführbaren JavaScript-Code statt korrekt codierten JSONDaten schickt. Eine sichere Alternative ist die Benutzung eines JSON-Decoders, der JavaScript-Objekt-Literale »von Hand« parst, ohne dabei eval( ) aufzurufen.
20.2.5 Zeitabbruch eines Requests Ein Mangel des XMLHttpRequest-Objekts ist das Fehlen eines Mechanismus, mit dem sich ein Timeout-Wert für einen Request angeben lässt. Im Fall von synchronen Requests ist das ein schwerer Mangel. Wenn sich des Server aufhängt, verbleibt der Webbrowser in der send( )-Methode, und alles friert ein. Asynchrone Requests können nicht zu einem Einfrieren führen, weil die send( )-Methode nicht blockiert und der Webbrowser damit weiter Benutzerevents verarbeiten kann. Ein Timeout-Problem haben Sie aber trotzdem. Nehmen wir mal an, Ihre Anwendung sendet einen HTTP-Request mit einem XMLHttpRequest-Objekt, wenn der Benutzer auf einen Button klickt. Um mehrfache Requests zu verhindern, empfiehlt es sich, den Button bis zum Eintreffen der Response zu deaktivieren. Was aber, wenn der Server ausfällt oder es aus irgendwelchen Gründen nicht schafft, den Request zu beantworten? Dann friert der Browser zwar nicht ein, aber Ihre Anwendung ist jetzt mit einem deaktivierten Button eingefroren. Um diese Art Problem zu verhindern, kann es nützlich sein, Ihre eigenen Timeouts mit der Window.setTimeout( )-Funktion festzulegen, wenn Sie HTTP-Requests starten. Normalerweise bekommen Sie Ihre Response, bevor Ihr Timeout-Handler ausgelöst wird; in diesem Fall verwenden Sie einfach die Window.clearTimeout( )-Funktion, um den Timeout abzubrechen. Wenn Ihr Timeout aber ausgelöst wird, bevor der XMLHttpRequest readyState 4 erreicht hat, können Sie den Request mit der XMLHttpRequest.abort( )Methode abbrechen. Danach werden Sie üblicherweise den Benutzer davon unterrichten, dass der Request fehlgeschlagen ist (beispielsweise mit Window.alert( )). Wenn Sie, wie in unserem hypothetischen Beispiel, einen Button vor dem Absenden des Requests deaktiviert haben, werden Sie ihn jetzt vermutlich reaktivieren wollen, nachdem der Timeout eingetreten ist. Beispiel 20-7 definiert eine HTTP.get( )-Funktion, die diese Timeout-Technik vorführt. Dabei handelt es sich um eine fortgeschrittene Version der HTTP.getText( )-Methode aus Beispiel 20-2, die viele der in vorhergehenden Beispielen eingeführten Features integriert, einschließlich eines Error-Handlers, Request-Parametern und der bereits beschriebenen
540 | Kapitel 20: HTTP skripten
491-0.book Seite 541 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Beispiel 20-7: Die HTTP.get( )-Utility /** * Sende einen HTTP GET-Request für die angegebene URL. Wenn eine erfolgreiche * Response eintrifft, wird sie in ein Objekt nach Maßgabe des Content-Type-Headers * konvertiert und der angegebenen Callback-Funktion übergeben. * Zusätzliche Argumente können als Eigenschaften des options-Objekts angegeben werden. * * Wenn eine Response mit Fehler eintrifft (z.B., ein 404 Not Found), * werden Statuscode und -meldung an options.errorHandler übergeben. * Wenn kein Error-Handler angegeben ist, wird die Callback* Funktion mit einem null-Argument aufgerufen. * * Wenn das options.parameters-Objekt angegeben ist, werden seine Eigenschaften * als Namen und Werte von Request-Parametern verwendet. Sie werden * mit HTTP.encodeFormData( ) in einen URL-codierten String konvertiert und * nach einem '?' an die URL angehängt. * * Wenn eine options.progressHandler-Funktion angegeben ist, wird sie * jedes Mal aufgerufen, wenn die readyState-Eigenschaft auf einen Wert kleiner * gesetzt 4 wird. Jedem Aufruf der Progress-Handler-Funktion wird eine * Zahl übergeben, die angibt, wie oft die Funktion aufgerufen worden ist. * * Wenn ein options.timeout-Wert angegeben ist, wird der XMLHttpRequest * abgebrochen, wenn er nicht vor Ablauf der angegebenen Anzahl Millisekunden * fertig geworden ist. Wenn der Timeout abläuft und ein * options.timeoutHandler angegeben ist, wird diese Funktion mit der * angeforderten URL als Argument aufgerufen. /** HTTP.get = function(url, callback, options) { var request = HTTP.newRequest( ); var n = 0; var timer; if (options.timeout) timer = setTimeout(function( ) { request.abort( ); if (options.timeoutHandler) options.timeoutHandler(url); }, options.timeout); request.onreadystatechange = function( ) { if (request.readyState == 4) { if (timer) clearTimeout(timer);
20.2 XMLHttpRequest-Beispiele und Utilities |
541
clientseitiges JavaScript
HTTP._getResponse( )-Methode. Sie ermöglicht es der aufrufenden Funktion auch, eine optionale Callback-Funktion zur Fortschrittsüberwachung anzugeben, die immer dann aufgerufen wird, wenn der onreadystatechange-Handler mit einem readyState aufgerufen wird, der nicht 4 ist. In Browsern wie Firefox, die diesen Handler mehrfach in Status 3 aufrufen, ermöglicht ein solcher Callback einem Skript die Anzeige von Download-Feedback für den Benutzer.
491-0.book Seite 542 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 20-7: Die HTTP.get( )-Utility (Fortsetzung) if (request.status == 200) { callback(HTTP._getResponse(request)); } else { if (options.errorHandler) options.errorHandler(request.status, request.statusText); else callback(null); } } else if (options.progressHandler) { options.progressHandler(++n); } } var target = url; if (options.parameters) target += "?" + HTTP.encodeFormData(options.parameters) request.open("GET", target); request.send(null); };
20.3 Ajax und dynamisches Skripten Der Begriff Ajax beschreibt eine Architektur für Webanwendungen, in denen skriptkontrolliertes HTTP und das XMLHttpRequest-Objekt eine prominente Rolle spielen. (Für viele sind das XMLHttpRequest-Objekt und Ajax sogar mehr oder minder dasselbe.) Ajax ist ein (meist nicht komplett großgeschriebenes) Akronym für Asynchronous JavaScript and XML.5 Der Begriff wurde von Jesse James Garrett geprägt und erschien zum ersten Mal in seinem Essay »Ajax: A New Approach to Web Applications« im Februar 2005. Sie können dieses richtungsweisende Essay unter http://www.adaptivepath.com/publications/ essays/archives/000385.php finden (auf Englisch). Das XMLHttpRequest-Objekt, auf dem Ajax beruht, gab es in Webbrowsern von Microsoft und Netscape/Mozilla bereits ungefähr vier Jahre lang, bevor Garretts Essay veröffentlicht wurde, es hatte aber nie viel Aufmerksamkeit bekommen.6 In 2004 änderte sich 5 Die Ajax-Architektur ist überzeugend, und die Vergabe eines einfachen Namens für sie hat mitgeholfen, eine Revolution im Design von Webanwendungen auszulösen. Wie sich zeigt, klärt das Akronym aber nicht besonders gut über die an Ajax-Anwendungen beteiligten Technologien auf. Clientseitiges JavaScript verwendet überall Event-Handler und ist daher asynchron. Außerdem ist die Benutzung von XML in Ajax-Anwendungen oft zwar bequem, aber immer optional. Das definierende Merkmal von Ajax-Anwendungen ist die Tatsache, dass sie skriptgesteuertes HTTP betreiben, aber diese Charakteristik taucht in der Abkürzung gar nicht auf. 6 Ich bedaure es, XMLHttpRequest nicht in der vierten Auflage dieses Buchs dokumentiert zu haben. Diese Auflage war sehr auf Standards bezogen und XMLHttpRequest wurde ausgelassen, weil das Objekt nie von einer standardisierenden Organisation unterstützt wurde. Hätte ich die Fähigkeiten von skriptgesteuertem HTTP zu dieser Zeit erkannt, hätte ich meine eigenen Regeln gebrochen und es trotzdem mit aufgenommen.
542 | Kapitel 20: HTTP skripten
491-0.book Seite 543 Mittwoch, 4. April 2007 9:55 09
e-bol.net das, als Google seine Webmail-Anwendung Gmail vorstellte, die XMLHttpRequest verwendet. Die Kombination dieses weithin sichtbaren und professionell ausgeführten Beispiels zusammen mit Garretts Essay von Anfang 2005 ließ das Interesse an Ajax rasant wachsen.
Ein optionales Feature von Ajax-Anwendungen ist die Verwendung von XML zur Codierung des Datenaustausches zwischen Client und Server. Kapitel 21 zeigt, wie man clientseitiges JavaScript dazu verwenden kann, XML-Daten zu manipulieren, einschließlich der Ausführung von XPath-Abfragen und XSL-Transformationen von XML nach HTML. Einige Ajax-Anwendungen verwenden XSLT, um den Inhalt (XML-Daten) von der Darstellung (HTML-Formatierung, durch ein XSL-Stylesheet ausgedrückt) zu trennen. Diese Vorgehensweise hat die zusätzlichen Vorteile, dass die zwischen Server und Client zu transferierende Datenmenge reduziert wird und die Transformation vom Server auf den Client verlegt wird. Man kann Ajax in einen RPC-Mechanismus formalisieren.7 In dieser Formel verwenden Webentwickler Ajax-Bibliotheken im Hintergrund sowohl auf Client- als auch Serverseite, um Kommunikation zwischen Client und Server auf höherer Ebene zu ermöglichen. Dieses Kapitel beschreibt keine solchen RPC-over-Ajax-Bibliotheken und konzentriert sich stattdessen auf die darunterliegende Technologie, die Ajax funktionsfähig macht. Ajax ist eine junge Anwendungsarchitektur, und Garretts Essay, das sie beschreibt, endet mit einem Aufruf zur Tat, den es sich hier wiederzugeben lohnt: Die größten Herausforderungen in der Erstellung von Ajax-Anwendungen sind nicht technischer Natur. Die Kerntechnologien für Ajax sind ausgereift, stabil und werden gut verstanden. Die Herausforderungen richten sich stattdessen an die Designer dieser Anwendungen: Vergessen wir, was wir glauben, über die Beschränkungen des Webs zu wissen, und stellen wir uns eine breitere und reichere Palette an Möglichkeiten vor. Das wird noch spaßig.
7 RPC steht für Remote Procedure Call und beschreibt eine Strategie, die im Distributed Computing zur Vereinfachung der Client/Server-Kommunikation angewandt wird.
20.3 Ajax und dynamisches Skripten |
543
clientseitiges JavaScript
Das zentrale Feature einer Ajax-Anwendung ist, dass sie skriptgesteuertes HTTP verwendet, um mit einem Webserver ohne Neuladen von Seiten zu kommunizieren. Da die ausgetauschte Datenmenge oft gering ist und weil der Browser kein Dokument (und die damit verbundenen Stylesheets und Skripten) parsen und darstellen muss, ist die Ansprechzeit erheblich kürzer. Das Ergebnis sind Webanwendungen, die sich mehr wie traditionelle Desktopanwendungen verhalten.
491-0.book Seite 544 Mittwoch, 4. April 2007 9:55 09
e-bol.net
20.3.1 Ajax-Beispiel Die XMLHttpRequest-Beispiele, die wir bisher in diesem Kapitel gesehen haben, waren Utility-Funktionen, die demonstrieren, wie man das XMLHttpRequest-Objekt verwendet. Sie haben nicht gezeigt, warum Sie das Objekt vielleicht verwenden möchten, oder erläutert, was Sie mit ihm erreichen können. Wie das Zitat vom Garrett zeigt, eröffnet die Ajax-Architektur viele Möglichkeiten – und wir stehen erst am Anfang, sie zu ergründen. Das nächste Beispiel ist ein einfaches, aber es fängt etwas vom Geschmack und der Bequemlichkeit der Ajax-Architektur ein. Beispiel 20-8 ist ein unauffälliges Skript, das Event-Handler auf Links im Dokument registriert, sodass sie Tooltips anzeigen, wenn der Benutzer mit der Maus über sie fährt. Für Links, die zum selben Server zurückführen, von dem das Dokument geladen wurde, verwendet das Skript XMLHttpRequest, um einen HTTP HEAD-Request zu starten. Aus den zurückgegebenen Headern extrahiert es den Content-Type, die Größe und den Änderungszeitpunkt des gelinkten Dokuments und zeigt diese Informationen im Tooltip an (siehe Abbildung 20-1). Der Tooltip stellt daher eine Art Vorschau auf das Linkziel dar und kann einem Benutzer helfen zu entscheiden, ob er klicken soll oder nicht.
Abbildung 20-1: Ein Ajax-Tooltip
Der Code stützt sich auf die Tooltip-Klasse, die in Beispiel 16-4 entwickelt wurde, braucht aber die Erweiterung dieser Klasse aus Beispiel 17-3 nicht. Zusätzlich benutzt er das Geometry-Modul aus Beispiel 14-2 und die Utility-Funktion HTTP.getHeaders( ), die wir in Beispiel 20-4 entwickelt haben. Der Code enthält mehrere Ebenen an Asynchronität, und zwar in der Form eines onload-Event-Handlers, eines onmouseover-Event-Handlers, eines Timers und einer Callback-Funktion für das XMLHttpRequest-Objekt. Dadurch entstehen tief verschachtelte Funktionen.
544 | Kapitel 20: HTTP skripten
491-0.book Seite 545 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 20-8: Ajax-Tooltips
// Beim Laden des Dokuments die init( )-Funktion aufrufen lassen if (window.addEventListener) window.addEventListener("load", init, false); else if (window.attachEvent) window.attachEvent("onload", init); // Nach dem Laden des Dokuments aufzurufen function init( ) { var links = document.getElementsByTagName('a'); // Durchlaufe alle Links, und füge ihnen Event-Handler hinzu for(var i = 0; i < links.length; i++) if (links[i].href) addTooltipToLink(links[i]); } // Diese Funktion fügt die Event-Handler hinzu function addTooltipToLink(link) { // Event-Handler hinzufügen if (link.addEventListener) { // standardisiertes Verfahren link.addEventListener("mouseover", mouseover, false); link.addEventListener("mouseout", mouseout, false); } else if (link.attachEvent) { // IE-spezifisches Verfahren link.attachEvent("onmouseover", mouseover); link.attachEvent("onmouseout", mouseout); } var timer; // Wird mit setTimeout/clearTimeout verwendet function mouseover(event) { var e = event || window.event; // Mausposition holen, zu Dokumentkoordinaten konvertieren, Offset addieren var x = e.clientX + Geometry.getHorizontalScroll( ) + 25; var y = e.clientY + Geometry.getVerticalScroll( ) + 15; // Falls ein Tooltip ansteht, abbrechen if (timer) window.clearTimeout(timer);
20.3 Ajax und dynamisches Skripten |
545
clientseitiges JavaScript
/** * linkdetails.js * * Dieses unauffällige JavaScript-Modul gibt Links in einem Dokument Event-Handler, * sodass sie Tooltips anzeigen, wenn die Maus länger als eine halbe Sekunde lang * über ihnen verweilt. Wenn der Link auf ein Dokument auf dem gleichen Server zeigt, auf dem * auch das Quelldokument liegt, enthält der Tooltip Informationen über den Typ, die Größe * und das Datum des Dokuments, die über einen XMLHttpRequest-HEAD-Request beschafft werden. * * Dieses Modul braucht die Module Tooltip.js, HTTP.js und Geometry.js */ (function( ) { // Anonyme Funktion, die alle unsere Symbole speichert // Erzeuge das von uns zu verwendende Tooltip-Objekt var tooltip = new Tooltip( );
491-0.book Seite 546 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 20-8: Ajax-Tooltips (Fortsetzung) // Einen Tooltip in einer halben Sekunde einplanen timer = window.setTimeout(showTooltip, 500); function showTooltip( ) { // Wenn es ein HTTP-Link ist und er vom gleichen Host kommt // wie dieses Skript, können wir XMLHttpRequest verwenden, // um mehr über ihn zu erfahren. if (link.protocol == "http:" && link.host == location.host) { // Starte einen XMLHttpRequest für die Link-Header HTTP.getHeaders(link.href, function(headers) { // Mit den Headern bauen wir einen Textstring var tip = "URL: " + link.href + "" + "Typ: " + headers["Content-Type"] + "" + "Größe: " + headers["Content-Length"] + "" + "Date: " + headers["Last-Modified"]; // und zeigen ihn als Tooltip an tooltip.show(tip, x, y); }); } else { // Wenn es sich um einen Link auf eine andere Site handelt, // ist der Tooltip einfach die URL des Links tooltip.show("URL: " + link.href, x, y); } } } function mouseout(e) { // Wenn die Maus den Link verlässt, werden alle // anstehenden Tooltips gelöscht oder versteckt, falls sie angezeigt werden if (timer) window.clearTimeout(timer); timer = null; tooltip.hide( ); } } })( );
20.3.2 Einseiten-Anwendungen Eine Einseiten-Anwendung ist genau das, was der Name schon sagt: eine über JavaScript erstellte Webanwendung, für die nur eine Seite geladen werden muss. Manche EinseitenAnwendungen brauchen nach dem Laden nie mehr mit dem Server zu reden. Ein Beispiel dafür sind DHTML-Spiele, bei denen die Kommunikation mit dem Benutzer einfach zu skriptgesteuerten Änderungen am geladenen Dokument führt. Das XMLHttpRequest-Objekt und die Ajax-Architektur eröffnen jedoch viele Möglichkeiten. Webanwendungen können diese Verfahren benutzen, um Daten mit dem Server auszutauschen, und trotzdem Einseiten-Anwendungen sein. Solche Webanwendungen
546 | Kapitel 20: HTTP skripten
491-0.book Seite 547 Mittwoch, 4. April 2007 9:55 09
e-bol.net
20.3.3 Remote Scripting Der Begriff Remote Scripting entstand vier Jahre vor dem Begriff Ajax und ist einfach ein nicht so modischer Name für die gleiche Grundidee: die Verwendung von skriptgesteuertem HTTP für eine engere Integration (und verbesserte Ansprechzeit) zwischen Client und Server. Ein weithin bekannter Artikel von Apple aus dem Jahr 2002 beschreibt beispielsweise, wie man ein -Tag verwendet, um skriptgesteuerte HTTP-Requests an einen Webserver zu senden (siehe http://developer.apple.com/internet/webcontent/iframe.html). Im Artikel wird auf Folgendes hingewiesen: Wenn der Webserver eine HTML-Datei zurücksendet, die -Tags enthält, wird der in diesen Tags enthaltene JavaScript-Code vom Browser ausgeführt und kann Methoden aufrufen, die in dem Fenster definiert sind, das das enthält. Auf diese Weise kann der Server direkte Befehle in Form von JavaScript-Statements an seinen Client senden.
20.3.4 Vorsicht bei Ajax Wie jede Architektur hat Ajax seine Fallen. In diesem Abschnitt werden drei Situationen bei der Erstellung von Ajax-Anwendungen beschrieben, in denen Sie aufpassen müssen. Die erste Falle ist die des sichtbaren Feedbacks. Wenn ein Benutzer auf einen herkömmlichen Hyperlink klickt, gibt der Webbrowser Feedback und zeigt damit an, dass der Inhalt des Links gerade geholt wird. Das Feedback erscheint, bevor der Inhalt fertig zur Anzeige ist, wodurch der Benutzer sieht, dass der Browser sich mit der Anfrage beschäftigt. Wenn ein HTTP-Request aber über XMLHttpRequest gesendet wird, gibt der Browser kein Feedback. Selbst bei Breitbandverbindungen verursachen Netzwerklaufzeiten oft merkbare Verzögerungen zwischen dem Senden eines HTTP-Requests und dem Erhalt einer Antwort. Deshalb ist es für Ajax-basierte Anwendungen nützlich, wenn während des Wartens auf eine Anwort auf den XMLHttpRequest optisches Feedback vorhanden ist (wie z.B. eine einfache DHTML-Animation: siehe Kapitel 16). Beachten Sie, dass Beispiel 20-8 diesem Rat hinsichtlich optischem Feedback nicht folgt. Das liegt daran, dass der Benutzer in diesem Beispiel den HTTP-Request nicht aus eigenem Antrieb auslöst. Stattdessen wird die Anfrage initiiert, wenn der Benutzer die Maus (passiv) über einen Link hält. Der Benutzer verlangt nichts ausdrücklich von der Anwendung und erwartet folglich kein Feedback.
20.3 Ajax und dynamisches Skripten |
547
clientseitiges JavaScript
können einen kurzen JavaScript-Bootstrapping-Code und einen einfachen HTMLSplash-Screen enthalten, der angezeigt wird, während die Anwendung hochgefahren wird. Während der Splash-Screen gezeigt wird, kann der Bootstrap-Code beispielsweise ein XMLHttpRequest-Objekt verwenden, um den eigentlichen JavaScript-Code für die Anwendung herunterzuladen, der dann mit der Methode eval( ) ausgeführt wird. Dann übernimmt der JavaScript-Code, lädt Daten mit XMLHttpRequest, wenn sie benötigt werden, und verwendet DOM, um diese Daten als DHTML für den Benutzer anzuzeigen.
491-0.book Seite 548 Mittwoch, 4. April 2007 9:55 09
e-bol.net Die zweite Falle hat mit den URLs zu tun. Herkömmlich gehen Webanwendungen von einem in den nächsten Zustand über, indem neue Seiten geladen werden, wobei jede Seite eine eindeutige URL hat. Bei Ajax-Anwendungen ist das anders: Wenn eine AjaxAnwendung skriptgesteuertes HTTP verwendet, um neuen Inhalt herunterzuladen und anzuzeigen, ändert sich die URL in der Navigationsleiste nicht. Wenn Benutzer versuchen, ein Lesezeichen für einen bestimmten Zustand zu setzen, werden sie feststellen, dass das über die Lesezeichenoption des Browsers nicht geht. Sie können nicht einmal eine URL aus der Navigationsleiste des Browsers ausschneiden, um sie anderswo einzufügen. Dieses Problem und seine Lösung werden von Google Maps (http://local.google.com) ausgezeichnet vorgeführt. Beim Zoomen und Scrollen der Karte werden sehr viele Daten zwischen Client und Server hin- und hergeschoben, aber die im Browser angezeigte URL ändert sich überhaupt nicht. Google löst das Problem der Lesezeichen, indem es einen »link to this page«-Link in jede Seite einfügt. Beim Anklicken dieses Links wird eine URL für die momentan angezeigte Karte erzeugt und die Karte mit Hilfe dieser URL neu geladen. Nach diesem erneuten Laden kann der momentane Status der Karte als Lesezeichen gespeichert oder der Link per E-Mail an Freunde gesendet werden usw. Was lernen AjaxAnwendungsentwickler daraus? Dass es weiterhin wichtig ist, den Anwendungsstatus in eine URL einzubauen und dem Benutzer die Möglichkeit zu geben, diese URLs zu nutzen. Eine dritte Falle, die bei Diskussionen über Ajax oft auftaucht, hängt mit der Schaltfläche Zurück zusammen. Da dem Browser die Kontrolle über HTTP genommen wird, übergehen Skripte, die XMLHttpRequest verwenden, den History-Mechanismus des Browsers. Benutzer sind daran gewöhnt, sich mit den Schaltflächen Zurück und Vorwärts durchs Netz zu bewegen. Wenn eine Ajax-Anwendung skriptgesteuertes HTTP verwendet, um umfassende neue Inhalte anzuzeigen, versuchen Benutzer eventuell, sich innerhalb der Anwendung mit diesen Schaltflächen zu bewegen. Dabei stellen sie frustriert fest, dass die Schaltfläche Zurück sie nicht auf die gerade vorher angezeigte Seite führt, sondern ganz nach vorne auf die vor der Anwendung angezeigte Seite. Es gab Versuche, das Problem mit Zurück dadurch zu lösen, dass der Browser dazu gebracht wird, URLs in seine History einzufügen. Diese Vorgehensweisen bleiben allerdings meistens in browserabhängigem Code stecken und sind nicht wirklich zufriedenstellend. Und selbst wenn sie irgendwann funktionieren, untergraben sie das AjaxDenkmuster und ermutigen Benutzer, über das erneute Laden von Seiten anstatt über skriptgesteuertes HTTP zu navigieren. Meiner Ansicht nach ist das Zurück-Problem nicht so schwerwiegend, wie das oft dargestellt wird, und kann mit gut durchdachtem Webdesign weitgehend umgangen werden. Anwendungselemente, die wie Hyperlinks aussehen, sollten sich auch so verhalten und Seiten tatsächlich neu laden. Dadurch werden sie in die Browser-History aufgenommen, wie es vom Benutzer erwartet wird. Umgekehrt sollten Anwendungselemente, die skript-
548 | Kapitel 20: HTTP skripten
491-0.book Seite 549 Mittwoch, 4. April 2007 9:55 09
e-bol.net
In Ajax-Anwendungen sollten Sie darauf achten, Wörter wie »Vorwärts« und »Zurück« in den anwendungsinternen Navigationselementen zu vermeiden. Wenn eine Anwendung eine Schnittstelle im Wizard-Stil z.B. mit den Schaltflächen Weiter und Zurück verwendet, sollte sie zur Anzeige der nächsten oder vorherigen Bildschirmflächen tatsächlich Seiten traditionell laden (anstatt XMLHttpRequest zu verwenden). In dieser Situation erwartet der Benutzer, dass die Schaltfläche Zurück des Browsers genauso funktioniert wie die Schaltfläche Zurück der Anwendung. Allgemeiner gesagt, sollte das Zurück des Browsers nicht mit dem Rückgängig-Feature der Anwendung verwechselt werden. Ajax-Anwendungen können ihre eigenen Undo/redo-Optionen implementieren, wenn das für die Benutzer nützlich ist. Allerdings sollte klar sein, dass sie sich von den Schaltflächen Zurück und Nächste unterscheiden.
20.4 Skriptgesteuertes HTTP mit -Tags In Internet Explorer 5 und 6 ist das XMLHttpRequest-Objekt ein ActiveX-Objekt. Manchmal deaktivieren Benutzer aus Sicherheitsgründen alle ActiveX-Skripten in Internet Explorer, wodurch Skripten kein XMLHttpRequest-Objekt erzeugen können. Falls notwendig, können einfache HTTP GET-Requests mit den Tags und ausgeführt werden. Dadurch können zwar nicht alle Funktionalitäten von XMLHttpRequest neu implementiert werden,8 aber Sie können zumindest eine Version der HTTP.getText( )-Utility-Funktion erzeugen, die ohne ein ActiveX-Skript funktioniert. Ein HTTP-Request kann recht einfach über das Setzen der Eigenschaft src eines - oder -Tags erzeugt werden. Die gewünschten Daten aus diesen Elementen zu extrahieren, ohne dass die Daten dabei vom Browser geändert werden, ist aufwändiger. Ein -Tag erwartet, dass es in ein HTML-Dokument geladen wird. Wenn Sie versuchen, den Inhalt einer Klartextdatei in ein iframe herunterzuladen, stellen Sie fest, dass Ihr Text in HTML konvertiert wird. Außerdem implementieren manche Internet Explorer-Versionen den onload- oder onreadystatechange-Handler für das -Tag nicht richtig, was die Sache weiter kompliziert. Der hier gewählte Weg verwendet ein -Tag und ein Skript auf der Serverseite. Sie teilen dem Skript auf der Serverseite die URL mit, deren Inhalt Sie aufrufen wollen, und an welche Funktion auf der Clientseite der Inhalt übergeben werden soll. Das Skript auf der 8 Um XMLHttpRequest komplett zu ersetzen, brauchen Sie wahrscheinlich ein Java-Applet.
20.4 Skriptgesteuertes HTTP mit -Tags |
549
clientseitiges JavaScript
gesteuertes HTTP ausführen und nicht in die Browser-History aufgenommen werden, nicht wie Hyperlinks aussehen. Schauen wir uns noch einmal die Kartenanwendung von Google an. Wenn der Benutzer zum Scrollen einer Karte mit der Maus klickt und sie zieht, erwartet er nicht, dass die Zurück-Schaltfläche sein Scrollen zunichte macht. Schließlich macht die Zurück-Schaltfläche das Scrollen in einer Webseite über die Bildlaufleiste des Browsers auch nicht zunichte.
491-0.book Seite 550 Mittwoch, 4. April 2007 9:55 09
e-bol.net Serverseite holt den Inhalt der gewünschten URL, codiert ihn als (möglicherweise sehr langen) JavaScript-String und gibt ein Skript auf der Clientseite zurück, das diesen String an die von Ihnen angegebene Funktion übergibt. Da dieses Skript auf der Clientseite in ein -Tag geladen wird, wird der URL-Inhalt automatisch als JavaScript interpretiert, wenn der Download abgeschlossen ist, und die Funktion dadurch aufgerufen. Beispiel 20-9 implementiert ein passendes serverseitiges Skript in der Skriptsprache PHP. Beispiel 20-9: jsquoter.php [email protected][email protected][email protected]
560 | Kapitel 21: JavaScript und XML
491-0.book Seite 561 Mittwoch, 4. April 2007 9:55 09
e-bol.net Das unten aufgeführte HTML-Fragment zeigt, wie die makeTable( )-Funktion mit diesen XML-Daten verwendet werden kann. Beachen Sie, dass sich das Schema-Objekt auf Tagund Attributnamen aus dieser Beispiel-Datendatei bezieht:
var xmldoc = XML.load("adressen.xml"); makeTable(xmldoc, schema, "adressen");
clientseitiges JavaScript
// Diese Funktion verwendet makeTable( ) function displayAddressBook( ) { var schema = { rowtag: "Kontakt", columns: [ { tagname: "@name", label: "Name" }, { tagname: "email", label: "Adresse" } ] }; // Lies die XML-Daten // Konvertiere in eine HTML-Tabelle
} Adressbuch anzeigen
Die Implementierung von makeTable( ) zeigt Beispiel 21-7. Beispiel 21-7: Eine HTML-Tabelle aus XML-Daten erstellen /** * Extrahiere Daten aus dem angegebenen XML-Dokument, und formatiere sie als HTML-Tabelle. * Füge die Tabelle an das angegebene HTML-Element an. (Wenn das Element ein String ist, * wird es als Element-ID genommen und das angegebene Element wird herausgesucht.) * * Das schema-Argument ist ein JavaScript-Objekt und gibt an, welche Daten * extrahiert und wie sie angezeigt werden sollen. Das schema-Objekt muss eine Eigenschaft * mit dem Namen "rowtag" haben, die den Tagnamen des XML-Elements angibt, das * die Daten für eine Tabellenreihe enthält. Das schema-Objekt muss außerdem eine Eigenschaft * mit dem Namen "columns" haben, die auf ein Array verweist. Die Elemente dieses Arrays * geben die Reihenfolge und den Inhalt der Tabellenspalten an. Jedes * Array-Element kann ein String oder ein JavaScript-Objekt sein. Ist ein Element ein * String, so wird dieser String als Tag-Name des XML-Elements verwendet, das die * Tabellendaten und Überschrift für die Spalte enthält. * Wenn ein Element des columns[]-Arrays ein Objekt ist, muss es eine Eigenschaft * mit dem Namen "tagname" und eine mit dem Namen "label" haben. Die tagname-Eigenschaft * wird verwendet, um Daten aus dem XML-Dokument zu extrahieren, und die label-Eigenschaft * wird als Text für die Spaltenüberschrift verwendet. Beginnt der Tagname mit einem * @-Zeichen, so ist er kein Nachfahre der Reihe, sondern ein Attribut des Reihenelements. */ function makeTable(xmldoc, schema, element) { // Erzeuge das
-Element var table = document.createElement("table");
21.2 XML über die DOM API manipulieren |
561
491-0.book Seite 562 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 21-7: Eine HTML-Tabelle aus XML-Daten erstellen (Fortsetzung) // Erzeuge den Kopf für die Reihen der
-Elemente in einem
eines var thead = document.createElement("thead"); var header = document.createElement("tr"); for(var i = 0; i < schema.columns.length; i++) { var c = schema.columns[i]; var label = (typeof c == "string")?c:c.label; var cell = document.createElement("th"); cell.appendChild(document.createTextNode(label)); header.appendChild(cell); } // Füge den Kopf in die Tabelle ein thead.appendChild(header); table.appendChild(thead); // Die restlichen Reihen der Tabelle gehen in einen var tbody = document.createElement("tbody"); table.appendChild(tbody); // Hole jetzt die Elemente, die unsere Daten enthalten, aus dem XML-Dokument var xmlrows = xmldoc.getElementsByTagName(schema.rowtag); // Durchlaufe diese Elemente. Bei jedem Durchgang holen wir eine Tabellenreihe. for(var r=0; r < xmlrows.length; r++) { // Das ist das XML-Element, in dem sich die Daten für die Reihe befinden var xmlrow = xmlrows[r]; // Erzeuge ein HTML-Element, um die Daten in der Reihe anzuzeigen var row = document.createElement("tr"); // Durchlaufe die Spalten, die vom schema-Objekt angegeben werden for(var c = 0; c < schema.columns.length; c++) { var sc = schema.columns[c]; var tagname = (typeof sc == "string")?sc:sc.tagname; var celltext; if (tagname.charAt(0) == '@') { // Beginnt der Tagname mit '@', so ist es ein Attributname celltext = xmlrow.getAttribute(tagname.substring(1)); } else { // Suche das XML-Element, das die Daten für diese Spalte enthält var xmlcell = xmlrow.getElementsByTagName(tagname)[0]; // Gehe davon aus, dass das Element als ersten Nachfahren einen Textknoten // enthält var celltext = xmlcell.firstChild.data; } // Erzeuge das HTML-Element für diese Zelle var cell = document.createElement("td"); // Füge den Datentext in die HTML-Zelle ein cell.appendChild(document.createTextNode(celltext)); // Füge die Zelle an die Zeile an row.appendChild(cell); }
562 | Kapitel 21: JavaScript und XML
491-0.book Seite 563 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 21-7: Eine HTML-Tabelle aus XML-Daten erstellen (Fortsetzung) // Füge die Zeile dem tbody der Tabelle hinzu tbody.appendChild(row); }
// Jetzt haben wir die HTML-Tabelle erzeugt und fügen sie dem angegebenen Element hinzu. // Wenn das Element ein String ist, gehen wir von einer Element-ID aus. if (typeof element == "string") element = document.getElementById(element); element.appendChild(table); }
21.3 XML mit XSLT transformieren Nachdem Sie ein Document-Objekt, das ein XML-Dokument repräsentiert, geladen, geparst oder sonstwie erhalten haben, ist seine Transformation mit Hilfe eines XSLTStylesheets eines der eindrucksvollsten Dinge, die Sie mit ihm machen können. XSLT steht für XSL-Transformationen und XSL für Extensible Stylesheet Language. XSL-Stylesheets sind XML-Dokumente, die genau wie andere XML-Dokumente geladen und geparst werden können. Eine Anleitung zu XSL übersteigt den Umfang dieses Buchs bei Weitem, aber Beispiel 21-8 zeigt ein Beispiel-Stylesheet, das ein XML-Dokument, wie es in Beispiel 21-6 gezeigt ist, in eine HTML-Tabelle transformiert. Beispiel 21-8: Ein einfaches XSL-Stylesheet
Name
E-Mail-Adresse
21.3 XML mit XSLT transformieren |
563
clientseitiges JavaScript
// Setze ein HTML-Attribut am Tabellenelement durch Setzen einer Eigenschaft. // Beachten Sie, dass wir in XML stattdessen setAttribute( ) verwenden müssen. table.frame = "border";
491-0.book Seite 564 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 21-8: Ein einfaches XSL-Stylesheet (Fortsetzung)
XSLT transformiert den Inhalt eines XML-Dokuments anhand der Regeln in einem XSLStylesheet. Bei clientseitigem JavaScript wird das normalerweise gemacht, um das XMLDokument in HTML zu transformieren. Zwar verwenden viele Webanwendungsarchitekturen XSLT auf der Serverseite, aber Mozilla-basierte Browser und IE unterstützen XSLT auch auf der Clientseite. Das Verschieben der Transformation vom Server zum Client kann Serverressourcen und Netzwerkbandbreite einsparen (weil XML-Daten normalerweise kompakter sind als die HTML-Darstellung dieser Daten). Viele moderne Browser können XML sowohl durch CSS- als auch durch XSL-Stylesheets mit Stilen versehen. Wenn Sie ein Stylesheet in einer Verarbeitungsanweisung xmlstylesheet angeben, können Sie ein XML-Dokument direkt in den Browser laden, und der Browser übernimmt die Style-Transformation des Dokuments und zeigt es an. Die benötigte Verarbeitungsanweisung kann z.B. so aussehen:
Beachten Sie, dass der Browser diese Art der XSLT-Transformation automatisch durchführt, wenn ein XML-Dokument mit einer entsprechenden Verarbeitungsanweisung in das Anzeigefenster des Browsers geladen wird. Das ist wichtig und hilfreich, aber nicht das Thema dieses Abschnitts. Hier erkläre ich vielmehr, wie Sie mit JavaScript XSLTransformationen dynamisch durchführen. Das W3C definiert keine standardisierte API zur Durchführung von XSL-Transformationen an DOM-Document- und -Element-Objekten. In Mozilla-basierten Browsern stellt das XSLTProcessor-Objekt eine JavaScript-XSLT-API zur Verfügung. Unter IE haben XML-Document- und -Element-Objekte eine transformNode( )-Methode zum Ausführen von Transformationen. Beispiel 21-9 zeigt beide APIs. Es definiert eine XML.Transformer-Klasse, die ein XSL-Stylesheet kapselt und dessen Verwendung zur Transformation mehrerer XML-Dokumente gestattet. Die transform( )-Methode eines XML.Transformer-Objekts verwendet das gekapselte Stylesheet zur Transformation eines angegebenen XML-Dokuments und ersetzt den Inhalt eines angegebenen DOM-Elements durch die Transformationsergebnisse.
564 | Kapitel 21: JavaScript und XML
491-0.book Seite 565 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 21-9: XSLT unter Mozilla und Internet Explorer
clientseitiges JavaScript
/** * Diese XML.Transformer-Klasse kapselt ein XSL-Stylesheet ein. * Wenn der Stylesheet-Parameter eine URL ist, laden wir sie. * Ansonsten gehen wir davon aus, dass es ein passendes DOM-Dokument ist. */ XML.Transformer = function(stylesheet) { // Lade das Stylesheet, wenn nötig. if (typeof stylesheet == "string") stylesheet = XML.load(stylesheet); this.stylesheet = stylesheet; // In Mozilla-basierten Browsern: Erzeuge ein XSLTProcessor-Objekt, und // informiere es über das Stylesheet. if (typeof XSLTProcessor != "undefined") { this.processor = new XSLTProcessor( ); this.processor.importStylesheet(this.stylesheet); } }; /** * Das ist die transform( )-Methode der XML.Transformer-Klasse. * Sie transformiert den angegebenen XML-Knoten mit Hilfe des gekapselten Stylesheets. * Es wird davon ausgegangen, dass die Transformation HTML ergibt. Es * ersetzt den Inhalt des angegebenen Elements. */ XML.Transformer.prototype.transform = function(node, element) { // Wenn element über id angegeben ist, suche es. if (typeof element == "string") element = document.getElementById(element); if (this.processor) { // Haben wir einen XSLTProcessor erzeugt (d.h. wir sind in Mozilla), wenden wir // ihn an. // Transformiere den Knoten in ein DOM-DocumentFragment. var fragment = this.processor.transformToFragment(node, document); // Lösche den momentanen Inhalt von element. element.innerHTML = ""; // Und füge die transformierten Knoten ein. element.appendChild(fragment); } else if ("transformNode" in node) { // Wenn der Knoten eine transformNode( )-Funktion hat (unter IE), verwende sie. // Beachten Sie, dass transformNode( ) einen String zurückgibt. element.innerHTML = node.transformNode(this.stylesheet); } else { // Ansonsten haben wir diesmal kein Glück. throw "XSLT wird unter diesem Browser nicht unterstützt"; } }; /** * Das ist eine XSLT-Utility-Funktion, die nützlich ist, wenn ein Stylesheet
21.3 XML mit XSLT transformieren |
565
491-0.book Seite 566 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 21-9: XSLT unter Mozilla und Internet Explorer (Fortsetzung) * nur einmal verwendet wird. */ XML.transform = function(xmldoc, stylesheet, element) { var transformer = new XML.Transformer(stylesheet); transformer.transform(xmldoc, element); }
Als dieses Buch geschrieben wurde, waren IE und Mozilla-basierte Browser die einzigen geläufigen Browser, die eine JavaScript-API für XSLT zur Verfügung stellten. Wenn die Unterstützung anderer Browser für Sie wichtig ist, interessiert Sie vielleicht AJAXSLT, eine Open Source JavaScript XSLT-Implementierung. AJAXSLT stammt von Google und wird unter http://goog-ajaxslt.sourceforge.net entwickelt.
21.4 XML mit XPath abfragen XPath ist eine einfache Sprache, die sich auf die Elemente, Attribute und Text in einem XML-Dokument bezieht. Ein XPath-Ausdruck kann auf ein XML-Element über seine Position in der Dokumenthierarchie verweisen oder ein Element aufgrund des Wertes (oder auch nur des Vorhandenseins) eines Attributs auswählen. Eine vollständige Behandlung von XPath übersteigt den Umfang dieses Kapitels, aber Abschnitt 21.4.1 gibt eine einfache Einführung in XPath, die häufige XPath-Ausdrücke durch Beispiele erklärt. Das W3C entwarf eine API zur Auswahl von Knoten in einem DOM-Dokumentenbaum über einen XPath-Ausdruck. Firefox und verwandte Browser implementieren diese W3C API mit Hilfe der evaluate( )-Methode des Document-Objekts (für HTML- und XML-Dokumente). Mozilla-basierte Browser implementieren auch noch Document. createExpression( ). Diese Methode kompiliert einen XPath-Ausdruck, damit er auch mehrmals effizient ausgewertet werden kann. Unter IE kann ein XPath-Ausdruck mit den Methoden selectSingleNode( ) und selectNodes( ) von XML- (aber nicht HTML-) Dokument- und -Element-Objekten evaluiert werden. Weiter unten in diesem Abschnitt ist Beispielcode aufgeführt, der sowohl die W3C als auch die IE API verwendet. Falls Sie XPath mit anderen Browsern verwenden wollen, eignet sich vielleicht das AJAXSLT-Projekt unter http://goog-ajaxslt.sourceforge.net.
21.4.1 XPath-Beispiele Wenn Sie die Baumstruktur eines DOM-Dokuments verstehen, sollte es kein Problem für Sie sein, einfache XPath-Ausdrücke mit Hilfe von Beispielen zu lernen. Um diese Beispiele zu verstehen, müssen Sie wissen, dass ein XPath-Ausdruck in Bezug zu einem Kontextknoten im Dokument ausgewertet wird. Die einfachsten XPath-Ausdrücke verweisen schlicht auf Nachfahren des Kontextknotens:
566 | Kapitel 21: JavaScript und XML
491-0.book Seite 567 Mittwoch, 4. April 2007 9:55 09
e-bol.net contact // Die Gruppe aller -Tags unterhalb des Kontextknotens contact[1] // Das erste -Tag unterhalb des Kontexts contact[last( )] // Das letzte -Kind des Kontextknotens contact[last( )-1] // Das vorletzte -Kind des Kontextknotens
Beachten Sie, dass die Indizes in der Syntax eines XPath-Arrays nicht mit 0 (wie bei Arrays im JavaScript-Stil) anfangen, sondern mit 1.
Alle -Kinder der -Kinder des Kontexts Das -Kind der Document Root (voranstehendes /) Die -Kinder des ersten -Kindes Das zweite -Kind aller -Kinder des Kontexts
Beachten Sie, dass contact/email[2] die Gruppe von -Elementen ausgibt, die jeweils das zweite -Kind aller -Kinder des Kontextknotens sind. Das unterscheidet sich von contact[2]/email und (contact/email)[2]. Ein Punkt (.) in einem XPath-Ausdruck verweist auf das context-Element. Ein doppelter Schrägstrich (//) ignoriert die Hierarchieebenen und verweist nicht auf ein direktes Kind, sondern auf einen beliebigen Nachfahren. Ein Beispiel: .//email //email
// Alle -Nachfahren des Kontexts // Alle -Tags im Dokument // (beachten Sie den am Anfang stehenden Schrägstrich)
XPath-Ausdrücke können sowohl auf XML-Attribute als auch auf Elemente verweisen. Das Zeichen @ wird als Präfix verwendet, um einen Attributnamen zu identifizieren: @id contact/@name
// Der Wert des id-Attributs des Kontextknotens // Die Werte der Namensattribute der -Kinder
Der Wert eines XML-Attributs kann die von einem XPath-Ausdruck zurückgegebene Gruppe von Elementen filtern. Ein Beispiel: contact[@personal="true"]
// Alle -Tags mit dem Attribut personal="true"
Um den Textinhalt von XML-Elementen auszuwählen, verwenden Sie die text( )Methode: contact/email/text( ) // Die Textknoten in -Tags //text( ) // Alle Textknoten im Dokument
XPath erkennt Namensräume, und Sie können Namensraumpräfixe in Ihre Ausdrücke aufnehmen: //xsl:template
// Wähle alle -Elemente aus
Wenn Sie einen XPath-Ausdruck evaluieren, der Namensräume verwendet, müssen Sie den Namensraum-URLs natürlich Namensraumpräfixe zuordnen.
21.4 XML mit XPath abfragen |
567
clientseitiges JavaScript
Der »path« im Namen XPath bezieht sich darauf, dass die Sprache Ebenen in der XMLElement-Hierarchie genau wie Verzeichnisse in einem Dateisystem behandelt und das Zeichen »/« verwendet, um Hierarchieebenen voneinander abzugrenzen. Also:
491-0.book Seite 568 Mittwoch, 4. April 2007 9:55 09
e-bol.net Diese Beispiele spiegeln lediglich die üblichen Gebrauchsmuster von XPath wider. XPath hat zusätzliche Syntax und Features, die hier nicht beschrieben werden. Ein Beispiel hierfür ist die Funktion count( ), die nicht die Knotenmenge selbst zurückgibt, sondern die Knotenanzahl in der Menge: count(//email)
// Die Anzahl der -Elemente im Dokument
21.4.2 XPath-Ausdrücke auswerten Beispiel 21-10 zeigt eine Klasse XML.XPathExpression, die unter IE und standardkonformen Browsern, wie z.B. Firefox, funktioniert. Beispiel 21-10: XPath-Ausdrücke auswerten /** * XML.XPathExpression ist eine Klasse, die eine XPath-Query und ihre * zugehörige Namensraumpräfix-zu-URL-Zuordnung kapselt. Wurde ein Objekt XML.XPathExpression * erzeugt, kann es einmal oder mehrfach ausgewertet werden (in einem * oder mehreren Kontexten), und zwar mit den Methoden getNode( ) oder getNodes( ). * * Das erste Argument dieses Konstruktors ist der Text des XPath-Ausdrucks. * * Enthält der Ausdruck beliebige XML-Namensräume, so muss das zweite Argument * ein JavaScript-Objekt sein, das Namensraumpräfixe den URLs zuordnet, die * diese Namensräume definieren. Die Eigenschaften dieses Objekts sind die Präfixe, und * die Werte dieser Eigenschaften sind die URLs. */ XML.XPathExpression = function(xpathText, namespaces) { this.xpathText = xpathText; // Speichere den Text des Ausdrucks this.namespaces = namespaces; // Und die Namensraumzuordnung if (document.createExpression) { // Wenn wir in einem W3C-konformen Browser sind, so verwende die W3C API, // um den Text der XPath-Query zu kompilieren this.xpathExpr = document.createExpression(xpathText, // Diese Funktion wird an das // Namensraumpräfix übergeben und gibt die URL zurück. function(prefix) { return namespaces[prefix]; }); } else { // Ansonsten nehmen wir fürs Erste an, dass wir unter IE arbeiten, und konvertieren // das namespaces-Objekt in das von IE geforderte Textformat. this.namespaceString = ""; if (namespaces != null) { for(var prefix in namespaces) { // Füge ein Leerzeichen ein, wenn hier bereits etwas steht if (this.namespaceString) this.namespaceString += ' ';
568 | Kapitel 21: JavaScript und XML
491-0.book Seite 569 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 21-10: XPath-Ausdrücke auswerten (Fortsetzung) // Und füge den Namensraum hinzu this.namespaceString += 'xmlns:' + prefix + '="' + namespaces[prefix] + '"'; } }
clientseitiges JavaScript
} }; /** * Das ist die getNodes( )-Methode von XML.XPathExpression. Sie wertet den * XPath-Ausdruck im angegebenen Kontext aus. Das Kontextargument sollte * ein Document- oder Element-Objekt sein. Der Rückgabewert ist ein Array * oder ein Array-ähnliches Objekt mit den Knoten, die zum Ausdruck passen. */ XML.XPathExpression.prototype.getNodes = function(context) { if (this.xpathExpr) { // Wenn wir in einem W3C-konformen Browser sind, dann haben wir // den Ausdruck im Konstruktor kompiliert. Jetzt werten wir diesen kompilierten // Ausdruck im angegebenen Kontext aus. var result = this.xpathExpr.evaluate(context, // Das ist der gewünschte Ergebnistyp XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); // Kopiere die erhaltenen Ergebnisse in ein Array. var a = new Array(result.snapshotLength); for(var i = 0; i < result.snapshotLength; i++) { a[i] = result.snapshotItem(i); } return a; } else { // Wenn wir nicht in einem W3C-konformen Browser sind, so versuche, den Ausdruck // mit der IE API auszuwerten. try { // Wir brauchen das Document-Objekt, um Namensräume anzugeben var doc = context.ownerDocument; // Wenn der Kontext kein ownerDocument hat, ist es das Dokument if (doc == null) doc = context; // Das ist IE-spezifische Zauberei, um die Präfix-zu-URL-Zuordnung anzugeben doc.setProperty("SelectionLanguage", "XPath"); doc.setProperty("SelectionNamespaces", this.namespaceString); // Unter IE muss der Kontext ein Element und kein Dokument sein; // wenn der Kontext ein Dokument ist, so verwende stattdessen documentElement if (context == doc) context = doc.documentElement; // Verwende jetzt die IE-Methode selectNodes( ), um den Ausdruck auszuwerten return context.selectNodes(this.xpathText); }
21.4 XML mit XPath abfragen |
569
491-0.book Seite 570 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 21-10: XPath-Ausdrücke auswerten (Fortsetzung) catch(e) { // Wenn die IE API nicht funktioniert, geben wir auf throw "XPath wird von diesem Browser nicht unterstützt"; } } }
/** * Das ist die getNode( )-Methode von XML.XPathExpression. Sie wertet den * XPath-Ausdruck im angegebenen Kontext aus und gibt genau einen passenden * Knoten aus (oder null, wenn kein Knoten passt). Wenn mehrere Knoten passen, * gibt diese Methode den ersten im Dokument aus. * Die Implementierung unterscheidet sich von getNodes( ) lediglich durch den Rückgabetyp. */ XML.XPathExpression.prototype.getNode = function(context) { if (this.xpathExpr) { var result = this.xpathExpr.evaluate(context, // Wir wollen nur den ersten passenden Knoten XPathResult.FIRST_ORDERED_NODE_TYPE, null); return result.singleNodeValue; } else { try { var doc = context.ownerDocument; if (doc == null) doc = context; doc.setProperty("SelectionLanguage", "XPath"); doc.setProperty("SelectionNamespaces", this.namespaceString); if (context == doc) context = doc.documentElement; // Unter IE rufe selectSingleNode statt selectNodes auf return context.selectSingleNode(this.xpathText); } catch(e) { throw "XPath wird unter diesem Browser nicht unterstützt"; } } }; // Eine Utility, die eine XML.XPathExpression erzeugt und an ihr getNodes( ) aufruft XML.getNodes = function(context, xpathExpr, namespaces) { return (new XML.XPathExpression(xpathExpr, namespaces)).getNodes(context); }; // Eine Utility, die eine XML.XPathExpression erzeugt und an ihr getNode( ) aufruft XML.getNode = function(context, xpathExpr, namespaces) { return (new XML.XPathExpression(xpathExpr, namespaces)).getNode(context); };
570 | Kapitel 21: JavaScript und XML
491-0.book Seite 571 Mittwoch, 4. April 2007 9:55 09
e-bol.net
21.4.3 Mehr zur W3C XPath API Aufgrund der Einschränkungen in der IE XPath API verarbeitet der Code in Beispiel 21-10 nur Anfragen, die nach einem Dokumentknoten oder einer Knotengruppe suchen. Unter IE ist es unmöglich, einen XPath-Ausdruck auszuwerten, der einen Textstring oder eine Zahl zurückgibt. Mit der W3C-Standard-API ist das mit Code möglich, der so aussieht: clientseitiges JavaScript
// Wie viele
-Tags sind im Dokument? var n = document.evaluate("count(//p)", document, null, XPathResult.NUMBER_TYPE, null).numberValue; // Was ist der Text im zweiten Absatz? var text = document.evaluate("//p[2]/text( )", document, null, XPathResult.STRING_TYPE, null).stringValue;
Bei diesen einfachen Beispielen müssen Sie auf zwei Dinge achten. Erstens verwenden sie die document.evaluate( )-Methode, um einen XPath-Ausdruck direkt auszuwerten, ohne ihn zuerst zu kompilieren. Im Gegensatz dazu verwendet der Code in Beispiel 21-10 die document.createExpression( )-Methode, um einen XPath-Ausdruck in ein wiederverwendbares Format zu kompilieren. Zweitens benutzen diese Beispiele HTML-
-Tags im document-Objekt. Unter Firefox können XPath-Abfragen für HTML- und XML-Dokumente verwendet werden. Unter Document, XPathExpression und XPathResult im Teil IV werden alle Einzelheiten der W3C XPath API beschrieben.
21.5 Serialisierung von XML Manchmal ist es sinnvoll, ein XML-Dokument (oder ein Unterelement des Dokuments) durch Konvertierung in einen String zu serialisieren – zum Beispiel, um ein XML-Dokument als Body eines HTTP POST-Requests zu senden, der mit dem XMLHttpRequestObjekt erzeugt wurde. Ein XML-Dokument und XML-Elemente werden auch oft serialisiert, um Nachrichten zu debuggen! In Mozilla-basierten Browsern wird die Serialisierung mit dem XMLSerializer-Objekt durchgeführt. Unter IE ist es noch einfacher: Die xml-Eigenschaft eines XML-Documentoder -Element-Objekts gibt das serialisierte Format des Dokuments oder Elements aus. Beispiel 21-11 zeigt Code zur Serialisierung unter Mozilla und IE. Beispiel 21-11: Serialisierung von XML /** * Serialisiere ein XML-Document oder -Element, und gib es als String zurück. */ XML.serialize = function(node) { if (typeof XMLSerializer != "undefined") return (new XMLSerializer( )).serializeToString(node);
21.5 Serialisierung von XML |
571
491-0.book Seite 572 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 21-11: Serialisierung von XML (Fortsetzung) else if (node.xml) return node.xml; else throw "XML.serialize wird nicht unterstützt oder kann " + node + " nicht serialisieren"; };
21.6 HTML-Templates mit XML-Daten erweitern Ein Hauptfeature der XML-Dateninseln von IE ist die Möglichkeit, dass sie mit einer automatischen Template-Einrichtung verwendet werden können, in der Daten aus einer Dateninsel automatisch in HTML-Elemente eingefügt werden. Diese HTML-Templates werden unter IE definiert, indem die Attribute datasrc und datafld (»fld« kurz für »field«) zu den Elementen hinzugefügt werden. In diesem Abschnitt werden die weiter oben im Kapitel vorgestellten Techniken angewandt. XPath und DOM werden verwendet, um eine verbesserte Template-Einrichtung zu erstellen, die unter IE und Firefox funktioniert. Ein Template ist ein beliebiges HTMLElement mit einem datasource-Attribut. Der Wert dieses Attributs sollte die ID einer XML-Dateninsel oder die URL eines externen XML-Dokuments sein. Das Template-Element sollte außerdem ein foreach-Attribut haben. Der Wert dieses Attributs ist ein XPath-Ausdruck, dessen Auswertung die Knotenliste ergibt, aus der die XML-Daten extrahiert werden. Für jeden XML-Knoten, der von dem foreach-Ausdruck zurückgegeben wird, wird eine erweiterte Kopie des Templates in das HTML-Dokument eingefügt. Das Template wird erweitert, indem alle Elemente in ihm gefunden werden, die ein dataAttribut haben. Dieses Attribut ist ein weiterer XPath-Ausdruck, der im Kontext eines von dem foreach-Ausdruck zurückgegeben Knotens ausgewertet werden soll. Dieser data-Ausdruck wird mit XML.getNode( ) ausgewertet. Der im zurückgegebenen Knoten enthaltene Text wird als Inhalt des HTML-Elements verwendet, für das das data-Attribut definiert wurde. Diese Beschreibung wird durch ein praktisches Beispiel viel verständlicher. Beispiel 21-12 ist ein einfaches HTML-Dokument, das eine XML-Dateninsel enthält, sowie ein Template, das die Dateninsel verwendet. Es hat einen onload( )-Event-Handler, der das Template erweitert. Beispiel 21-12: Eine XML-Dateninsel und HTML-Template
572 | Kapitel 21: JavaScript und XML
491-0.book Seite 573 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 21-12: Eine XML-Dateninsel und HTML-Template (Fortsetzung)
Ein wichtiger Teil im Beispiel 21-12 ist der onload-Event-Handler, der eine Funktion namens XML.expandTemplates( ) aufruft. Beispiel 21-13 zeigt die Implementierung dieser Funktion. Der Code ist weitgehend plattformunabhängig und benutzt die grundlegende Level 1 DOM-Funktionalität und die XPath-Utility-Funktionen XML.getNode( ) and XML. getNodes( ), die aus Beispiel 21-10 stammen. Beispiel 21-13: HTML-Templates erweitern */ * Erweitere beliebige Templates in oder unterhalb von Element e. * Wenn ein Template XPath-Ausdrücke mit Namensräumen verwendet, so übergib * als zweites Argument eine Präfix-zu-URL-Zuordnung (wie bei XML.XPathExpression( )) * * Wenn e nicht angegeben wird, wird stattdessen document.body verwendet. Eine übliche * Anwendung ist der Aufruf dieser Funktion ohne Argumente als Antwort auf einen * onload-Event-Handler. Dadurch werden alle Templates automatisch erweitert. */ XML.expandTemplates = function(e, namespaces) { // Argumente etwas in Ordnung bringen. if (!e) e = document.body; else if (typeof e == "string") e = document.getElementById(e); if (!namespaces) namespaces = null; // undefined funktioniert nicht // // // if
Ein HTML-Element ist ein Template, wenn es ein "datasource"-Attribut aufweist. Suche und erweitere alle Templates rekursiv. Beachten Sie, dass wir Templates innerhalb von Templates nicht zulassen. (e.getAttribute("datasource")) {
21.6 HTML-Templates mit XML-Daten erweitern |
573
491-0.book Seite 574 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 21-13: HTML-Templates erweitern (Fortsetzung) // Wenn es ein Template ist, so erweitere es. XML.expandTemplate(e, namespaces); } else { // Ansonsten führe die Rekursion für jedes Kind durch. Wir fertigen eine statische // Kopie der Kinder an, sodass die Template-Erweiterung unsere // Rekursion nicht durcheinanderbringt. var kids = []; // Zum Speichern der Kindelement-Kopien for(var i = 0; i < e.childNodes.length; i++) { var c = e.childNodes[i]; if (c.nodeType == 1) kids.push(e.childNodes[i]); } // Rekursiere jetzt für jedes Kindelement for(var i = 0; i < kids.length; i++) XML.expandTemplates(kids[i], namespaces); } }; /** * Erweitere genau ein angegebenes Template. * Wenn die XPath-Ausdrücke im Template Namensräume verwenden, muss das zweite * Argument eine Präfix-zu-URL-Zuordnung angeben */ XML.expandTemplate = function(template, namespaces) { if (typeof template=="string") template=document.getElementById(template); if (!namespaces) namespaces = null; // undefined funktioniert nicht // Das Erste, was wir über ein Template wissen müssen, ist, woher die // Daten kommen. var datasource = template.getAttribute("datasource"); // Wenn das Attribut der Datenquelle mit '#' beginnt, so ist das der // Name einer XML-Dateninsel. Ansonsten ist es die URL einer externen XML-Datei. var datadoc; if (datasource.charAt(0) == '#') // Hole Dateninsel datadoc = XML.getDataIsland(datasource.substring(1)); else // Oder lade externes Dokument datadoc = XML.load(datasource); // Finde jetzt heraus, welche Knoten in der Datenquelle verwendet werden, um // die Daten zur Verfügung zu stellen. Wenn das Template ein foreach-Attribut hat, // verwenden wir es als XPath-Ausdruck, um eine Knotenliste zu erhalten. Andernfalls // verwenden wir alle Kind-Elemente des document-Elements. var datanodes; var foreach = template.getAttribute("foreach"); if (foreach) datanodes = XML.getNodes(datadoc, foreach, namespaces); else { // Wenn kein "foreach"-Attribut existiert, verwende die Kindelemente // des documentElement
574 | Kapitel 21: JavaScript und XML
491-0.book Seite 575 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 21-13: HTML-Templates erweitern (Fortsetzung) datanodes = []; for(var c=datadoc.documentElement.firstChild; c!=null; c=c.nextSibling) if (c.nodeType == 1) datanodes.push(c); }
clientseitiges JavaScript
// Entferne das Template-Element aus seinem übergeordeten Knoten, // aber speichere den übergeordneten Knoten sowie den nextSibling des Templates. var container = template.parentNode; var insertionPoint = template.nextSibling; template = container.removeChild(template); // Für jedes Element des datanodes-Arrays fügen wir wieder eine Kopie des // Templates in den container ein. Bevor wir das machen, // erweitern wir aber jedes Kind in der Kopie, das ein "data"-Attribut hat. for(var i = 0; i < datanodes.length; i++) { var copy = template.cloneNode(true); // Kopiere die Vorlage expand(copy, datanodes[i], namespaces); // Erweitere die Kopie container.insertBefore(copy, insertionPoint); // Füge die Kopie ein } // Diese rekursive Funktion sucht alle Kindelemente von e, die ein data// Attribut haben. Sie behandelt dieses Attribut als einen XPath-Ausdruck und // wertet ihn im Kontext von datanode aus. Sie nimmt den Textwert des // XPath-Ergebnisses und macht ihn zum Inhalt des zu erweiternden HTML-Knotens. // Der restliche Inhalt wird gelöscht. function expand(e, datanode, namespaces) { for(var c = e.firstChild; c != null; c = c.nextSibling) { if (c.nodeType != 1) continue; // nur Elemente var dataexpr = c.getAttribute("data"); if (dataexpr) { // Werte XPath-Ausdruck in context aus. var n = XML.getNode(datanode, dataexpr, namespaces); // Lösche den gesamten Inhalt des Elements c.innerHTML = ""; // und füge den Textinhalt des XPath-Ergebnisses ein c.appendChild(document.createTextNode(getText(n))); } // Wenn wir das Element nicht erweitern, rekursiere auf ihm else expand(c, datanode, namespaces); } } // Diese rekursive Funktion extrahiert den Text aus einem DOM-Node und // rekursiert, wenn notwendig. function getText(n) { switch(n.nodeType) { case 1: /* Element */ var s = ""; for(var c = n.firstChild; c != null; c = c.nextSibling) s += getText(c);
21.6 HTML-Templates mit XML-Daten erweitern |
575
491-0.book Seite 576 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 21-13: HTML-Templates erweitern (Fortsetzung) return s; case 2: /* Attribut*/ case 3: /* Text */ case 4: /* cdata */ return n.nodeValue; default: return ""; } } };
21.7 XML und Webservices Webservices stellen eine wichtige Anwendung für XML dar, und SOAP ist ein beliebtes Webservice-Protokoll, das vollständig auf XML beruht. In diesem Abschnitt zeige ich Ihnen, wie man das XMLHttpRequest-Objekt und XPath-Queries verwenden kann, um einfache SOAP-Anfragen an einen Webservice zu stellen. Beispiel 21-14 ist JavaScript-Code, der ein XML-Dokument konstruiert. Dieses stellt einen SOAP-Request dar und verwendet XMLHttpRequest, um ihn an einen Webservice zu senden. (Der Webservice gibt den Umtauschkurs zwischen den Währungen zweier Länder zurück). Der Code verwendet dann eine XPath-Query, um das Ergebnis aus der vom Server zurückgegebenen SOAP-Response zu extrahieren. Bevor wir uns den Code anschauen, muss ich Sie auf einige Dinge aufmerksam machen. Erstens sind Einzelheiten des SOAP-Protokolls nicht Gegenstand dieses Kapitels. Dieses Beispiel veranschaulicht einen einfachen SOAP-Request und eine SOAP-Response, ohne den Versuch zu machen, das Protokoll oder das XML-Format zu erklären. Zweitens verwendet das Beispiel keine Web Services Definition Language-(WSDL-)Dateien, um Einzelheiten über den Webservice herauszufinden. Die URL des Servers, die Methode und die Parameternamen sind alle im Beispielcode hardcodiert. Die dritte Warnung hat es in sich. Die Verwendung von Webservices von clientseitigem JavaScript aus wird durch die Same Origin Policy (siehe Abschnitt 13.8.2) stark eingeschränkt. Erinnern wir uns daran, dass die Same Origin Policy Skripte auf der Clientseite davon abhält, eine Verbindung zu anderen Hosts herzustellen oder Daten von ihnen abzurufen, wenn sie nicht mit dem Host identisch sind, von dem das Dokument mit dem gerade ausführenden Skript geladen wurde. Das bedeutet, dass JavaScript-Code in der Regel nur dann zum Zugriff auf einen Webservice geeignet ist, wenn er auf dem gleichen Server wie der Webservice untergebracht wird. Wer einen Webservice implementiert, will JavaScript vielleicht als einfache auf HTML basierende Schnittstelle für seine Dienste verwenden. Die Same Origin Policy verhindert aber den umfangreichen Gebrauch von clientseitigem JavaScript, wenn es um die Aggregation von Webservice-Ergebnissen aus verschiedenen Internetquellen in einer einzigen Webseite geht.
576 | Kapitel 21: JavaScript und XML
491-0.book Seite 577 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Damit Beispiel 21-14 unter Firefox läuft, enthält es einen Aufruf der Firefox-spezifischen enablePrivilege( )-Methode. Dieser Aufruf fordert den Benutzer auf, dem Skript weiterführende Rechte zuzugestehen, so dass es die Same Origin Policy aufheben kann. Das funktioniert, wenn das Beispiel von einer file:-URL aus im lokalen Dateisystem läuft. Es funktioniert nicht, wenn das Beispiel von einem Webserver heruntergeladen wird (es sei denn, das Skript wurde digital unterschrieben, was in diesem Buch nicht behandelt wird). Mit diesen Warnungen im Hinterkopf schauen wir uns jetzt den Code an. Beispiel 21-14: Einen Webservice mit SOAP abfragen /** * Diese Funktion gibt den Wechselkurs zwischen den Währungen zweier * Länder aus. Sie holt den Wechselkurs über einen SOAP-Request an einen * Beispiel-Webservice, der von XMethods gehostet wird (http://www.xmethods.net). * Dieser Service dient nur zur Veranschaulichung und garantiert keine * Ansprechempfindlichkeit, kein Vorhandensein oder keine Richtigkeit der Daten. Bitte * überlasten Sie den XMethod-Server nicht durch zu häufiges Ausführen dieses Beispiels. * Siehe http://www.xmethods.net/v2/demoguidelines.html */ function getExchangeRate(land1, land2) { // Unter Firefox müssen wir den Benutzer auffordern, uns die erforderlichen Rechte zu // geben. // Wir brauchen spezielle Rechte, da wir mit einem Webserver reden, der // nicht derjenige ist, von dem aus das Dokument geladen wurde, das das Skript enthält. // UniversalXPConnect ermöglicht es uns, einen XMLHttpRequest an den Server zu senden, // ermöglicht es uns, einen XMLHttpRequest an den Server zu senden, und // und UniversalBrowserRead erlaubt es uns, die Antwort anzuschauen. // Unter IE muss der Benutzer "Auf Datenquellen über Domänengrenzen hinweg zugreifen" // im Dialog Extras->Internetoptionen->Sicherheit aktivieren. if (typeof netscape != "undefined") { netscape.security.PrivilegeManager. enablePrivilege("UniversalXPConnect UniversalBrowserRead"); } // Erzeuge einen XMLHttpRequest, um den SOAP-Request auszugeben. Das ist eine Utility// Funktion, die im letzten Kapitel definiert wurde. var request = HTTP.newRequest( );
21.7 XML und Webservices |
577
clientseitiges JavaScript
Um Beispiel 21-14 unter IE laufen zu lassen, können Sie die Same Origin Policy lockern. Wählen Sie Extras ➝ Internetoptionen ➝ Sicherheit, und klicken Sie im dann erscheinenden Dialog auf die Registrierkarte Internet. Scrollen Sie durch die Auflistung der Sicherheitsoptionen, bis Sie die mit dem Namen »Auf Datenquellen über Domänengrenzen hinweg zugreifen« finden. Diese Option ist gewöhnlich auf deaktivieren gesetzt (und das ist auch richtig so). Um dieses Beispiel laufen zu lassen, ändern Sie sie in Eingabeaufforderung.
491-0.book Seite 578 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 21-14: Einen Webservice mit SOAP abfragen (Fortsetzung) // Wir werden an diese URL POSTen und wollen eine synchrone Response request.open("POST", "http://services.xmethods.net/soap", false); // Setze ein paar Header: Der Body dieses POST-Requests ist XML request.setRequestHeader("Content-Type", "text/xml"); // Dieser Header ist ein notwendiger Teil des SOAP-Protokolls request.setRequestHeader("SOAPAction", '""'); // Sende jetzt einen SOAP-Request im XML-Format an den Server request.send( '' + '' + ' '+ ' ' + ' ' + land1 + '' + ' ' + land2 + '' + ' ' + ' ' + '' ); // Wenn wir einen HTTP-Fehler erhalten, löse eine Exception aus if (request.status != 200) throw request.statusText; // Diese XPath-Query gibt uns das -Element aus dem Dokument var query = "/s:Envelope/s:Body/ex:getRateResponse"; // Dieses Objekt definiert die in der Abfrage verwendeten Namensräume var namespaceMapping = { s: "http://schemas.xmlsoap.org/soap/envelope/", // SOAP-Namensraum ex: "urn:xmethods-CurrencyExchange" // der service-spezifische Namensraum }; // Extrahiere das -Element aus dem Antwortdokument var responseNode=XML.getNode(request.responseXML, query, namespaceMapping); // Das tatsächliche Ergebnis steht in einem Textknoten innerhalb eines -Knotens // in der return responseNode.firstChild.firstChild.nodeValue; }
578 | Kapitel 21: JavaScript und XML
491-0.book Seite 579 Mittwoch, 4. April 2007 9:55 09
e-bol.net
21.8 E4X: ECMAScript für XML
Obwohl E4X ein offizieller Standard ist, ist es noch nicht verbreitet genug, um eine genaue Beschreibung in diesem Buch zu rechtfertigen. Trotz seiner begrenzten Verfügbarkeit werden die leistungsstarken und einzigartigen Features von E4X hier kurz dargestellt. In diesem Abschnitt erhalten Sie anhand von Beispielen einen Überblick über E4X. Zukünftige Ausgaben dieses Buchs werden das Thema eventuell besser abdecken. Das Auffälligste an E4X ist, dass die XML-Syntax zum Bestandteil der JavaScript-Sprache wird und Sie XML-Literale wie das folgende direkt in Ihren JavaScript-Code aufnehmen können: // Erzeuge ein XML-Objekt var pt = Wasserstoff Helium Lithium ; // Füge der Tabelle ein neues Element hinzu pt.element += Beryllium;
Die XML-Literalsyntax von E4X verwendet geschweifte Klammern als Escape-Zeichen, mit denen Sie JavaScript-Ausdrücke in XML unterbringen können. Das hier ist ein anderes Beispiel zum Erstellen des gerade gezeigten XML-Elements: pt = ; // Beginne mit einer leeren Tabelle var elements = ["Wasserstoff", "Helium", "Lithium"]; // die hinzuzufügenden Elemente // Erzeuge XML-Tags aus Array-Inhalten for(var n = 0; n < elements.length; n++) { pt.element += {elements[n]}; }
Zusätzlich zu dieser Literal-Syntax können Sie auch mit aus Strings geparstem XML arbeiten. Dieser Code fügt Ihrem Periodensystem ein weiteres Element hinzu: pt.element += new XML('Bor');
1 E4X wird durch den ECMA-357-Standard definiert. Sie können die offizielle Spezifikation unter http://www.ecma-international.org/publications/standards/Ecma-357.htm finden.
21.8 E4X: ECMAScript für XML |
579
clientseitiges JavaScript
ECMAScript für XML, besser bekannt als E4X, ist eine Standarderweiterung1 von JavaScript, die eine Anzahl leistungsfähiger Features für die Verarbeitung von XMLDokumenten definiert. Als dieses Buch geschrieben wurde, stand E4X noch nicht weitverbreitet zur Verfügung. Firefox 1.5 unterstützt es, und es ist auch auch in Version 1.6 von Rhino verfügbar, dem JavaScript-Interpreter auf Java-Basis. Microsoft plant nicht, es in IE 7 zu unterstützen, und es ist auch nicht klar, ob oder wann andere Browser Unterstützung anbieten werden.
491-0.book Seite 580 Mittwoch, 4. April 2007 9:55 09
e-bol.net Wenn
Sie
mit
XML-Fragmenten
arbeiten,
sollten
Sie
statt
XML( )
besser
XMLList( )verwenden: pt.element += new XMLList('Kohlenstoff' + 'Stickstoff');
Sobald Sie ein XML-Dokument definiert haben, definiert E4X eine intuitive Syntax zum Zugriff auf seinen Inhalt: var elements = pt.element; var names = pt.element.name; var n = names[0];
// Ergibt eine Liste aller -Tags // Eine Liste aller -Tags // "Wasserstoff": Inhalt des -Tags 0.
Zusätzlich fügt E4X neue Syntax zum Arbeiten mit XML-Objekten hinzu. Der Operator .. ist der Nachfahre-Operator; Sie können ihn anstelle des normalen .-KlassenelementOperators verwenden: // Hier sehen Sie eine Alternative zum Erzeugen einer Liste aller -Tags var names2 = pt..name;
E4X hat sogar einen Wildcard-Operator: // Hole alle Nachfahren aller -Tags. // Dies ist noch eine Möglichkeit, eine Liste aller -Tags zu erhalten. var names3 = pt.element.*;
Unter E4X unterscheiden sich Attributnamen von Tag-Namen durch das Zeichen @ (eine von XPath übernommene Syntax). Den Wert eines Attributs können Sie beispielsweise so abfragen: // Welche Ordnungszahl hat Helium? var atomicNumber = pt.element[1].@id;
Der Wildcard-Operator für Attributnamen ist @*: // Eine Liste aller Attribute aller -Tags var atomicNums = pt.element.@*;
E4X enthält sogar eine schlagkräftige und erstaunlich präzise Syntax zum Filtern einer Liste anhand einer beliebigen Eigenschaft: // Beginne mit einer Liste aller Elemente, und filtere sie so, // dass sie nur diejenigen Elemente enthält, deren id-Attribut < 3 ist var lightElements = pt.element.(@id < 3); // Beginne mit einer Liste aller -Tags, und filtere sie so, dass sie nur // diejenigen Tags enthält, deren Namen mit "B" beginnen. Erstelle dann eine Liste der // -Tags mit jedem dieser übrig gebliebenen -Tags. var bElementNames = pt.element.(name.charAt(0) == 'B').name;
E4X definiert ein neues Schleifenstatement, um die Liste der XML-Tags und -Attribute zu durchlaufen. Die Schleife for/each/in funktioniert wie die for/in-Schleife, außer dass nicht durch die Eigenschaften eines Objekts iteriert wird, sondern durch die Werte der Eigenschaften eines Objekts:
580 | Kapitel 21: JavaScript und XML
491-0.book Seite 581 Mittwoch, 4. April 2007 9:55 09
e-bol.net // Drucke den Namen jedes Elements im Periodensystem aus // (Angenommen, Sie haben eine print( )-Funktion definiert.) for each (var e in pt.element) { print(e.name); }
Bei E4X-aktivierten Browsern ist diese for/each/in-Schleife auch zum Durchlaufen von Arrays nützlich. E4X-Ausdrücke können auf der linken Seite einer Zuweisung stehen. Dadurch können bestehende Tags und Attribute geändert und neue hinzugefügt werden: // Ändere das -Tag für Wasserstoff, um ein neues Attribut // und ein neues Kindelement hinzuzufügen, sodass der Code so aussieht: // // // Wasserstoff // 1.00794 // // pt.element[0].@symbol = "H"; pt.element[0].gewicht = 1.00794;
Mit dem standardisierten delete-Operator können Attribute und Tags auch auf einfache Art entfernt werden: delete pt.element[0].@symbol; delete pt..gewicht;
// lösche ein Attribut // lösche alle -Tags
E4X wurde so entwickelt, dass die meisten üblichen XML-Manipulationen mit der Sprachsyntax durchgeführt werden können. E4X definiert zusätzlich Methoden, die Sie auf XML-Objekten aufrufen können. Hier sehen Sie beispielsweise die insertChildBefore( )-Methode: pt.insertChildBefore(pt.element[1], Deuterium);
Beachten Sie, dass die von E4X-Ausdrücken erzeugten und bearbeiteten Objekte XMLObjekte sind. Sie sind keine DOM-Node- oder -Element-Objekte und sind nicht mit der DOM API kompatibel. Der E4X-Standard definiert eine optionale XML-Methode domNode( ), die ein DOM-Knoten-Äquivalent zum XML-Objekt zurückgibt, aber diese Methode wird unter Firefox 1.5 nicht implementiert. Der E4X-Standard gibt auch an, dass ein DOM-Knoten an den XML( )-Konstruktor übergeben werden kann, um das E4X-Äquivalent des DOM-Baums zu erhalten. Dieses Feature ist unter Firefox 1.5 ebenfalls nicht implementiert, wodurch die Nützlichkeit von E4X für clientseitiges JavaScript eingeschränkt wird. E4X ist vollständig kompatibel mit Namensräumen und enthält Sprachsyntax und APIs zum Arbeiten mit XML-Namensräumen. Aus Gründen der Einfachheit haben die hier gezeigten Beispiele diese Syntax nicht demonstriert.
21.8 E4X: ECMAScript für XML |
581
clientseitiges JavaScript
// Drucke die Ordnungszahlen der Elemente aus for each (var n in pt.element.@*) print(n);
491-0.book Seite 582 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Chapter 1
KAPITEL 22
Skriptgesteuerte Grafiken auf der Clientseite
In diesem Kapitel wird beschrieben, wie Grafiken mit JavaScript bearbeitet werden. Zunächst werden herkömmliche JavaScript-Techniken für optische Effekte erklärt, wie z.B. für Bild-Rollover (bei denen ein statisches Bild durch ein anderes ersetzt wird, wenn der Mauszeiger über dieses bewegt wird). Anschließend wird beschrieben, wie Sie JavaScript zum Zeichnen Ihrer eigenen Grafiken verwenden können. Durch die Kombination von JavaScript mit CSS können horizontale und vertikale Linien und Rechtecke gezeichnet werden, was für viele Arten von »Boxen-und-Pfeile«-Zeichnungen und aufwendigere Grafiken, wie beispielsweise Balkendiagramme, ausreicht. Als Nächstes werden Vektorgrafik-Technologien erläutert, die weitaus leistungsfähigere Zeichnungsmöglichkeiten auf der Clientseite bereitstellen. Die Fähigkeit, anspruchsvolle Grafiken auf der Clientseite dynamisch erzeugen zu können, ist aus mehreren Gründen wichtig: • Der Code zum Erstellen von clientseitigen Grafiken ist normalerweise viel kürzer als die eigentlichen Bilder es wären, wodurch erhebliche Bandbreiteneinsparungen möglich werden. • Dynamisch erzeugte Grafiken aus Echtzeitdaten brauchen sehr viele CPU-Zyklen. Wird diese Arbeit an den Client weitergegeben (der oft CPU-Leistung übrig hat), vermindert sich die Serverlast, und es lassen sich eventuell sogar Hardware-Kosten einsparen. • Die Erzeugung von clientseitigen Grafiken passt in die Ajax-Anwendungsarchitektur, bei der Server die Daten zur Verfügung stellen und die Clients die Anzeige dieser Daten regeln. Das Kapitel enthält Beispiele für fünf Vektorgrafik-Technologien, die mit clientseitigem JavaScript nutzbar gemacht werden können: • Scalable Vector Graphics oder kurz SVG ist eine dem W3C-Standard entsprechende und auf XML basierende Sprache zur Beschreibung von Zeichnungen. SVG wurde als Erstes von Firefox 1.5 unterstützt und ist über Plug-ins auch in anderen Browsern verfügbar. Da SVG-Zeichnungen XML-Dokumente sind, können sie in JavaScript dynamisch erzeugt werden.
582 |
491-0.book Seite 583 Mittwoch, 4. April 2007 9:55 09
e-bol.net • Vector Markup Language, oder VML, ist die SVG-Alternative exklusiv für Microsoft. Sie ist nicht sehr bekannt, steht aber seit Internet Explorer 5.5 zur Verfügung. Genau wie SVG basiert VML auf XML, und VML-Zeichnungen können dynamisch auf der Clientseite erzeugt werden.
• Der Flash-Player steht in den meisten Webbrowsern als Plug-in zur Verfügung. Flash 6 führte eine Zeichnungs-API ein, und mit Flash 8 wurde die Verwendung dieser API von clientseitigem JavaScript aus sehr vereinfacht. • Schließlich unterstützt Java eine leistungsstarke Zeichnungs-API und ist in vielen Webbrowsern über ein Plug-in von Sun Microsystems erhältlich. Wie die Kapitel 12 und 23 zeigen, kann JavaScript-Code Methoden von Java-Applets aufrufen und – in Mozilla-basierten Browsern – sogar Java-Methoden in Abwesenheit eines Applets aufrufen. Dadurch kann JavaScript-Code auf der Clientseite die hochentwickelte Vektorzeichnungs-API von Java verwenden. Bevor wir uns diese fortgeschrittenen Zeichentechniken ansehen, fangen wir zunächst mit den Grundlagen an.
22.1 Skriptgesteuerte Bilder Webseiten enthalten Bilder, die das HTML--Tag verwenden. Wie alle HTML-Elemente ist ein -Tag Teil des DOM und kann deshalb wie jedes andere Element in einem Dokument per Skript gesteuert werden. Dieser Abschnitt stellt einige weitverbreitete Techniken vor.
22.1.1 Bilder und das Level 0 DOM Bilder waren eines der ersten skriptgesteuerten HTML-Elemente. Mit dem Level 0 DOM können Sie über das images[]-Array des Document-Objekts auf Bilder zugreifen. Jedes Element dieses Arrays ist ein Image-Objekt, das ein -Tag im Dokument repräsentiert. Eine vollständige Dokumentation des Image-Objekts finden Sie in Teil IV. Zugriff auf Image-Objekte besteht auch über Level 1 DOM-Methoden, wie z.B. getElementById( ) und getElementsByTagName( ) (siehe Kapitel 15). Das Array document.images[] führt Image-Objekte in der im Dokument angezeigten Reihenfolge auf. Nützlicher ist allerdings, dass es Zugang zu angegebenen Bildern verschafft. Hat ein -Tag ein name-Attribut, so kann das Bild über den von diesem Attribut angegebenen Namen abgefragt werden. Nehmen wir beispielsweise dieses -Tag:
22.1 Skriptgesteuerte Bilder |
583
clientseitiges JavaScript
• Das HTML--Tag stellt eine ausdrücklich auf JavaScript basierende Zeichnungs-API zur Verfügung. Sie wurde unter Safari 1.3 eingeführt und von Firefox 1.5 und Opera 9 übernommen.
491-0.book Seite 584 Mittwoch, 4. April 2007 9:55 09
e-bol.net Wenn wir annehmen, dass kein anderes -Tag den gleichen Wert für sein name-Attribut hat, ist das entsprechende Image-Objekt zugänglich als: document.images.nextpage
oder als: document.images["nextpage"]
Wenn kein anderes Tag (beliebigen Typs) im Dokument das gleiche name-Attribut hat, ist das Image-Objekt sogar über eine Eigenschaft des document-Objekts selbst zugänglich: document.nextpage
22.1.2 Herkömmliche Bild-Rollover Das wichtigste Feature des Image-Objekts ist, dass seine src-Eigenschaft les- und schreibbar ist. Sie können diese Eigenschaft lesen, um die URL zu erhalten, von der ein Bild geladen wurde. Noch wichtiger ist die Möglichkeit, die src-Eigenschaft setzen zu können, um den Browser zum Laden und Anzeigen eines neuen Bildes am gleichen Platz aufzufordern. Die Fähigkeit, in einem HTML-Dokument ein Bild dynamisch durch ein anderes zu ersetzen, öffnet die Tür zu einer Vielzahl von Spezialeffekten, von der Animation bis zu Digitaluhren, die sich selbst in Echtzeit laufen lassen. In der Praxis ist die verbreitetste Anwendung der Bildersetzung die Implementierung von Bild-Rollovern, in denen sich ein Bild ändert, wenn der Mauszeiger über das Bild bewegt wird. (Um verzerrende optische Effekte zu umgehen, sollte das neue Bild die gleiche Größe wie das Original haben.) Wenn Sie Bilder anklickbar machen, indem Sie sie in Ihre Hyperlinks setzen, sind Rollover-Effekte eine leistungsfähige Methode, den Benutzer einzuladen, auf das Bild zu klicken.1 Dieses einfache HTML-Fragment zeigt ein Bild in einem -Tag an und verwendet JavaScript-Code in den Event-Handlern onmouseover und onmouseout, um einen Rollover-Effekt zu erzeugen:
Beachten Sie, dass das -Tag in diesem Code-Fragment ein name-Attribute enthält, das es einfach macht, in den Event-Handlern des -Tags auf das entsprechende ImageObjekt zu verweisen. Das Attribut border hindert den Browser daran, einen blauen Hyperlink-Rahmen um das Bild herum anzuzeigen. Die Event-Handler des -Tags erle1 Eine Besprechung von Bild-Rollovern wäre unvollständig ohne den Hinweis, dass sie auch mit der CSS-Pseudoklasse :hover implementiert werden können, um verschiedene CSS-Hintergrundbilder auf Elemente anzuwenden, wenn die Maus über ihnen »schwebt«. Leider ist es schwierig, CSS-Bild-Rollover portabel zu machen. In der Praxis ist :hover nützlicher, wenn es statt auf Bilder auf Hyperlinks mit Textinhalt angewendet wird.
584 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 585 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Bild-Rollover werden stark mit der Anklickbarkeit von Bildern assoziiert. Daher sollte dieses -Tag außerdem in ein -Tag eingebettet werden oder einen onclick-EventHandler haben.
22.1.3 Offscreen-Bilder und Caching Um praktikabel zu sein, müssen Bild-Rollover und ähnliche Effekte schnelle Ansprechzeiten haben. Also müssen Sie sicherstellen können, dass die benötigten Bilder im Voraus in den Cache des Browsers geladen werden. Um ein Bild in den Cache zu zwingen, erzeugen Sie zuerst mit dem Image( )-Konstruktor ein Image-Objekt. Dann laden Sie das Bild in das Objekt, indem Sie dessen src-Eigenschaft auf die gewünschte URL setzen. Das Bild wird nicht zum Dokument hinzugefügt und ist damit nicht sichtbar, aber der Browser lädt es trotzdem und speichert die Bilddaten im Cache. Wenn die gleiche URL später für ein Onscreen-Bild verwendet wird, braucht es nicht erst langsam über das Netzwerk geladen zu werden, sondern kann schnell aus dem Browser-Cache geholt werden. Das im vorhergehenden Abschnitt gezeigte Bild-Rollover-Codefragment lädt das verwendete Rollover-Bild nicht vorab, wodurch der Benutzer eventuell eine Verzögerung im Rollover-Effekt bemerkt, wenn er die Maus zum ersten Mal über das Bild bewegt. Um dieses Problem zu umgehen, ändern Sie den Code wie folgt: (new Image( )).src = "images/help_rollover.gif";
22.1.4 Unauffällige Bild-Rollover Der gerade gezeigte Bild-Rollover-Code benötigt ein -Tag und zwei JavaScriptEvent-Handler-Attribute, um einen einzigen Rollover-Effekt zu implementieren. Das ist ein perfektes Beispiel für auffälliges JavaScript. Obwohl es oft vorkommt, dass Code die Darstellung (HTML) und das Verhalten (JavaScript) auf diese Art kombiniert, ist es besser, das so weit wie möglich zu vermeiden. Das gilt vor allem dann, wenn wie in diesem
22.1 Skriptgesteuerte Bilder |
585
clientseitiges JavaScript
digen die ganze Arbeit: Sie ändern das gerade dargestellte Bild, indem sie einfach die srcEigenschaft des Bildes auf die URLs der gewünschten Bilder setzen. Diese Event-Handler sind im -Tag platziert, da sehr alte Browser diese Handler nur für bestimmte Tags, wie z.B. , unterstützen. In praktisch allen derzeit verwendeten Browsern können Sie die Event-Handler in das -Tag selbst setzen, was das Auffinden des Bilds vereinfacht. Der Event-Handler-Code kann dann mit dem this-Schlüsselwort auf dieses ImageObjekt verweisen:
491-0.book Seite 586 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel der Umfang des JavaScript-Codes sehr umfangreich ist und das HTML praktisch versteckt. Für den Anfang zeigt Beispiel 22-1 eine Funktion, die einen Rollover-Effekt zu einem angegebenen -Element hinzufügt. Beispiel 22-1: Einem Bild einen Rollover-Effekt hinzufügen /** * Dem angegebenen Bild einen Rollover-Effekt geben, indem wir Event* Handler zum Umschalten des Bilds auf die angegebene URL hinzufügen, * wenn die Maus über dem Bild steht. * * Wenn das Bild als String angegeben ist, so suche nach einem Bild mit * diesem String als id- oder name-Attribut. * * Diese Methode setzt die Event-Handler onmouseover und onmouseout * des angegebenen Bildes und überschreibt/entsorgt dabei alle Handler, * die vorher über diese Eigenschaften gesetzt wurden. */ function addRollover(img, rolloverURL) { if (typeof img == "string") { // Wenn img ein String ist, var id = img; // es ist eine id, kein Image img = null; // und wir haben noch kein Bild. // Versuche zuerst, das Bild über die id zu finden if (document.getElementById) img = document.getElementById(id); else if (document.all) img = document.all[id]; // ist es über id erfolglos, suche das Bild über den Namen. if (!img) img = document.images[id]; // Bild nicht aufzufinden? Nichts machen und aufgeben if (!img) return; } // Wenn das Element kein -Tag ist, geben wir auch auf if (img.tagName.toLowerCase( ) != "img") return; // Speichere die Original-URL des Bildes var baseURL = img.src; // Lade das Rollover-Bild im Voraus in den Browser-Cache (new Image( )).src = rolloverURL; img.onmouseover = function( ) { img.src = rolloverURL; } img.onmouseout = function( ) { img.src = baseURL; } }
Die addRollover( )-Funktion, die in Beispiel 22-1 definiert wurde, ist nicht komplett unauffällig, da Sie immer noch ein Skript in Ihren HTML-Dateien unterbringen müssen, das die Funktion aufruft. Um wirklich unauffällige Bild-Rollover zu erreichen, müssen
586 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 587 Mittwoch, 4. April 2007 9:55 09
e-bol.net Sie signalisieren können, welche Bilder Rollover haben und was die URL des RolloverBildes ist, ohne dabei JavaScript zu verwenden. Eine einfache Art, das zu erreichen, ist das Einfügen eines unechten HTML-Attributs in das -Tag. Sie können Bilder mit Rollover-Effekten beispielsweise so codieren:
Beispiel 22-2: Rollover-Effekte unauffällig hinzufügen /** * Suche alle -Tags im Dokument, die ein "rollover"* Attribut haben. Verwende den Wert dieses Attributs als URL eines * Bildes, das beim Bewegen der Maus über dem Bild angezeigt wird, und setze * entsprechende Event-Handler, um den Rollover-Effekt zu erzielen. */ function initRollovers( ) { var images = document.getElementsByTagName("img"); for(var i = 0; i < images.length; i++) { var image = images[i]; var rolloverURL = image.getAttribute("rollover"); if (rolloverURL) addRollover(image, rolloverURL); } }
Jetzt müssen Sie nur noch sicherstellen, dass diese initRollovers( )-Methode aufgerufen wird, sobald das Dokument geladen wurde. Der folgende Code sollte in derzeitigen Browsern funktionieren: if (window.addEventListener) window.addEventListener("load", initRollovers, false); else if (window.attachEvent) window.attachEvent("onload", initRollovers);
Kapitel 17 enthält eine vollständigere Beschreibung des onload-Handlings. Sie können also eine vollständig unauffällige Lösung für Bild-Rollovers erzielen, indem Sie die Funktionen addRollover( ) und initRollovers( ) in die gleiche Datei wie den Code für die Event-Handler-Registrierung setzen. Fügen Sie die Code-Datei einfach mit einem -Tag ein, und setzen Sie rollover-Attribute für alle -Tags, die RolloverEffekte benötigen. Wenn Sie verhindern möchten, dass Ihre HTML-Dateien bei der Validierung durchfallen, weil Sie in Ihre -Tags ein nicht standardkonformes rollover-Attribut eingefügt haben, können Sie auf XHTML umsatteln und für die neuen Attribute XML-Namensräume verwenden. Beispiel 22-3 zeigt eine Version der initRollovers( )-Funktion, die
22.1 Skriptgesteuerte Bilder |
587
clientseitiges JavaScript
Mit einer solchen Konvention bei der HTML-Codierung können Sie auf einfache Art alle Bilder lokalisieren, die Rollover-Effekte benötigen, und können diese Effekte mit der Funktion initRollovers( ) implementieren, die in Beispiel 22-2 definiert wird.
491-0.book Seite 588 Mittwoch, 4. April 2007 9:55 09
e-bol.net Namensräume erkennt. Beachten Sie allerdings, dass diese Version der Funktion nicht unter Internet Explorer 6 läuft, da dieser Browser die DOM-Methoden zur Namensraumunterstützung nicht implementiert. Beispiel 22-3: Rollover mit XHTML und Namensräumen initialisieren /** * Suche alle -Tags im Dokument mit einem "ro:src" *-Attribut. Verwende den Wert dieses Attributs als die URL eines * Bildes, das beim Bewegen der Maus über dem Bild angezeigt wird, und setze * entsprechende Event-Handler, um den Rollover-Effekt zu erzielen. * Das ro:-Namensraum-Präfix bezieht sich auf die URI * "http://www.davidflanagan.com/rollover" */ function initRollovers( ) { var images = document.getElementsByTagName("img"); for(var i = 0; i < images.length; i++) { var image = images[i]; var rolloverURL = image.getAttributeNS(initRollovers.xmlns, "src"); if (rolloverURL) addRollover(image, rolloverURL); } } // Diese Namensraum-URI wurde für unseren "ro:"-Namensraum erfunden initRollovers.xmlns = "http://www.davidflanagan.com/rollover";
22.1.5 Bildanimationen Ein weiterer Grund, die src-Eigenschaft eines -Tags per Skript zu steuern, ist die Durchführung einer Animation, in der sich ein Bild oft genug ändert, um als flüssige Bewegung zu erscheinen. Eine typische Anwendung dieser Technik ist z.B. die Anzeige einer Abfolge von Wetterkarten, die die vergangene oder vorhergesagte stündliche Entwicklung eines Sturms über 2 Tage hinweg zeigen. Beispiel 22-4 zeigt eine JavaScript-ImageLoop-Klasse zur Erstellung einer solchen Bildanimation. Es verwendet die gleiche Steuerung der src-Eigenschaft per Skript und die gleichen Techniken zum Vorausladen von Bildern wie Beispiel 22-1. Es führt außerdem den Event-Handler onload des Image-Objekts ein, der bestimmen kann, wann der Ladevorgang eines Bildes (oder in diesem Fall einer Bildabfolge) abgeschlossen ist. Der Code für die Animation selbst wird von Window.setInterval( ) gesteuert und ist recht einfach: Die Frame-Nummer wird einfach um eins erhöht und die src-Eigenschaft des angegebenen -Tags auf die URL des nächsten Frames gesetzt. Diese einfache HTML-Datei verwendet die ImageLoop-Klasse: var animation = new ImageLoop("loop", 5,["images/0.gif", "images/1.gif", "images/2.gif",
588 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 589 Mittwoch, 4. April 2007 9:55 09
Der Code in Beispiel 22-4 ist vielleicht etwas komplizierter als erwartet, da sowohl der Event-Handler Image.onload als auch die Timer-Funktion Window.setInterval( ) Funktionen nicht als Methoden, sondern als Funktionen aufrufen. Aus diesem Grund muss der ImageLoop( )-Konstruktor verschachtelte Funktionen definieren, die wissen, wie sie mit dem neu konstruierten ImageLoop umgehen sollen. Beispiel 22-4: Bildanimationen /** * ImageLoop.js: Eine ImageLoop-Klasse zur Durchführung von Bildanimationen * * Konstruktor-Argumente: * imageId: Die id des zu animierenden -Tags * fps: die Anzahl der pro Sekunde darzustellenden Frames * frameURLs: Ein Array aus URLs, eines für jedes Frame der Animation * * Öffentliche Methoden: * start( ): Animation starten (nachdem alle Frames geladen sind) * stop( ): Animation anhalten * * Öffentliche Eigenschaften: * loaded: true, wenn alle Frames der Animation geladen sind, * andernfalls false */ function ImageLoop(imageId, fps, frameURLs) { // Speichere die Image-ID. Suche sie aber noch nicht, da dieser Konstruktor // eventuell aufgerufen wird, bevor das Dokument geladen ist. this.imageId = imageId; // Berechne die Wartezeit zwischen den Frames der Animation this.frameInterval = 1000/fps; // Ein Array, das die Image-Objekte jedes Frames speichert this.frames = new Array(frameURLs.length); this.image = null; this.loaded = false; this.loadedFrames = 0; this.startOnLoad = false; this.frameNumber = -1; this.timer = null;
// // // // // //
Das -Element mit id Sind alle Frames geladen? Anzahl der geladenen Frames Starte Animation nach dem Laden? Momentan angezeigtes Frame Der Rückgabewert von setInterval( )
// Initialisiere das frames[]-Array, und lade die Bilder im Voraus
22.1 Skriptgesteuerte Bilder |
589
clientseitiges JavaScript
Start Stop
491-0.book Seite 590 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-4: Bildanimationen (Fortsetzung) for(var i = 0; i < frameURLs.length; i++) { this.frames[i] = new Image( ); // Erzeuge Image-Objekt // Registriere Event-Handler, um Laden des Frames anzuzeigen this.frames[i].onload = countLoadedFrames; // wird später definiert this.frames[i].src = frameURLs[i]; // Lade das Frame-Bild im Voraus } // Diese eingebettete Event-Handler-Funktion zählt, wie viele // Frames geladen wurden. Wenn alle geladen sind, setzt sie ein Flag // und beginnt mit der Animation, wenn das so gewünscht wurde. var loop = this; function countLoadedFrames( ) { loop.loadedFrames++; if (loop.loadedFrames == loop.frames.length) { loop.loaded = true; if (loop.startOnLoad) loop.start( ); } } // Hier definieren wir eine Funktion, die das nächste Frame der // Animation anzeigt. Sie darf keine normale Instanzmethode sein, da // setInterval( ) keine Methoden, sondern nur Funktionen aufrufen kann. // Also erstellen wir einen Wrapper, der eine Referenz // auf das ImageLoop-Objekt enthält this._displayNextFrame = function( ) { // Erhöhe zuerst die Frame-Nummer. Per Modulo-Operator (%) // springen wir vom letzten zum ersten Frame loop.frameNumber = (loop.frameNumber+1)%loop.frames.length; // Setze die src-Eigenschaft des Bildes auf die URL des neuen Frames loop.image.src = loop.frames[loop.frameNumber].src; }; } /** * Diese Methode startet eine ImageLoop-Animation. Sind die Frame-Bilder nicht vollständig * geladen, setzt sie stattdessen ein Flag, und die Animation wird * automatisch gestartet, sobald der Ladevorgang abgeschlossen ist */ ImageLoop.prototype.start = function( ) { if (this.timer != null) return; // Bereits gestartet // Ist der Ladevorgang noch nicht abgeschlossen, setzte ein Flag und warte if (!this.loaded) this.startOnLoad = true; else { // Bild über id holen, falls wir es nicht schon haben if (!this.image) this.image = document.getElementById(this.imageId); // Zeige das erste Frame sofort an this._displayNextFrame( ); // und setze einen Timer für die Anzeige der folgenden Frames this.timer = setInterval(this._displayNextFrame, this.frameInterval); } };
590 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 591 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-4: Bildanimationen (Fortsetzung) /** Halte eine ImageLoop-Animation an */ ImageLoop.prototype.stop = function( ) { if (this.timer) clearInterval(this.timer); this.timer = null; };
Zusätzlich zum Event-Handler onload, der in Beispiel 22-4 vorgestellt wurde, unterstützt das Image-Objekt zwei weitere Event-Handler. Der Event-Handler onerror wird aufgerufen, wenn während des Ladevorgangs der Bilder ein Fehler auftritt, z.B. wenn sich die angegebene URL auf fehlerhafte Bilddaten bezieht. Der Event-Handler onabort wird aufgerufen, wenn der Benutzer den Ladevorgang vorzeitig abbricht (z.B., indem er im Browser auf die Schaltfläche Stop klickt). Für ein Bild wird einer (und nur einer) dieser EventHandler aufgerufen. Zusätzlich hat jedes Image-Objekt eine complete-Eigenschaft. Während das Bild lädt, steht diese Eigenschaft auf false; sie ändert sich zu true, nachdem das Bild geladen wurde oder der Browser das Laden aufgegeben hat. Anders ausgedrückt, die Eigenschaft complete wird zu true, nachdem einer der drei möglichen Event-Handler aufgerufen wurde. Die anderen Eigenschaften des Image-Objekts spiegeln einfach die Attribute des HTML -Tags wider. Bei modernen Browsern sind diese Eigenschaften les- und schreibbar,
und Sie können JavaScript verwenden, um die Bildgröße dynamisch zu ändern, sodass der Browser das Bild auseinanderzieht oder zusammendrückt.
22.2 Grafiken mit CSS Cascading Style Sheets (CSS) werden in Kapitel 16 beschrieben, und Sie haben dort gelernt, wie Sie Code für CSS-Styles schreiben, um damit DHTML-Effekte zu erzielen. CSS kann auch einfache Grafiken erzeugen: Die Eigenschaft background-color »füllt« ein Rechteck mit einer Deckfarbe, und die Eigenschaft border zeichnet den Umriss eines Rechtecks. Zusätzlich können speziellere Rahmeneigenschaften, wie z.B. border-left und border-top, verwendet werden, um nur an einer Reckteckseite einen Rahmen zu zeichnen, wodurch horizontale und vertikale Linien entstehen. In Browsern, die Styles unterstützen, können diese Linien sogar gepunktet oder gestrichelt werden! Das ist zwar nichts Großartiges, aber wenn diese grundlegenden CSS-Rechteck- und Linien-Bausteine mit absoluter Positionierung verknüpft werden, können sie Diagramme ergeben wie die in Abbildung 22-1 und 22-2 gezeigten. Die anschließenden Abschnitte zeigen, wie diese Figuren erzeugt wurden.
22.2 Grafiken mit CSS |
591
clientseitiges JavaScript
22.1.6 Weitere Image-Eigenschaften
491-0.book Seite 592 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Abbildung 22-1: Ein mit CSS gestaltetes Balkendiagramm
Abbildung 22-2: Ein mit CSS gestalteter Baum
592 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 593 Mittwoch, 4. April 2007 9:55 09
e-bol.net
22.2.1 Balkendiagramme mit CSS Das Balkendiagramm in Abbildung 22-1 wurde mit der folgenden HTML-Datei erstellt:
clientseitiges JavaScript
function drawChart( ) { var chart = makeBarChart([1,2,4,8,16,32,64,128,256], 600, 300); var container = document.getElementById("chartContainer"); container.appendChild(chart); } y = 2n Beachte, dass jeder Balken doppelt so hoch wie der vorhergehende ist -- eine Eigenschaft exponentiellen Wachstums
Natürlich ist der interessante Code die Funktion makeBarChart( ), die in der Datei BarChart.js definiert und in Beispiel 22-5 aufgeführt ist. Beispiel 22-5: Balkendiagramme mit CSS zeichnen /** * BarChart.js: * Diese Datei definiert die Funktion makeBarChart( ), die ein Balkendiagramm erzeugt, mit dem * die Zahlen im data[]-Array dargestellt werden. Die Gesamtgröße des Diagramms wird * durch die optionalen Argumente width und height angegeben, die den * Platz für den Diagrammrahmen und den Abstand zwischen Rahmen und Inhalt einbeziehen. * Das optionale Argument barcolor gibt die Balkenfarbe an. Die Funktion gibt das * von ihr erzeugte -Element zurück, sodass der Benutzer das Diagramm weiter * ändern kann, z.B., indem er eine Randbreite festlegt. Der Aufrufer muss das zurückgegebene * Element wieder in das Dokument einfügen, um das Diagramm sichtbar zu machen. /** function makeBarChart(data, width, height, barcolor) { // Stelle die Standardwerte für die optionalen Argumente zu Verfügung if (!width) width = 500; if (!height) height = 350; if (!barcolor) barcolor = "blue"; // Die Argumente width und height geben die Gesamtgröße des // erzeugten Diagramms an. Davon müssen wir den Rahmen und den Abstand zwischen Rahmen // und Inhalt abziehen,
22.2 Grafiken mit CSS |
593
491-0.book Seite 594 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-5: Balkendiagramme mit CSS zeichnen (Fortsetzung) // um die Größe des zu erzeugenden Elements zu erhalten. width -= 24; // Ziehe 10px für das Padding ab und jeweils 2px für den linken und rechten // Rahmen height -= 14; // Ziehe 10px für Padding oben ab und jeweils 2px für den oberen und // unteren Rahmen // Erstelle jetzt das Element, in das das Diagramm aufgenommen wird. Beachten Sie, // dass wir das Diagramm relativ positionieren, damit die Kinder absolut positioniert // werden können und trotzdem im normalen Elementablauf erscheinen. var chart = document.createElement("div"); chart.style.position = "relative"; // Setze relative Positionierung chart.style.width = width + "px"; // Setze Diagrammbreite chart.style.height = height + "px"; // Setze Diagrammhöhe chart.style.border = "solid black 2px"; // Mache einen Rahmen chart.style.paddingLeft = "10px"; // Füge links Leerraum hinzu chart.style.paddingRight = "10px"; // und rechts ebenso chart.style.paddingTop = "10px"; // und oben chart.style.paddingBottom = "0px"; // aber nicht unten chart.style.backgroundColor = "white"; // Mache den Diagrammhintergrund weiß // Berechne die Breite jedes Balkens var barwidth = Math.floor(width/data.length); // Suche nach der größten Zahl in data[]. Beachte die smarte Verwendung von // Function.apply( ). var maxdata = Math.max.apply(this, data); // Der Skalierfaktor für das Diagramm: scale*data[i] ergibt die Höhe eines Balkens var scale = height/maxdata; // Durchlaufe das data-Array, und erzeuge für jedes Datum einen Balken for(var i = 0; i < data.length; i++) { var bar = document.createElement("div"); // Erzeuge div für Balken var barheight = data[i] * scale; // Berechne Balkenhöhe bar.style.position = "absolute"; // Setze Balkenposition und -größe bar.style.left = (barwidth*i+1+10)+"px"; // Füge Balkenrahmen und Diagrammpad hinzu bar.style.top = height-barheight+10+"px";// Füge Diagrammleerraum hinzu bar.style.width = (barwidth-2) + "px"; // -2 für den Balkenrahmen bar.style.height = (barheight-1) + "px"; // -1 für den oberen Balkenrahmen bar.style.border = "solid black 1px"; // Art des Balkenrahmens bar.style.backgroundColor = barcolor; // Balkenfarbe bar.style.fontSize = "0px"; // IE-Hilfskonstruktion chart.appendChild(bar); // Füge den Balken ins Diagramm ein } // Gib schließlich das Diagrammelement zurück, damit der Aufrufer es ändern kann return chart; }
Der Code für Beispiel 22-5 ist unkompliziert und recht verständlich. Er verwendet die in Kapitel 15 vorgestellten Techniken, um neue -Elemente zu erzeugen und sie zum Dokument hinzuzufügen. Zusätzlich verwendet er die in Kapitel 16 gezeigten Techniken,
594 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 595 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Beispiel 22-5 enthält ein bisschen elementare Mathematik zur Berechnung der Höhe jedes Balkens in Pixeln anhand der zu plottenden Datenwerte. Der Code, der die Position und Größe des Diagramms und der Balken festlegt, enthält außerdem eine Arithmetik, die die Rahmen und Abstände zwischen Rahmen und Inhalt berücksichtigt.
22.2.2 Eine CSSDrawing-Klasse Der Code in Beispiel 22-5 ist genau für eine Aufgabe gemacht: Er zeichnet Linien, und nichts anderes als Linien. Genauso ist es durchaus möglich, CSS zum Zeichnen allgemeinerer Diagramme zu verwenden (z.B. für den in Abbildung 22-2 dargestellten Baum), solange sie aus Boxen, horizontalen Linien und vertikalen Linien bestehen. Beispiel 22-6 ist eine CSSDrawing-Klasse, die eine einfache API zum Zeichnen von Boxen und Linien definiert, und Beispiel 22-7 enthält Code, der mit der CSSDrawing-Klasse die in Abbildung 22-2 gezeigten Figuren erzeugt. Beispiel 22-6: Die CSSDrawing-Klasse /** * Diese Konstruktorfunktion erzeugt ein div-Element, in das eine * CSS-basierte Figur gezeichnet werden kann. Instanzmethoden werden definiert, um * Linien und Boxen zu zeichnen und die Figur in das Dokument einzufügen. * * Der Konstruktor kann mit zwei verschiedenen Signaturen aufgerufen werden: * * new CSSDrawing(x, y, width, height, classname, id) * * In diesem Fall wird ein mit position:absolute und der * angegebenen Position und Größe erzeugt. * * Der Konstruktor kann auch nur mit einer Breite und Höhe aufgerufen werden: * * new CSSDrawing(width, height, classname, id) * * In diesem Fall hat das erzeugte die angegebene Breite und Höhe * und verwendet position:relative (was notwendig ist, damit die Kindelemente, * mit denen Linien und Boxen gezeichnet werden, absolut positioniert werden können). *
22.2 Grafiken mit CSS |
595
clientseitiges JavaScript
um CSS-Style-Eigenschaften an den von ihm erzeugten Elementen zu setzen. Hier wird kein Text oder anderer Inhalt verwendet; das Balkendiagramm ist einfach ein Bündel maßgeschneiderter Rechtecke, die in einem weiteren Rechteck positioniert sind. Die CSS-Attribute border und background-color machen die Rechtecke sichtbar. Ein wichtiger Codeteil setzt den Stil position:relative für das Balkengramm selbst, ohne dabei die Stile top und left zu setzen. Durch diese Festlegung kann das Diagramm im normalen Dokumentenfluss bleiben und gleichzeitig Kinder haben, die mit Bezug auf die linke obere Diagrammecke absolut positioniert sind. Wenn das Diagramm nicht auf relative (oder absolute) Positionierung gesetzt wird, stehen alle Balken am falschen Platz.
491-0.book Seite 596 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-6: Die CSSDrawing-Klasse (Fortsetzung) * In beiden Fällen sind die Argumente classname und id optional. Wenn sie angegeben sind, * werden sie als Wert der class- und id-Attribute des erzeugten * verwendet und lassen sich benutzen, um CSS-Styles wie z.B. Rahmen mit * der Figur zu assoziieren. */ function CSSDrawing(/* variable Argumente, siehe oben */) { // Erzeuge und speichere das -Element für die Zeichnung var d = this.div = document.createElement("div"); var next; // Finde heraus, ob wir vier oder zwei Zahlen haben, und lege die Größe und // Position des div entsprechend fest if (arguments.length >= 4 && typeof arguments[3] == "number") { d.style.position = "absolute"; d.style.left = arguments[0] + "px"; d.style.top = arguments[1] + "px"; d.style.width = arguments[2] + "px"; d.style.height = arguments[3] + "px"; next = 4; } else { d.style.position = "relative"; // Das ist wichtig d.style.width = arguments[0] + "px"; d.style.height = arguments[1] + "px"; next = 2; } // Setze class- und id-Attribute, sofern sie angegeben sind. if (arguments[next]) d.className = arguments[next]; if (arguments[next+1]) d.id = arguments[next+1]; } /** * Füge der Zeichnung eine Box hinzu. * * x, y, w, h: lege die Position und Größe der Box fest. * content: ein Text- oder HTML-String, der in der Box angezeigt wird * classname, id: optionale class- und id-Werte für die Box. Nützlich, um * Styles mit der Box zu assoziieren (Farbe, Umrandung usw.) * Rückgabewert: Das für die Anzeige der Box erzeugte -Element */ CSSDrawing.prototype.box = function(x, y, w, h, content, classname, id) { var d = document.createElement("div"); if (classname) d.className = classname; if (id) d.id = id; d.style.position = "absolute"; d.style.left = x + "px"; d.style.top = y + "px"; d.style.width = w + "px"; d.style.height = h + "px";
596 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 597 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-6: Die CSSDrawing-Klasse (Fortsetzung) d.innerHTML = content; this.div.appendChild(d); return d; };
clientseitiges JavaScript
/** * Füge der Zeichnung eine horizontale Linie hinzu. * * x, y, width: Gib die Startposition und Linienbreite an * classname, id: Optionale class- und id-Werte für die Box. Mindestens ein solcher Wert * muss vorhanden sein und einen Umrandungsstil angeben, der * für den Linienstil, die Linienfarbe und -breite verwendet wird. * Rückgabewert: Das für die Anzeige der Linie erzeugte -Element */ CSSDrawing.prototype.horizontal = function(x, y, width, classname, id) { var d = document.createElement("div"); if (classname) d.className = classname; if (id) d.id = id; d.style.position = "absolute"; d.style.left = x + "px"; d.style.top = y + "px"; d.style.width = width + "px"; d.style.height = 1 + "px"; d.style.borderLeftWidth = d.style.borderRightWidth = d.style.borderBottomWidth = "0px"; this.div.appendChild(d); return d; }; /** * Füge der Zeichnung eine vertikale Linie hinzu. * Für Einzelheiten siehe horizontal( ). */ CSSDrawing.prototype.vertical = function(x, y, height, classname, id) { var d = document.createElement("div"); if (classname) d.className = classname; if (id) d.id = id; d.style.position = "absolute"; d.style.left = x + "px"; d.style.top = y + "px"; d.style.width = 1 + "px"; d.style.height = height + "px"; d.style.borderRightWidth = d.style.borderBottomWidth = d.style.borderTopWidth = "0px"; this.div.appendChild(d); return d; }; /** Füge die Zeichnung als Kind des angegebenen Containers in das Dokument ein */ CSSDrawing.prototype.insert = function(container) { if (typeof container == "string") container = document.getElementById(container);
22.2 Grafiken mit CSS |
597
491-0.book Seite 598 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-6: Die CSSDrawing-Klasse (Fortsetzung) container.appendChild(this.div); } /** Füge die Zeichnung durch Ersetzen des angegebenen Elements in das Dokument ein */ CSSDrawing.prototype.replace = function(elt) { if (typeof elt == "string") elt = document.getElementById(elt); elt.parentNode.replaceChild(this.div, elt); }
Der Konstruktor CSSDrawing( ) erzeugt ein neues CSSDrawing-Objekt, das lediglich einen Wrapper um ein -Element darstellt. Die Instanzmethoden box( ), vertical( ) und horizontal( ) verwenden CSS, um Boxen bzw. vertikale und horizontale Linien zu zeichnen. Bei jeder Methode lässt sich die Position und Größe des zu zeichnenden Rahmens oder der Linie festlegen sowie eine Klasse und/oder eine ID für das erzeugte Rahmenoder Linienelement. Über die Klasse oder ID können CSS-Styles mit dem Element assoziiert und so Farben, Linienbreiten usw. angegeben werden. Die Erzeugung eines CSSDrawing-Objekts macht es noch nicht sichtbar. Verwenden Sie die Methoden insert( ) oder replace( ), um es dem Dokument hinzuzufügen. Beispiel 22-7 zeigt, wie die CSSDrawing-Klasse verwendet werden kann. Sowohl der JavaScript-Code in der Methode drawFigure( ) und das CSS-Stylesheet sind für die Figur entscheidend. Der Code definiert die Positionen und Größen der Rahmen und Linien, und das Stylesheet definiert die Farben und Linienbreiten. Beachten Sie, dass sich JavaScript und CSS verheddern und der Code in der Methode drawFigure( ) die Rahmenbreiten und Padding-Abstände miteinbeziehen muss, die im Stylesheet angegeben werden. Das ist ein Manko der von der CSSDrawing-Klasse definierten API. Beispiel 22-7: Eine Figur mit der CSSDrawing-Klasse zeichnen /* Styles für die Box mit der Abbildung */ .figure { border: solid black 2px; background-color: #eee;} /* Styles für Rasterlinien */ .grid { border: dotted black 1px; opacity: .1; } /* Styles für Boxen in der Abbildung */ .boxstyle { border: solid black 2px; background: #aaa; padding: 2px 10px 2px 10px; font: bold 12pt sans-serif; text-align: center; }
598 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 599 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-7: Eine Figur mit der CSSDrawing-Klasse zeichnen (Fortsetzung) /* Styles für die Linie, die die Boxen verbindet */ .boldline { border: solid black 2px; }
clientseitiges JavaScript
// Zeichne ein Raster im angegebenen Rechteck mit dx,dy als Linienabstand function drawGrid(drawing, x, y, w, h, dx, dy) { for(var x0 = x; x0 < x +w; x0 += dx) drawing.vertical(x0, y, h, "grid"); for(var y0 = y; y0 < y + h; y0 += dy) drawing.horizontal(x, y0, w, "grid"); } function drawFigure( ) { // Erzeuge eine neue Abbildung var figure = new CSSDrawing(500, 200, "figure"); // Füge der Zeichnung ein Raster hinzu drawGrid(figure, 0, 0, 500, 200, 25, 25); // Zeichne vier Boxen in der Figur figure.box(200, 50, 75, 25, "Life", "boxstyle"); figure.box(50, 125, 75, 25, "Archaea", "boxstyle"); figure.box(200, 125, 75, 25, "Bacteria", "boxstyle"); figure.box(350, 125, 75, 25, "Eukaryota", "boxstyle");
// // // //
obere Box Reihe von 3 ...Boxen unter ...der oberen
// Diese Linie wird vom unteren Mittelpunkt der oberen "Life"-Box gezeichnet. // Die y-Startposition dieser Linie ist 50+25+2+2+2+2 oder // y + Höhe + oberer Rahmen + oberes Padding + unteres Padding + unterer Rahmen // NB: Diese Berechnung benötigt Informationen sowohl aus dem Code als auch // aus dem Stylesheet, was nicht ideal ist. figure.vertical(250, 83, 20, "boldline"); figure.horizontal(100, 103, 300, "boldline"); figure.vertical(100, 103, 22, "boldline"); figure.vertical(250, 103, 22, "boldline"); figure.vertical(400, 103, 22, "boldline");
// // // //
Linie über den 3 unteren Boxen verbinde mit "archaea" verbinde mit "bacteria" verbinde mit "eukaryota"
// Füge jetzt die Figur in das Dokument ein, und ersetze den Platzhalter figure.replace("placeholder"); }
22.2 Grafiken mit CSS |
599
491-0.book Seite 600 Mittwoch, 4. April 2007 9:55 09
e-bol.net
22.3 SVG: Scalable Vector Graphics SVG ist eine XML-Grammatik für Grafiken. Der Begriff »Vektor« im Namen zeigt bereits, dass diese Grafiken grundsätzlich anders aufgebaut sind als Rasterbildformate (wie z.B. GIF, JPEG und PNG), die eine Matrix mit Pixelwerten angeben. Vielmehr ist eine SVG»Abbildung« eine genaue, auflösungsunabhängige (und dadurch »skalierbare«) Beschreibung der notwendigen Schritte zum Zeichnen der gewünschten Grafik. Hier sehen Sie, wie ein einfaches SVG-Bild im Textformat aussieht:
Abbildung 22-3 zeigt, wie die SVG-Datei aussieht, wenn sie grafisch wiedergegeben wird.
Abbildung 22-3: Eine einfache SVG-Grafik
600 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 601 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Als dieses Buch geschrieben wurde, war Firefox 1.5 der einzige der Mainstream-Browser, der von Haus aus SVG-Grafiken unterstützte. Unter diesem Browser können Sie eine SVG-Grafik ganz einfach anzeigen, indem Sie die URL des anzuzeigenden Bildes eingeben. Sinnvoller ist es, SVG-Grafiken direkt in eine XHTML-Datei einzubetten, wie in dieser einfachen Datei: Das ist ein rotes Quadrat: Das ist ein blauer Kreis:
Abbildung 22-4 zeigt, wie Firefox 1.5 dieses XHTML-Dokument wiedergibt.
Abbildung 22-4: SVG-Grafiken in einem XHTML-Dokument
22.3 SVG: Scalable Vector Graphics |
601
clientseitiges JavaScript
SVG hat eine umfrangreiche und ziemlich komplizierte Grammatik. Zusätzlich zu Bausteinen für das Zeichnen einfacher Formen unterstützt es beliebige Kurven, Text und Animation. SVG-Grafiken können sogar JavaScript-Skripten und CSS-Stylesheets beinhalten und so Informationen zum Verhalten und zur Darstellung aufnehmen. Dieser Abschnitt zeigt, wie clientseitiger JavaScript-Code (der nicht in SVG, sondern in HTML eingebettet ist) mit Hilfe von SVG dynamisch Grafiken zeichnen kann. Er enthält Beispiele mit SVG-Zeichnungen, kann aber die Möglichkeiten mit SVG nur in sehr begrenztem Umfang darstellen. Vollständige Erläuterungen zu SVG sind in der umfangreichen, aber recht gut lesbaren Spezifikation aufgeführt. Diese wird vom W3C unter http://www.w3.org/TR/SVG/ gepflegt. Beachten Sie, dass diese Spezifikation ein vollständiges Document Object Model für SVG-Dokumente enthält. In diesem Abschnitt werden SVG-Grafiken mit dem standardisierten XML DOM bearbeitet, und das SVG DOM wird überhaupt nicht verwendet.
491-0.book Seite 602 Mittwoch, 4. April 2007 9:55 09
e-bol.net SVG-Abbildungen können auch mit einem -Tag in ein HTML-Dokument eingebettet werden, sodass sie mit einem Plug-in angezeigt werden können. Adobe hat ein kostenloses (aber nicht Open Source) SVG-Viewer-Plug-in, das unter den üblichen Browsern und Betriebssystemen funktioniert. Sie finden es, indem Sie den Links unter http://www. adobe.com/svg folgen. Da SVG eine XML-Grammatik hat, lässt sich beim Zeichnen von SVG-Grafiken einfach das DOM verwenden, um die passenden XML-Elemente zu erzeugen. Beispiel 22-8 ist eine Auflistung einer pieChart( )-Funktion, die die SVG-Elemente für ein Tortendiagramm erzeugt, wie es in Abbildung 22-5 dargestellt ist. (Die anderen in diesem Kapitel untersuchten Vektorgrafik-Technologien werden ebenfalls zum Zeichnen von Tortendiagrammen verwendet, die diesem sehr ähnlich sind.)
Abbildung 22-5: Ein mit JavaScript gebautes Tortendiagramm
602 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 603 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-8: Ein Tortendiagramm mit JavaScript und SVG zeichnen
// Zähle die Datenwerte zusammen, damit wir wissen, wie groß die Torte ist var total = 0; for(var i = 0; i < data.length; i++) total += data[i]; // Finde jetzt heraus, wie groß jedes Tortenstück ist. Winkel im Bogenmaß. var angles = [] for(var i = 0; i < data.length; i++) angles[i] = data[i]/total*Math.PI*2; // Durchlaufe alle Tortenstücke. startangle = 0; for(var i = 0; i < data.length; i++) { // Hier endet das Tortenstück var endangle = startangle + angles[i]; // Berechne die zwei Punkte, in denen das Tortenstück den Kreis schneidet. // Diese Formeln sind so gewählt, dass ein Winkel von 0 auf der 12-Uhr-Position steht // und positive Winkel im Uhrzeigersinn abgebildet werden. var x1 = cx + r * Math.sin(startangle); var y1 = cy - r * Math.cos(startangle); var x2 = cx + r * Math.sin(endangle); var y2 = cy - r * Math.cos(endangle); // Das ist ein Flag für Winkel, die größer als ein Halbkreis sind var big = 0; if (endangle - startangle > Math.PI) big = 1; // Wir beschreiben ein Tortenstück mit einem -Element // Sie sehen, dass wir das mit createElementNS( ) erstellen var path = document.createElementNS(SVG.ns, "path"); // Dieser String enthält die Pfaddaten var d = "M " + cx + "," + cy + // Beginne am Kreismittelpunkt " L " + x1 + "," + y1 + // Zeichne eine Linie nach (x1,y1) " A " + r + "," + r + // Zeichne einen Kreisbogen mit dem Radius r
22.3 SVG: Scalable Vector Graphics |
603
clientseitiges JavaScript
/** * Zeichne ein Tortendiagramm in ein -Element. * Argumente: * Canvas: das SVG-Element (oder die id dieses Elements), in das gezeichnet wird * Daten: ein Array mit darzustellenden Zahlen, eine für jedes Tortenstück * cx, cy, r: der Mittelpunkt und Radius der Torte * Farben: ein Array mit HTML-Farbstrings, einer für jedes Tortenstück * Beschriftungen: ein Array mit Beschriftungen, die in der Legende angezeigt werden, eine * für jedes Tortenstück lx, ly: die linke obere Ecke der Diagrammlegende */ function pieChart(canvas, data, cx, cy, r, colors, labels, lx, ly) { // Suche nach dem Canvas, wenn er nicht durch ein Element, sondern über eine id angegeben // wird if (typeof canvas == "string") canvas = document.getElementById(canvas);
491-0.book Seite 604 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-8: Ein Tortendiagramm mit JavaScript und SVG zeichnen (Fortsetzung) " 0 " + big + " 1 " + // Kreisbogendaten ... x2 + "," + y2 + // ein Kreisbogen bis nach (x2,y2) " Z"; // Schließe den Pfad durch eine Verbindung zu (cx,cy) // Das ist ein XML-Element, sodass alle Attribute mit // setAttribute( ) gesetzt werden müssen. Wir können nicht einfach JavaScript// Eigenschaften verwenden path.setAttribute("d", d); // Setze diesen Pfad path.setAttribute("fill", colors[i]); // Setze Farbe des Tortenstücks path.setAttribute("stroke", "black"); // Zeichne einen schwarzen Umriss für das // Tortenstück, path.setAttribute("stroke-width", "2"); // der 2 Einheiten breit ist canvas.appendChild(path); // Setze das Tortenstück auf den Canvas // Das nächste Tortenstück beginnt dort, wo dieses aufhört startangle = endangle; // Zeichne jetzt ein kleines, passendes Quadrat für die Legende var icon = document.createElementNS(SVG.ns, "rect"); icon.setAttribute("x", lx); // Positioniere das Quadrat icon.setAttribute("y", ly + 30*i); icon.setAttribute("width", 20); // Lege die Quadratgröße fest icon.setAttribute("height", 20); icon.setAttribute("fill", colors[i]); // Gleiche Füllfarbe wie das Tortenstück icon.setAttribute("stroke", "black"); // und die gleiche Umrissfarbe. icon.setAttribute("stroke-width", "2"); canvas.appendChild(icon); // Setze es auf den Canvas // Füge eine Beschriftung rechts vom Rechteck ein var label = document.createElementNS(SVG.ns, "text"); label.setAttribute("x", lx + 30); // Positioniere den Text label.setAttribute("y", ly + 30*i + 18); // Text-Style-Attribute können auch mit CSS gesetzt werden label.setAttribute("font-family", "sans-serif"); label.setAttribute("font-size", "16"); // Füge einen DOM-Textknoten zum -Element hinzu label.appendChild(document.createTextNode(labels[i])); canvas.appendChild(label); // Setze den Text auf den Canvas }
Der Code in Beispiel 22-8 ist ziemlich unkompliziert. Etwas Mathematik ist nötig, um die Daten in grafisch darstellbare Tortenstückwinkel zu konvertieren. Der Großteil des Beispiels ist allerdings DOM-Code, der SVG-Elemente erzeugt und Attribute für diese Elemente setzt. Da SVG einen Namensraum verwendet, wird statt createElement( ) createElementNS( ) verwendet. Die Namensraumkonstante SVG.ns wird später in Beispiel 22-9 definiert. Der undurchsichtigste Teil dieses Beispiels ist der Code, der die eigentlichen Tortenstücke zeichnet. Das zur Darstellung der einzelnen Tortenstücke verwendete Tag ist . Dieses SVG-Element beschreibt beliebige Formen, die aus Linien und Kurven
604 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 605 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Der Code in Beispiel 22-8 verwendet die Konstante SVG.ns, um den SVG-Namensraum zu beschreiben. Diese Konstante und mehrere SVG-Utility-Funktionen werden in einer separaten SVG.js-Datei definiert, die in Beispiel 22-9 aufgelistet ist. Beispiel 22-9: SVG-Utility-Code // Erzeuge einen Namensraum für unsere SVG-bezogenen Utilities var SVG = {}; // Das sind Namensraum-URLs, die mit SVG zu tun haben SVG.ns = "http://www.w3.org/2000/svg"; SVG.xlinkns = "http://www.w3.org/1999/xlink"; // Erzeuge ein leeres -Element, und gib es aus. // Beachte, dass das Element nicht in das Dokument eingefügt wird. // Beachte, dass wir sowohl die Größe des Bilds in Pixeln angeben können als auch // sein internes Koordinatensystem. SVG.makeCanvas = function(id, pixelWidth, pixelHeight, userWidth, userHeight) { var svg = document.createElementNS(SVG.ns, "svg:svg"); svg.setAttribute("id", id); // Wie groß ist der Canvas in Pixeln? svg.setAttribute("width", pixelWidth); svg.setAttribute("height", pixelHeight); // Setze die Koordinaten, die für die Zeichnungen auf dem Canvas verwendet werden svg.setAttribute("viewBox", "0 0 " + userWidth + " " + userHeight); // Definiere den XLink-Namensraum, den SVG verwendet svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", SVG.xlinkns); return svg; }; // Serialisiere das Canvas-Element in einen String, und verwende // in einer data:-URL zur Anzeige in einem -Tag. Dadurch // unter Browsern, die das data:-URL-Schema unterstützen und ein // Plug-in installiert haben. SVG.makeDataURL = function(canvas) { // Wir geben uns nicht mit der IE-Serialisierungstechnik ab, // data:-URLs nicht unterstützt
ihn funktioniert SVG SVG-
da sie
22.3 SVG: Scalable Vector Graphics |
605
clientseitiges JavaScript
bestehen. Die Formbeschreibung wird durch das Attribut d des -Tags angegeben. Der Wert dieses Attributs verwendet eine kompakte, aus Buchstabencode und Zahlen bestehende Grammatik, die die Koordinaten, Winkel und andere Werte festlegt. Beispielsweise bedeutet der Buchstabe M »move to (gehe zu)«; auf ihn folgen die X- und Y-Koordinaten. Der Buchstabe L bedeutet »line to« und zeichnet eine Linie vom momentanen Punkt zu den Koordinaten, die auf den Buchstaben folgen. Dieses Beispiel verwendet außerdem den Buchstaben A, um einen Kreisbogen zu zeichnen. Auf den Buchstaben folgen sieben Zahlen, die den Kreisbogen beschreiben. Die genauen Einzelheiten sind hier nicht von Bedeutung, aber Sie können sie in der Spezifikation unter http://www. w3.org/TR/SVG/ nachlesen.
491-0.book Seite 606 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-9: SVG-Utility-Code (Fortsetzung) var text = (new XMLSerializer( )).serializeToString(canvas); var encodedText = encodeURIComponent(text); return "data:image/svg+xml," + encodedText; }; // Erzeuge ein , um mit einer data:-URL eine SVG-Zeichnung anzuzeigen SVG.makeObjectTag = function(canvas, width, height) { var object = document.createElement("object"); // Erzeuge HTML--Tag object.width = width; // Setze die Größe des Objekts object.height = height; object.data = SVG.makeDataURL(canvas); // SVG-Bild als data:-URL object.type = "image/svg+xml" // SVG-MIME-Typ return object; }
Die wichtigste Utility-Funktion in diesem Beispiel ist SVG.makeCanvas( ). Sie verwendet DOM-Methoden zur Erzeugung eines neuen -Elements, mit dem dann SVG-Grafiken gezeichnet werden können. Mit makeCanvas( ) kann sowohl die Größe (in Pixeln) angegeben werden, in der die SVG-Grafik wiedergeben wird, als auch die Größe des internen Koordinatensystems (oder »user space«), das die Zeichnung verwendet. (Beispiel: Eine Zeichnung mit 1000 × 1000 als user space wird als Quadrat mit 250 × 250 Pixeln wiedergegeben. Damit entspricht jede Einheit user space einem Viertelpixel). makeCanvas( ) erzeugt ein -Tag und gibt es zurück, fügt es aber nicht in das Dokument ein. Das muss der aufrufende Code machen. Die zwei anderen Utility-Methoden in Beispiel 22-9 werden unter Browsern verwendet, die SVG-Grafiken über ein Plug-in anzeigen. SVG.makeDataURL( ) serialisiert den XMLText eines -Tags und codiert ihn als eine data:-URL. SVG.makeObjectTag( ) geht noch einen Schritt weiter und erzeugt ein HTML-Tag zum Einbetten einer SVGGrafik und ruft dann SVG.makeDataURL( ) auf, um das data-Attribut dieses Tags zu setzen. Ebenso wie SVG.makeCanvas( ) gibt die Methode SVG.makeObjectTag( ) das -Tag zurück. Sie fügt es aber nicht ins Dokument ein. SVG.makeObjectTag( ) funktioniert beispielsweise in Browsern wie Firefox 1.0, die das data:-URL-Schema und DOM-Methoden unterstützen, namensraumkompatible Methoden wie z.B. document.createElementNS( ) unterstützen und in denen ein SVG-Plug-in installiert ist. Unter IE funktioniert das nicht, weil dieser Browser die data:-URLs und createElementNS( ) nicht unterstützt. Unter IE bietet es sich als Alternative an, das SVG-
Dokument über Stringmanipulation zu konstruieren und nicht über den Aufruf von DOM-Methoden. Anstelle einer data:-URL kann die Grafik dann mit einer javascript:URL codiert werden. Ich schließe diese Besprechung der skriptgesteuerten SVG-Grafiken mit der HTML-Datei ab, die die Funktion pieChart( ) aus Beispiel 22-8 und die SVG-Utility-Methoden in Bei-
606 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 607 Mittwoch, 4. April 2007 9:55 09
e-bol.net spiel 22-9 verbindet. Der folgende Code erzeugt einen SVG-Canvas, zeichnet auf ihm und fügt ihn dann zweimal in das Dokument ein: einmal direkt und einmal über ein -Tag:
clientseitiges JavaScript
function init( ) { // Erzeuge ein -Tag mit 600x400 Auflösung, wiedergegeben // mit 300x200 Pixeln var canvas = SVG.makeCanvas("canvas", 300, 200, 600, 400); pieChart(canvas, [12, 23, 34, 45], 200, 200, 150, // Canvas, Daten, Größe ["red", "blue", "yellow", "green"], // Farbe der Tortenstücke ["Nord","Süd","Ost","West"], 400, 100); // Legende // Füge die Grafik direkt in das Dokument ein: document.body.appendChild(canvas); // Bette sie mit einem -Tag ein var object = SVG.makeObjectTag(canvas, 300, 200); document.body.appendChild(object); } // Lasse diese Funktion laufen, sobald das Dokument vollständig geladen ist window.onload = init;
22.4 VML: Vector Markup Language VML ist die Microsoft-Antwort auf SVG. Wie SVG ist VML eine XML-Grammatik zur Beschreibung von Zeichnungen. VML ähnelt SVG in vielen Gesichtspunkten. VML ist zwar nicht ganz so umfangreich, hat aber vollständige Zeichenfähigkeiten und steht unter IE 5.5 und höher von Haus aus zur Verfügung. Microsoft (und einige andere Partnerunternehmen) reichten VML beim W3C als Normentwurf ein, aber dieses Bestreben verlief im Sand. Die beste Dokumentation für VML ist Microsofts Entwurf, der immer noch auf der W3C-Webseite unter http://www.w3.org/TR/NOTE-VML zu haben ist. Beachten Sie, dass das Dokument zwar auf der W3C-Seite steht, aber nie standardisiert wurde und die Implementierung unter IE Microsoft gehört. VML ist eine leistungsfähige Technologie, die nie richtig Fuß gefasst hat. Da sie nicht weit verbreitet ist,2 wurde sie anscheinend nie sorgfältig dokumentiert. Die Microsofteigenen Webseiten verweisen normalerweise auf Microsofts W3C-Entwurf als maßgebende Dokumentationsquelle. Da dieses Dokument ein vorläufiger Entwurf war, war es leider nie Gegenstand der sorgfältigen Überprüfung des Standardisierungsverfahrens und ist in Teilen immer noch unvollständig oder verwirrend. Beim Arbeiten mit VML müssen 2 Google Maps (http://local.google.com) ist die einzige mir bekannte berühmtere Site, die VML verwendet.
22.4 VML: Vector Markup Language |
607
491-0.book Seite 608 Mittwoch, 4. April 2007 9:55 09
e-bol.net Sie eventuell mit der IE-Implementierung experimentieren, um die Zeichnungen zu erzeugen, die Sie wollen. Das ist ein ziemlich geringfügiger Nachteil, wenn Sie bedenken, dass VML eine leistungsstarke clientseitige Vektorzeichnungsengine ist und in den Webbrowser eingebettet ist, der immer noch den Markt dominiert. VML ist ein XML-Dialekt und unterscheidet sich von HTML. Allerdings unterstützt IE keine echten XHTML-Dokumente, und seine DOM-Implementierung unterstützt keine namensraumkompatiblen Funktionen, wie z.B. document.createElementNS( ). IE bringt VML zum Laufen, indem ein HTML-Behavior (eine weitere IE-spezifische Erweiterung) zum Umgang mit Tags im VML-Namensraum verwendet wird. Alle HTML-Dateien mit VML müssen den Namensraum zuerst wie folgt deklarieren:
Alternativ kann diese Namensraumdeklaration auf eine IE-spezifische (und nicht standardisierte) Weise wie folgt erreicht werden:
Sie müssen dann mit diesem nicht standardkonformen Teil von CSS angeben, wie mit Tags in diesem Namensraum umgegangen werden soll: v\:* { behavior: url(#default#VML); }
Sind diese Teile vorhanden, können VML-Zeichnungen frei mit HTML kombiniert werden, wie im folgenden Code gezeigt wird, der ein sehr ähnliches Ergebnis wie die SVGGrafik in Abbildung 22-4 produziert: v\:* { behavior: url(#default#VML); } Das ist ein rotes Quadrat: Das ist ein blauer Kreis:
Dieses Kapitel konzentriert sich allerdings auf die Verwendung von clientseitigem JavaScript zum dynamischen Zeichnen von Grafiken. Beispiel 22-10 zeigt, wie VML ein Tortendiagramm erzeugt. Dieses Beispiel und das Beispiel des SVG-Tortendiagramms sind sich sehr ähnlich, außer dass SVG-Zeichenfunktionen durch VML-Funktionen ersetzt werden. Aus Gründen der Einfachheit kombiniert dieses Beispiel die Funktionen makeVMLCanvas( ) und pieChart( ) mit dem Code, der diese Funktionen zur Erzeugung des Diagramms aufruft. Die Codeausgabe wird hier nicht gezeigt: Sie hat große Ähnlichkeit mit dem SVG-Tortendiagramm in Abbildung 22-5. Beispiel 22-10: Ein Tortendiagramm mit JavaScript und VML zeichnen
608 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 609 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-10: Ein Tortendiagramm mit JavaScript und VML zeichnen (Fortsetzung)
// Beginne mit einem weißen Rechteck mit dünnem schwarzen Umriss. var rect = document.createElement("v:rect"); rect.style.width = pixelWidth + "px"; rect.style.height = pixelHeight + "px"; vml.appendChild(rect); return vml; } /* Zeichne ein Tortendiagramm auf einen VML-Canvas */ function pieChart(canvas, data, cx, cy, r, colors, labels, lx, ly) { // Hole das Canvas-Element, sofern es per id angegeben wurde if (typeof canvas == "string") canvas = document.getElementById(canvas); // Zähle die Datenwerte zusammen var total = 0; for(var i = 0; i < data.length; i++) total += data[i]; // Bestimme die Größe (in Grad) jedes Tortenstücks var angles = [] for(var i = 0; i < data.length; i++) angles[i] = data[i]/total*360; // Durchlaufe alle Tortenstücke // VML misst Winkel in Grad/65535, bewegt sich // gegen den Uhrzeigersinn und beginnt an der 3-Uhr-Position startangle = 90; // Beginne an der 12-Uhr-Position. for(var i = 0; i < data.length; i++) { // Winkel anpassen, damit unsere Torte im Uhrzeigersinn ab 12 Uhr läuft. var sa = Math.round(startangle * 65535); var a = -Math.round(angles[i] * 65536); // Erzeuge ein VML-Form-Element var wedge = document.createElement("v:shape"); // VML beschreibt die Form eines Pfads ähnlich wie SVG var path = "M " + cx + " " + cy + // Gehe zu (cx,cy) " AE " + cx + " " + cy + " " + // Kreisbogen mit Mittelpunkt auf (cx,cy) r + " " + r + " " + // Horizontale und vertikale Radii
22.4 VML: Vector Markup Language |
609
clientseitiges JavaScript
v\:* { behavior: url(#default#VML); } */ * Erzeuge ein VML--Element, in dem mit VML gezeichnet werden kann, und gib es aus. * Beachte, dass das zurückgegebene Element noch nicht ins Dokument eingefügt wurde. */ function makeVMLCanvas(id, pixelWidth, pixelHeight) { var vml = document.createElement("v:group"); vml.setAttribute("id", id); vml.style.width = pixelWidth + "px"; vml.style.height = pixelHeight + "px"; vml.setAttribute("coordsize", pixelWidth + " " + pixelHeight);
491-0.book Seite 610 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-10: Ein Tortendiagramm mit JavaScript und VML zeichnen (Fortsetzung) sa + " " + a + " X E";
// Startwinkel und Gesamtwinkel // Schließe den Pfad durch eine Verbindung zum // Mittelpunkt wedge.setAttribute("path", path); // Setze Form des Tortenstücks wedge.setAttribute("fillcolor", colors[i]); // Setze Farbe des Tortenstücks wedge.setAttribute("strokeweight", "2px"); // Umrissbreite // Positioniere das Tortenstück mit CSS-Styles. Die Koordinaten des // Pfads werden relativ zu dieser Größe interpretiert. Also geben wir jeder // Form die gleiche Größe wie dem Canvas selbst. wedge.style.position = "absolute"; wedge.style.width = canvas.style.width; wedge.style.height = canvas.style.height; // Füge die Tortenstücke zum Canvas hinzu canvas.appendChild(wedge); // Nächstes Tortenstück beginnt dort, wo dieses aufhört startangle -= angles[i]; // Erzeuge ein VML-Element für die Legende var icon = document.createElement("v:rect"); icon.style.left = lx + "px"; // CSS-Positionierung icon.style.top = (ly+i*30) + "px"; icon.style.width = "20px"; // CSS-Größe icon.style.height = "20px"; icon.setAttribute("fillcolor", colors[i]); // Gleiche Füllfarbe wie das Tortenstück icon.setAttribute("stroke", "black"); // Umrissfarbe icon.setAttribute("strokeweight", "2"); // Umrissbreite canvas.appendChild(icon); // Setze es auf den Canvas // VML hat fortgeschrittene Textfähigkeiten, aber der Großteil des Texts ist einfach // HTML wird direkt auf den VML-Canvas gesetzt, und zwar // mit Canvas-Koordinaten var label = document.createElement("div"); // für den Text label.appendChild(document.createTextNode(labels[i])); // die Textlabel.style.position = "absolute"; // Position mit CSS label.style.left = (lx + 30) + "px"; label.style.top = (ly + 30*i + 5) + "px"; label.style.fontFamily = "sans-serif"; // Text-Styles label.style.fontSize = "16px"; canvas.appendChild(label); // Setze den Text auf den Canvas } } function init( ) { var canvas = makeVMLCanvas("canvas", 600, 400); document.body.appendChild(canvas); pieChart(canvas, [12, 23, 34, 45], 200, 200, 150, ["red", "blue", "yellow", "green"], ["Nord", "Süd", "Ost", "West"],
610 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 611 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-10: Ein Tortendiagramm mit JavaScript und VML zeichnen (Fortsetzung)
clientseitiges JavaScript
400, 100); }
22.5 Grafiken auf einem Die nächste Station auf unserer Tour der Vektorgrafik-Technologien auf der Clientseite ist das -Tag. Dieses nicht standardkonforme HTML-Element wurde speziell für clientseitige Vektorgrafiken entwickelt. Es hat keine eigene Darstellung, sondern stellt eine Zeichnungs-API für clientseitiges JavaScript zur Verfügung, damit Skripten beliebig auf einen Canvas zeichnen können. Das -Tag wurde von Apple unter dem Webbrowser Safari 1.3 eingeführt. (Der Grund für diese extreme Erweiterung von HTML liegt darin, dass die HTML-Wiedergabefähigkeit von Safari auch von der Dashboard-Komponente des Mac OS X-Desktops verwendet wird und Apple nach einer Möglichkeit suchte, skriptgesteuerte Grafiken in Dashboard zu unterstützen). Firefox 1.5 und Opera 9 sind dem Beispiel von Safari gefolgt. Beide unterstützen das -Tag. Sie können das -Tag sogar unter IE mit Open Source-JavaScriptCode (ursprünglich von Google) verwenden, der Canvas-Kompatibilität auf der Grundlage der VML-Unterstützung in IE herstellt (siehe http://excanvas.sourceforge.net). Der Prozess zur Standardisierung des -Tags läuft dank eines informellen Zusammenschlusses von Webbrowser-Herstellern, und eine vorläufige Spezifikation steht unter http://www.whatwg.org/specs/web-apps/current-work. Ein wichtiger Unterschied zwischen dem -Tag und SVG und VML ist, dass eine auf JavaScript aufbauende Zeichnungs-API hat, während SVG und VML eine Zeichnung anhand eines XML-Dokuments beschreiben. Diese zwei Vorgehensweisen sind in der Funktion äquivalent: Die eine kann durch die andere simuliert werden. An der Oberfläche sind sie jedoch ziemlich unterschiedlich, und jede hat ihre Stärken und Schwächen. Beispielsweise kann eine SVG-Zeichnung einfach bearbeitet werden, indem Elemente aus ihrer Beschreibung gelöscht werden. Um ein Element aus der gleichen Grafik in einem -Tag zu entfernen, muss man die Zeichnung oft löschen und von Grund auf neu zeichnen. Da die Canvas-Zeichnungs-API auf JavaScript basiert und recht kompakt ist (was für die SVG- und VML-Grammatiken nicht zutrifft), wird sie in diesem Buch dokumentiert. Vergleichen Sie Canvas, CanvasRenderingContext2D und dazugehörige Einträge in Teil IV. Der Großteil der Canvas-Zeichnungs-API wird nicht auf dem -Element selbst definiert, sondern über ein »drawing context«-Objekt, das über die Methode getContext( ) des
22.5 Grafiken auf einem |
611
491-0.book Seite 612 Mittwoch, 4. April 2007 9:55 09
e-bol.net Canvas verfügbar ist.3 Dieses Skript zeichnet ein kleines, rotes Quadrat und einen blauen Kreis und ist typisch für das Zeichnen auf einem Canvas: window.onload = function( ) { // Zeichne, wenn das Dokument lädt var canvas = document.getElementById("square"); // Hole das Canvas-Element var context = canvas.getContext("2d"); // Hole den 2D-Zeichnungskontext context.fillStyle = "#f00"; // Setze Füllfarbe auf Rot context.fillRect(0,0,10,10); // Fülle ein Rechteck canvas = document.getElementById("circle"); // Neues Canvas-Element context = canvas.getContext("2d"); // Hole seinen Inhalt context.fillStyle = "#00f"; // Setze Füllfarbe auf Blau context.beginPath( ); // Beginne mit einer Form // Füge einen vollen Kreis mit Radius 5 und Mittelpunkt (5,5) zur Form hinzu context.arc(5, 5, 5, 0, 2*Math.PI, true); context.fill( ); // Fülle die Form } Das ist ein rotes Quadrat: . Das ist ein blauer Kreis: .
In den vorherigen Abschnitten haben Sie gesehen, dass SVG und VML komplizierte Formen als »Pfade« aus Linien und Kurven beschreiben, die gefüllt oder als Umrisse gezeichnet werden können. Die Canvas-API verwendet ebenfalls das Pfad-Konzept. Anstatt einen Pfad als String von Buchstaben und Zahlen zu beschreiben, wird der Pfad hier aber durch eine Abfolge von Methodenaufrufen definiert, wie beispielsweise die Aufrufe beginPath( ) und arc( ) in unserem Beispiel. Nach der Definition eines Pfads führen andere Methoden, wie z.B. fill( ), Operationen an ihm durch. Verschiedene Eigenschaften des Zeichnungskontexts, wie zum Beispiel fillStyle, geben an, wie diese Operationen durchzuführen sind. Ein Grund für die Kompaktheit der Canvas-API liegt in der fehlenden Unterstützung zum Zeichnen von Text. Um Text in eine -Grafik einzubauen, müssen Sie ihn entweder selbst zeichnen, ihn mit Bitmap-Bildern einbauen oder HTML-Text mittels CSS-Positionierung über legen. Beispiel 22-11 zeigt, wie Tortendiagramme mit einem Canvas gezeichnet werden. Ein großer Teil dieses Codes in diesem Beispiel ist Ihnen aus den SVG- und VML-Beispielen geläufig. Der neue Code im Beispiel ist die Canvas-API. Sie können diese Methoden in Teil IV nachschlagen. 3 Die Methode braucht ein einziges Argument, das der String »2d« sein muss, und gibt einen Zeichnungskontext zurück, der eine zweidimensionale API implementiert. Falls das -Tag in der Zukunft 3D-Zeichnungen unterstützt, wird die Methode getContext( ) voraussichtlich die Übergabe des Strings »3d« erlauben.
612 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 613 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-11: Ein Tortendiagramm auf ein -Tag zeichnen
clientseitiges JavaScript
// Erzeuge ein neues Canvas-Tag mit der angegebenen id und Größe, und gib es zurück. // Beachte, dass diese Methode den Canvas noch nicht in das Dokument einfügt function makeCanvas(id, width, height) { var canvas = document.createElement("canvas"); canvas.id = id; canvas.width = width; canvas.height = height; return canvas; } /** * Zeichne ein Tortendiagramm auf den per Element oder id angegebenen Canvas. * Daten: ein Array mit darzustellenden Zahlen, eine für jedes Tortenstück * Das Tortendiagramm hat seinen Mittelpunkt in (cx, cy) und den Radius r. * Die Farben der Tortenstücke sind HTML-Farbstrings im colors[]-array. * Eine Legende erscheint bei (lx,ly), um die Beschriftungen mit den labels[] zu assoziieren * Array mit allen Farben. */ function pieChart(canvas, data, cx, cy, r, colors, labels, lx, ly) { // Hole den Canvas, sofern per id angegeben if (typeof canvas == "string") canvas = document.getElementById(canvas); // Wir zeichnen mit dem Zeichnungskontext des Canvas var g = canvas.getContext("2d"); // Alle von uns gezeichneten Linien sind 2 Pixel breit und schwarz g.lineWidth = 2; g.strokeStyle = "black"; // Summiere die Datenwerte var total = 0; for(var i = 0; i < data.length; i++) total += data[i]; // Berechne den Winkel (im Bogenmaß) für jedes Tortenstück var angles = [] for(var i = 0; i < data.length; i++) angles[i] = data[i]/total*Math.PI*2; // Durchlaufe jetzt alle Tortenstücke startangle = -Math.PI/2; // Beginne nicht bei 3, sondern bei 12 Uhr for(var i = 0; i < data.length; i++) { // Das ist der Winkel, bei dem das Tortenstück endet var endangle = startangle + angles[i]; // Zeichne ein Tortenstück g.beginPath( ); // Beginne eine neue Form g.moveTo(cx,cy); // Gehe zum Mittelpunkt // Linie zum startangle-Punkt und Kreisbogen zum endangle-Punkt
22.5 Grafiken auf einem |
613
491-0.book Seite 614 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-11: Ein Tortendiagramm auf ein -Tag zeichnen (Fortsetzung) g.arc(cx,cy,r,startangle, endangle, false); g.closePath( ); // Zurück zum Mittelpunkt und beende die Figur g.fillStyle = colors[i]; // Farbe setzen g.fill( ); // Fülle das Tortenstück g.stroke( ); // Zeichne den Umriss des Tortenstücks // Das nächste Tortenstück beginnt dort, wo dieses aufhört startangle = endangle; // Zeichne das Rechteck für dieses Tortenstück in der Legende g.fillRect(lx, ly+30*i, 20, 20); g.strokeRect(lx, ly+30*i, 20, 20); // Setze eine Beschriftung neben das Rechteck. // Die Canvas-API unterstützt keinen Text, weswegen wir hier // einfach normalen HTML-Text verwenden. Wir verwenden die CSS// Positionierung, um den Text an die richtige Stelle, also über das // Canvas-Element zu setzen. Das wäre etwas sauberer, wenn das canvas-Tag // selbst absolut positioniert wäre var label = document.createElement("div"); label.style.position = "absolute"; label.style.left = (canvas.offsetLeft + lx+30)+"px"; label.style.top = (canvas.offsetTop+ly+30*i-4) + "px"; label.style.fontFamily = "sans-serif"; label.style.fontSize = "16px"; label.appendChild(document.createTextNode(labels[i])); document.body.appendChild(label); } } function init( ) { // Erzeuge ein Canvas-Element var canvas = makeCanvas("canvas", 600, 400); // Füge es zum Dokument hinzu, document.body.appendChild(canvas); // und zeichne ein Tortendiagramm auf ihm pieChart("canvas", [12, 23, 34, 45], 200, 200, 150, ["red", "blue", "yellow", "green"], ["Nord", "Süd", "Ost", "West"], 400, 100); }
614 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 615 Mittwoch, 4. April 2007 9:55 09
e-bol.net
22.6 Grafiken mit Flash
Ein leistungsstarkes Vektorgrafik-Plug-in ist aber vielerorts (fast überall) installiert: der Flash-Player von Adobe (früher Macromedia). Der Flash-Player hat seine eigene skriptgesteuerte Sprache namens ActionScript (das eigentlich ein Dialekt von JavaScript ist). Seit Flash 6 exponiert der Player eine einfache, aber leistungsfähige Zeichnungs-API für ActionScript-Code. Flash 6 und 7 stellen auch begrenzte Kommunikationskanäle zwischen clientseitigem JavaScript und ActionScript bereit. Das ermöglicht es clientseitigem JavaScript, Zeichenkommandos an das Flash-Plug-in zu senden, die dann durch den ActionScript-Interpreter des Plug-ins ausgeführt werden. Dieses Kapitel beruht auf Flash 8, das brandneu war, als dieses Buch geschrieben wurde. Flash 8 enthält eine ExternalInterface-API, die den Export von ActionScript-Methoden spielend leicht macht, um sie dann von clientseitigem JavaScript transparent aufzurufen. Kapitel 23 zeigt, wie Flash-Zeichenmethoden unter Flash 6 und 7 aufgerufen werden. Um einen Flash-basierenden Zeichnungscanvas zu erzeugen, brauchen Sie eine .swfDatei, die nicht selbst zeichnet, sondern lediglich eine Zeichnungs-API in JavaScript4 auf der Clientseite exportiert. Fangen wir mit der in Beispiel 22-12 gezeigten ActionScriptDatei an. Beispiel 22-12: Canvas.as import flash.external.ExternalInterface; class Canvas { // Der Open Source-mtasc-ActionScript-Kompilierer ruft automatisch diese // main( )-Methode in der von ihm erstellten kompilierten .swf-Datei auf. Wenn Sie das // Flash-IDE verwenden, um eine Canvas.swf-Datei zu erzeugen, müssen Sie stattdessen // Canvas.main( ) vom ersten Frame des Movies aus aufrufen. static function main( ) { var canvas = new Canvas( ); } // Dieser Konstruktor enthält Initialisierungscode für unseren Flash-Canvas function Canvas( ) { // Gib das Verhalten bei der Größenanpassung für den Canvas an Stage.scaleMode = "noScale"; Stage.align = "TL";
4 Der Flash-basierte Tortendiagramm-Code in Beispiel 22-13 verwendet diese Flash-Zeichnungs-API, die ich aber hier nicht dokumentiere. Eine Dokumentation befindet sich auf der Adobe-Website.
22.6 Grafiken mit Flash |
615
clientseitiges JavaScript
Alle bisher im Kapitel besprochenen Vektorgrafik-Technologien sind nur begrenzt verfügbar: Das -Tag wird nur von Safari 1.3, Firefox 1.5 und Opera 9 unterstützt. VML ist (und bleibt) nur unter IE anwendbar, und SVG wird von Haus aus nur unter Firefox 1.5 unterstützt. Eine Plug-in-Unterstützung für SVG ist erhältlich, aber das Plugin ist nicht weit genug verbreitet.
491-0.book Seite 616 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-12: Canvas.as (Fortsetzung) // Exportiere jetzt einfach die Funktionen der Flash-Zeichnungs-API ExternalInterface.addCallback("beginFill", _root, _root.beginFill); ExternalInterface.addCallback("beginGradientFill", _root, _root.beginGradientFill); ExternalInterface.addCallback("clear", _root, _root.clear); ExternalInterface.addCallback("curveTo", _root, _root.curveTo); ExternalInterface.addCallback("endFill", _root, _root.endFill); ExternalInterface.addCallback("lineTo", _root, _root.lineTo); ExternalInterface.addCallback("lineStyle", _root, _root.lineStyle); ExternalInterface.addCallback("moveTo", _root, _root.moveTo); // Exportiere die unten stehende addText( )-Funktion ebenfalls ExternalInterface.addCallback("addText", null, addText); } static function addText(text, x, y, w, h, depth, font, size) { // Erzeuge ein TextField-Objekt, um den Text an der angegebenen Stelle anzuzeigen var tf = _root.createTextField("tf", depth, x, y, w, h); // Sage ihm, welcher Text angezeigt werden soll tf.text = text; // Setze die Font-Familie und Punktgröße für den Text var format = new TextFormat( ); format.font = font; format.size = size; tf.setTextFormat(format); } }
Der ActionScript-Code in der Canvas.as-Datei in Beispiel 22-12 muss zuerst zu einer Canvas.swf-Datei kompiliert werden, bevor sie mit dem Flash-Player verwendet werden kann. Die Einzelheiten zu dieser Vorgehensweise übersteigen den Umfang dieses Buchs, aber Sie können ein kommerzielles Flash-IDE von Adobe oder einen Open SourceActionScript-Compiler verwenden.5 Leider bietet Flash nur eine primitive API. Insbesondere ist curveTo( ) die einzige Funktion zum Zeichnen von Kurven und zeichnet eine quadratische Bezierfunktion. Alle Kreise, Ellipsen und kubische Bezierfunktionen müssen durch einfachere quadratische Kurven approximiert werden. Diese primitive API passt gut zum kompilierten SWFFlash-Format: Alle Berechnungen, die für kompliziertere Kurven benötigt werden, können während der Kompilation durchgeführt werden, und der Flash-Player muss lediglich wissen, wie einfachere Kurven gezeichnet werden. Eine Zeichnungs-API auf höherer
5 Ich habe den Open Source-mtasc-Compiler (http://www.mtasc.org) verwendet und den Code mit diesem Befehl kompiliert: mtasc -swf Canvas.swf -main -version 8 -header 500:500:1 Canvas.as
Nach der Kompilation ist die resultierende Canvas.swf-Datei gerade mal 578 Bytes groß – kleiner als die meisten Bitmap-Bilder.
616 | Kapitel 22: Skriptgesteuerte Grafiken auf der Clientseite
491-0.book Seite 617 Mittwoch, 4. April 2007 9:55 09
e-bol.net Ebene kann auf der von Flash-Player bereitgestellten einfacheren Ebene aufgebaut werden, was in ActionScript und JavaScript möglich ist (Beispiel 22-13 ist in JavaScript).
Beispiel 22-13: Ein Tortendiagramm mit JavaScript und Flash zeichnen // Bette einen Flash-Canvas der angegebenen Größe ein, und füge ihn als einziges // Kind des angegebenen Container-Elements ein. Aus Gründen der Übertragbarkeit verwendet // diese Funktion in Netscape-artigen Browsern ein -Tag und in anderen Browsern // ein -Tag. Inspiriert durch FlashObject von Geoff Stearns. // Siehe http://blog.deconcept.com/flashobject/ function insertCanvas(containerid, canvasid, width, height) { var container = document.getElementById(containerid); if (navigator.plugins && navigator.mimeTypes&&navigator.mimeTypes.length){ container.innerHTML = ""; } else { container.innerHTML = "" + " " + " " + ""; } } // Die Flash-Zeichnungs-API ist primitiver als andere und hat nur eine einfache // Bezierkurvenfunktion. Diese Methode zeichnet ein Tortenstück mit dieser API. // Beachte, dass die Winkel im Bogenmaß angegeben werden. function wedge(canvas, cx, cy, r, startangle, endangle, color) {
22.6 Grafiken mit Flash |
617
clientseitiges JavaScript
Beispiel 22-13 beginnt mit einer Utility-Funktion, die die Canvas.swf-Datei in das HTML-Dokument einbettet. Das wird unter verschiedenen Browsern unterschiedlich gemacht, und das insertCanvas( )-Utility vereinfacht diese Arbeit. Dann kommt eine wedge( )-Funktion, die die einfache Flash-Zeichnungs-API verwendet, um ein Tortenstück des Diagramms zu zeichnen. Daran schließt sich die pieChart( )-Funktion an und ruft wedge( ) auf, um ihr Tortenstück zu zeichnen. Schließlich definiert das Beispiel einen onload-Handler, um den Flash-Canvas in das Dokument einzufügen und ihn zu zeichnen.
491-0.book Seite 618 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 22-13: Ein Tortendiagramm mit JavaScript und Flash zeichnen (Fortsetzung) // Bestimme den Startpunkt des Tortenstücks var x1 = cx + r*Math.sin(startangle); var y1 = cy - r*Math.cos(startangle); canvas.beginFill(color, 100); // Fülle mit angegebener Farbe, voll deckend canvas.moveTo(cx, cy); // Gehe zum Kreismittelpunkt canvas.lineTo(x1, y1); // Zeichne eine Linie zum Kreisumfang // Unterteile jetzt den Kreisbogen in Stücke < 45 Grad, und zeichne jedes davon // über einen Aufruf an die eingebettete arc( )-Methode while(startangle < endangle) { var theta; if (endangle-startangle > Math.PI/4) theta = startangle+Math.PI/4; else theta = endangle; arc(canvas,cx,cy,r,startangle,theta); startangle += Math.PI/4; } canvas.lineTo(cx, cy); canvas.endFill( );
// Beende mit einer Linie zurück zum Mittelpunkt // Fülle den Umriss des Tortenstücks
// Diese eingebettete Funktion zeichnet einen Kreisbogen per Bezierkurve. // endangle-startangle muss
Das -Tag hat ein id-Attribut, und das -Tag hat ein name-Attribut. Das ist eine übliche Vorgehensweise und bedeutet, dass Sie mit dem folgenden browserübergreifenden Codefragment auf das einbettende Element verweisen können: // Hole das Flash-Movie unter IE über Window und unter anderen Browsern über Document var flash = window.movie || document.movie; // Hole das Flash-Objekt
Damit die Flash-nach-JavaScript-Skriptsteuerung einwandfrei läuft, muss das Tag ein name-Attribut haben. Wenn Sie möchten, können Sie ihm auch eine id geben. Damit lässt sich getElementById( ) browserübergreifend zur Lokalisierung des oder -Tags verwenden.
23.4.2 Den Flash-Player steuern Jetzt haben wir das Flash-Movie in Ihre HTML-Seite eingebettet und JavaScript verwendet, um eine Referenz auf das HTML-Element zu erhalten, das das Movie zur Einbettung enthält. Jetzt können wir den Flash-Player per Skript steuern, indem wir einfach Metho1 Beim Schreiben dieses Buchs stand das Dictionary unter http://www.adobe.com/support/flash/action_scripts/ actionscript_dictionary/.
23.4 Flash skripten |
639
clientseitiges JavaScript
Bevor ein Flash-Movie skriptgesteuert werden kann, muss es in eine HTML-Seite eingebettet werden, damit Ihr JavaScript-Code auf das Movie zugreifen kann. Das einzige Problem besteht hier in Browser-Inkompatibilitäten: IE braucht ein -Tag mit bestimmten Attributen, andere Browser wollen ein -Tag mit anderen Attributen oder ein -Tag. Das Standard-HTML-Tag ist , aber die hier beschriebene Skripttechnik für Flash-nach-JavaScript scheint ein -Tag zu erwarten.
491-0.book Seite 640 Mittwoch, 4. April 2007 9:55 09
e-bol.net den dieses Elements aufrufen. Beispielsweise lassen sich die folgenden Dinge über diese Methoden machen: var flash = window.movie || document.movie; if (flash.IsPlaying( )) { flash.StopPlay( ); flash.Rewind( ); } if (flash.PercentLoaded( ) == 100) flash.Play( ); flash.Zoom(50); flash.Pan(25, 25, 1); flash.Pan(100, 0, 0);
// // // //
Hole das Movie-Objekt Wenn das Movie läuft, halte es an, und spule es zurück
// // // // //
Ist es vollständig geladen, dann lasse es laufen. Zoome 50% heran Verschiebe es um 25% nach unten rechts Verschiebe 100 Pixel nach rechts
Diese Flash-Player-Methoden sind in Teil IV unter FlashPlayer dokumentiert, und einige werden in Beispiel 23-5 vorgeführt.
23.4.3 Flash-Movies skripten Interessanter als das Steuern des Flash-Players ist das Aufrufen von ActionScript-Methoden, die im Movie selbst definiert sind. Mit Java-Applets geht das ganz leicht: Rufen Sie einfach die gewünschten Methoden so auf, als wären sie die Methoden des HTML-Tags. Unter Flash 8 geht das genauso einfach. Wenn Sie allerdings auf Benutzer abzielen, die diese Player-Version vielleicht noch nicht haben, müssen Sie ein paar Hürden mehr nehmen. Eine der grundlegenden Methoden zum Skripten des Flash-Players heißt SetVariable( ). Eine andere hat den Namen GetVariable( ). Sie lassen sich zum Setzen und Auslesen der Werte von ActionScript-Variablen verwenden. Es gibt keine InvokeFunction( )-Methode, aber Sie können eine ActionScript-Erweiterung von JavaScript ausnutzen, um mit SetVariable( ) einen Funktionsaufruf auszulösen. Unter ActionScript hat jedes Objekt eine watch( )-Methode, die einen Watchpoint im Debugging-Stil setzen kann: Jedes Mal, wenn sich der Wert einer angegebenen Eigenschaft des Objekts ändert, wird eine angegebene Funktion aufgerufen. Schauen Sie sich diesen ActionScript-Code an: /* ActionScript */ // Definiere Variablen für Funktionsargumente und Rückgabewert // _root bezieht sich auf die Root-Timeline des Movies. SetVariable( ) und // GetVariable( ) können Eigenschaften dieses Objekts setzen und lesen. _root.arg1 = 0; _root.arg2 = 0; _root.result = 0; // Diese Variable wird definiert, um einen Funktionsaufruf auszulösen _root.multiply = 0; // Verwenden Sie jetzt Object.watch( ), um eine Funktion aufzurufen, wenn sich der Wert // der "multiply"-Eigenschaft ändert. Beachten Sie, dass wir die Typenkonvertierung // der Argumente explizit verwenden _root.watch("multiply", function( ) { _root.result = Number(_root.arg1) * Number(_root.arg2);
640 | Kapitel 23: Java-Applets und Flash-Movies skripten
491-0.book Seite 641 Mittwoch, 4. April 2007 9:55 09
e-bol.net // Dieser Rückgabewert wird zum neuen Wert der Eigenschaft. return 0; });
/* JavaScript */ // Weise das Flash-Movie an, zwei Zahlen zu multiplizieren function multiply(x, y) { var flash = window.movie || document.movie; // Hole das Flash-Objekt flash.SetVariable("arg1", x); // Setze das erste Argument flash.SetVariable("arg2", y); // Setze das zweite Argument flash.SetVariable("multiply", 1); // Triggere den Multiplikationscode var result = flash.GetVariable("result"); // Rufe das Ergebnis ab return Number(result); // Konvertiere es, und gib es aus. }
23.4.4 JavaScript von Flash aus aufrufen ActionScript kann über eine Funktion namens fscommand( ) mit JavaScript kommunizieren, der es zwei Strings übergibt: fscommand("eval", "alert('Hallo von Flash')");
Die Argumente von fscommand( ) tragen zwar die Namen kommando und argumente, müssen aber keinen Befehl und keine Argumente repräsentieren: Sie dürfen zwei beliebige Strings sein. Wenn der ActionScript-Code fscommand( ) aufruft, werden die zwei Strings an eine spezielle JavaScript-Funktion übergeben, die als Antwort auf kommando eine beliebige Aktion durchführen kann. Beachten Sie, dass der JavaScript-Rückgabewert nicht an ActionScript zurückgegeben wird. Der von fscommand( ) aufgerufene Name der JavaScript-Funktion hängt von dem id- oder name-Argument ab, das beim Einbetten des Movies zusammen mit dem - oder -Tag verwendet wurde. Wenn Ihr Movie »film« heißt, müssen Sie eine JavaScript-Funktion mit dem Namen film_DoFSCommand definieren. Das folgende Beispiel kann den fscommand( )-Aufruf verarbeiten: function film_DoFSCommand(kommando, argumente) { if (kommando == "eval") eval(argumente); }
Das ist recht unkompliziert, funktioniert aber nicht unter Internet Explorer. Aus unerklärlichen Gründen kann im IE-Browser eingebettetes Flash nicht direkt mit JavaScript kommunizieren. Das ist jedoch über die Microsoft-eigene Skriptsprache VBScript möglich. Und VBScript kann mit JavaScript kommunizieren. Um also fscommand( ) unter IE zum Laufen zu bringen, müssen Sie zusätzlich das folgende Codefragment in Ihre HTML-Datei aufnehmen, das auch davon ausgeht, dass das Movie »film« heißt:
23.4 Flash skripten |
641
clientseitiges JavaScript
Um ein Beispiel zu formulieren: Nehmen wir einfach einmal an, dass das Flash-PlayerPlug-in Multiplikationen viel besser durchführen kann als der JavaScript-Interpreter. So rufen Sie den ActionScript-Multiplikationscode über JavaScript auf:
491-0.book Seite 642 Mittwoch, 4. April 2007 9:55 09
e-bol.net sub film_FSCommand(byval kommando, byval argumente) call film_DoFSCommand(kommando, argumente) ' Einfach die JavaScript-Version aufrufen end sub
Niemand erwartet, dass Sie diesen Code verstehen; binden Sie ihn einfach in Ihre HTMLDatei ein. Browser, die VBScript nicht verstehen, ignorieren dieses -Tag und seinen Inhalt einfach.
23.4.5 Beispiel: von Flash zu JavaScript und zurück zu Flash Jetzt setzen wir diese ganzen Teile in einem zweiteiligen Beispiel zusammen, das aus aus einer Datei mit ActionScript-Code (Beispiel 23-4) und einer Datei mit HTML- und JavaScript-Code (Beispiel 23-5) besteht. Beim Laden des Flash-Movies verwendet es fscommand( ), um JavaScript Bescheid zu geben, das daraufhin einen Formular-Button aktiviert. Wenn der Formular-Button gedrückt wird, verwendet JavaScript die SetVariable( )-Technik, um das Flash-Movie zum Zeichnen eines Dreiecks aufzufordern. Wenn der Benutzer die Maus innerhalb des Flash-Movies anklickt, verwendet es fscommand( ), um JavaScript die Mausposition mitzuteilen. Beide Beispiele sind ausführlich dokumentiert und sollten leicht verständlich sein. Beispiel 23-4: ActionScript-Code, der unter JavaScript funktioniert /** * Box.as: ActionScript-Code zur Demonstration der * JavaScript Flash-Kommunikation * * Diese Datei ist in ActionScript 2.0 geschrieben, einer Sprache, die auf * JavaScript beruht, aber zur objektorientierteren Programmierung erweitert wurde. * Wir definieren hier nur eine einfache, statische Funktion namens main( ) * in einer Klasse mit dem Namen Box. * * Dieser Code kann mit dem Open Source-ActionScript-Compiler mtasc * kompiliert werden, und zwar mit folgendem Befehl: * * mtasc -header 300:300:1 -main -swf Box1.swf Box1.as * * mtasc erzeugt eine SWF-Datei, die die main( )-Methode des ersten * Movie-Frames aufruft. Wenn Sie das Flash-IDE verwenden, müssen Sie Ihren eigenen * Aufruf an Box.main( ) in das erste Frame einfügen. */ class Box { static function main( ) { // Eine ActionScript-Funktion, die wir von JavaScript aus nutzen wollen. // Sie zeichnet ein Quadrat und gibt seine Fläche zurück. var drawBox = function(x,y,b,h) { _root.beginFill(0xaaaaaa, 100); _root.lineStyle(5, 0x000000, 100);
642 | Kapitel 23: Java-Applets und Flash-Movies skripten
491-0.book Seite 643 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 23-4: ActionScript-Code, der unter JavaScript funktioniert (Fortsetzung)
clientseitiges JavaScript
_root.moveTo(x,y); _root.lineTo(x+b, y); _root.lineTo(x+b, y+h); _root.lineTo(x, b+h); _root.lineTo(x,y); _root.endFill( ); return b*h; } // So können wir der Funktion erlauben, von JavaScript aufgerufen zu werden // (vor Flash 8). Erst definieren wir in unserer Root-Timeline Eigenschaften, // um die Funktionsargumente und den Rückgabewert zu speichern. _root.arg1 = 0; _root.arg2 = 0; _root.arg3 = 0; _root.arg4 = 0; _root.result = 0; // Dann definieren wir noch eine Eigenschaft mit dem gleichen Namen wie die Funktion. _root.drawBox = 0; // Jetzt "beobachten" wir die Eigenschaft mit der Object.watch( )-Methode. // Wenn sie gesetzt wird, ruft das die von uns angegebene Funktion auf. // Das bedeutet: Der JavaScript-Code kann mit SetVariable einen // Funktionsaufruf auslösen. _root.watch("drawBox", // Der Name der zu beobachtenden Eigenschaft function( ) { // Die bei Eigenschaftsänderung aufzurufende Funktion // Rufe die drawBox( )-Funktion auf, und konvertiere die // Argumente von Strings nach Zahlen, und speichere // den Rückgabewert. _root.result = drawBox(Number(_root.arg1), Number(_root.arg2), Number(_root.arg3), Number(_root.arg4)); // Gib 0 zurück, damit sich der Wert der von uns // beobachteten Eigenschaft nicht ändert. return 0; });
// Das ist ein ActionScript-Event-Handler. // Er ruft die fscommand( )-Funktion auf, um die // Koordinaten eines Mausklicks an JavaScript weiterzuleiten. _root.onMouseDown = function( ) { fscommand("mousedown", _root._xmouse + "," + _root._ymouse); } // Hier verwenden wir fscommand( ) noch einmal, um JavaScript mitzuteilen, // dass das Flash-Movie geladen und bereit ist.
23.4 Flash skripten |
643
491-0.book Seite 644 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 23-4: ActionScript-Code, der unter JavaScript funktioniert (Fortsetzung) fscommand("loaded", ""); } }
Beispiel 23-5: Skriptsteuerung eines Flash-Movies unter IE und für andere Browser. Beachten Sie die IE-spezifischen bedingten Kommentare. --> Zeichnen Zoom Verschieben // Diese Funktion zeigt, wie Flash auf die harte Tour aufgerufen wird. function draw( ) { // Zuerst beschaffen wir uns das Flash-Objekt. Da wir "film" als id // und Name der - und -Tags verwenden, steht das Objekt // in einer Eigenschaft mit dem Namen "film". Unter IE ist sie eine window-Eigenschaft // und unter anderen Browsern eine document-Eigenschaft. var flash = window.movie || document.movie; // Hole das Flash-Objekt. // // // // if
Sicherstellen, dass das Movie vor der Skriptsteuerung vollständig geladen ist. Das ist nur zu Veranschaulichung: Es ist überflüssig, da wir den Button, der diese Methode aufruft, so lange deaktivieren, bis Flash uns über das vollständige Laden informiert (flash.PercentLoaded( ) != 100) return;
644 | Kapitel 23: Java-Applets und Flash-Movies skripten
491-0.book Seite 645 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 23-5: Skriptsteuerung eines Flash-Movies (Fortsetzung) // Als Nächstes "übergeben" wir Funktionsargumente, indem wir sie einzeln setzen. flash.SetVariable("arg1", 10); flash.SetVariable("arg2", 10); flash.SetVariable("arg3", 50); flash.SetVariable("arg4", 50);
clientseitiges JavaScript
// Jetzt lösen wir die Funktion aus, indem wir noch eine Eigenschaft setzen. flash.SetVariable("drawBox", 1); // Schließlich fordern wir den Rückgabewert der Funktion an. return flash.GetVariable("result"); } function zoom( ) { var flash = window.movie || document.movie; // Hole Flash-Objekt. flash.Zoom(50); } function pan( ) { var flash = window.movie || document.movie; // Hole Flash-Objekt. flash.Pan(-50, -50, 1); } // Diese Funktion wird aufgerufen, wenn Flash fscommand( ) aufruft. // Die zwei Argumente sind Strings, die Flash übergibt. // Diese Funktion muss genau diesen Namen haben, sonst wird sie nicht aufgerufen. // Der Funktionsname beginnt mit "film", weil das die id bzw. der Name der // vorher verwendeten - und -Tags ist. function film_DoFSCommand(kommando, argumente) { if (kommando=="loaded") { // Wenn Flash uns das vollständige Laden anzeigt, können wir den Formular// Button aktivieren. document.f.button.disabled = false; } else if (kommando == "mousedown") { // Flash sagt uns, wenn der Benutzer die Maus anklickt. // Flash kann uns nur Strings übergeben. Wir müssen Sie nach Bedarf parsen, // um an die Daten zu kommen, die Flash uns sendet. var coords = argumente.split(","); alert("Mousedown: (" + coords[0] + ", " + coords[1] + ")"); } // Das hier sind ein paar andere nützliche Befehle. else if (kommando == "debug") alert("Flash-Debug: " + argumente); else if (kommando == "eval") eval(argumente); } ' Dieses Skript ist nicht in JavaScript, sondern in der ' Visual Basic Scripting Edition von Microsoft geschrieben. Dieses Skript ist unter Internet
23.4 Flash skripten |
645
491-0.book Seite 646 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 23-5: Skriptsteuerung eines Flash-Movies (Fortsetzung) ' Explorer notwendig, um fscommand( )-Benachrichtigungen von Flash zu erhalten. Unter allen anderen ' Browsern wird es ignoriert, da sie VBScript nicht unterstützen. ' Der Name dieser VBScript-Subroutine muss genau so sein, wie hier gezeigt. sub film_FSCommand(byval kommando, byval argumente) call film_DoFSCommand(kommando, argumente) ' Einfach die JavaScript-Version aufrufen end sub
23.5 Flash 8 skripten Die Version 8 des Flash-Players enthält eine Klasse namens ExternalInterface, die das Skripten von Flash revolutioniert, indem sie die JavaScript-nach-Flash-Kommunikation und Flash-nach-JavaScript-Kommunikation außerordentlich vereinfacht. ExternalInterface definiert eine statische call( )-Funktion zum Aufruf angegebener JavaScript-Funktionen und zum Lesen ihrer Rückgabewerte. Sie definiert außerdem eine statische addCallback( )-Methode zum Export von ActionScript-Funktionen, die unter JavaScript verwendet werden sollen. ExternalInterface wird in Teil IV dokumentiert. Um die Einfachheit der Skriptsteuerung mit ExternalInterface zu demonstrieren, konvertieren wir die Beispiele 23-4 und 23-5 zur Verwendung mit ExternalInterface. Beispiel 236 zeigt den konvertierten ActionScript-Code und Beispiel 23-7 den konvertierten JavaScript-Code (die Tags , und werden aus Beispiel 23-5 übernommen und sind hier nicht aufgeführt). Die Kommentare dieser Beispiele sollten Ihnen alles Nötige über die Verwendung von ExternalInterface sagen. Die Methode ExternalInterface.addCallback( ) wird außerdem in Beispiel 22-12 angewendet. Beispiel 23-6: ActionScript unter Verwendung von ExternalInterface /** * Box2.as: ActionScript-Code zur Darstellung der * JavaScript Flash-Kommunikation * unter Verwendung der ExternalInterface-Klasse von Flash 8. * * Kompilieren Sie diesen Code, indem Sie mtasc mit einem * Befehl wie dem folgenden verwenden: * * mtasc -version 8 -header 300:300:1 -main -swf Box2.swf Box2.as * * Wenn Sie stattdessen das Flash-IDE verwenden, fügen Sie den Aufruf von Box.main( ) * in das erste Frame Ihres Movies ein. */ import flash.external.ExternalInterface;
646 | Kapitel 23: Java-Applets und Flash-Movies skripten
491-0.book Seite 647 Mittwoch, 4. April 2007 9:55 09
e-bol.net Beispiel 23-6: ActionScript unter Verwendung von ExternalInterface (Fortsetzung)
// Das ist ein ActionScript-Event-Handler. // Informiere JavaScript mittels ExternalInterface.call( ) über Mausklicks. _root.onMouseDown = function( ) { ExternalInterface.call("reportMouseClick", _root._xmouse, _root._ymouse); } // Teile JavaScript mit, dass wir alles geladen haben und zum Skriptsteuern bereit // sind. ExternalInterface.call("flashReady"); } }
Beispiel 23-7: Vereinfachte Flash-Skriptsteuerung mit ExternalInterface // Wurde eine ActionScript-Funktion mit ExternalInterface.addCallback exportiert, // können wir sie ganz einfach als eine Methode des Flash-Objekts aufrufen. function draw( ) { var flash = window.movie || document.movie; // Hole das Flash-Objekt return flash.drawBox(100, 100, 100, 50); // Rufe einfach eine Funktion an ihm auf } // Das sind Funktionen, die Flash über ExternalInterface.call( ) aufruft. function flashReady( ) { document.f.button.disabled = false; } function reportMouseClick(x, y) { alert("Klick: " + x + ", " + y); }
23.5 Flash 8 skripten |
647
clientseitiges JavaScript
class Box { static function main( ) { // Verwende das neue ExternalInterface für den Export unserer ActionScript-Funktion. // Das vereinfacht den Funktionsaufruf über JavaScript stark, // wird aber nur von Flash 8 und höher unterstützt. // Das erste Argument von addCallback ist der Name, unter dem die Funktion // in JavaScript bekannt ist. Das zweite Argument ist das // ActionScript-Objekt, an dem die Funktion aufgerufen wird. Das // ist der Wert des 'this'-Schlüsselworts. Das dritte Argument // ist die aufzurufende Funktion. ExternalInterface.addCallback("drawBox", null, function(x,y,b,h) { _root.beginFill(0xaaaaaa, 100); _root.lineStyle(5, 0x000000, 100); _root.moveTo(x,y); _root.lineTo(x+b, y); _root.lineTo(x+b, y+h); _root.lineTo(x, b+h); _root.lineTo(x,y); _root.endFill( ); return b*h; });
491-0.book Seite 648 Mittwoch, 4. April 2007 9:55 09
e-bol.net
491-0.book Seite 649 Mittwoch, 4. April 2007 9:55 09
e-bol.net
TEIL III
Referenz für den JavaScript-Sprachkern III.
Dieser Teil des Buchs ist eine vollständige Referenz der Klassen, Eigenschaften, Funktionen und Methoden der JavaScript-Kern-API. Die ersten Seiten dieses Teils erklären, wie Sie das Referenzmaterial benutzen, und sie sind es wert, sorgfältig durchgelesen zu werden. Die in diesem Teil dokumentierten Klassen und Objekte beinhalten: Arguments
Global
Array
JavaArray
Object
Boolean
JavaClass
RegExp
Date
JavaObject
String
Error
JavaPackage
Function
Math
Number
491-0.book Seite 650 Mittwoch, 4. April 2007 9:55 09
e-bol.net
491-0.book Seite 651 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Referenz für den Sprachkern von JavaScript
Dieser Teil des Buchs ist eine Referenz der Klassen, Methoden und Eigenschaften, die im Kern von JavaScript definiert sind. Die Einleitung und der nachfolgende Beispiel-Referenzeintrag erklären, wie Sie diese Referenz benutzen und am besten davon profitieren können. Bitte nehmen Sie sich die Zeit, dieses Material sorgfältig durchzulesen, denn dann können Sie die benötigten Informationen später schneller auffinden. Diese Referenz ist alphabetisch angelegt. Die Referenzeinträge für die Methoden und Eigenschaften von Klassen werden alphabetisch mit ihrem vollen Namen aufgeführt, zu dem auch die Klasse gehört, in der sie definiert sind. Wenn Sie z.B. etwas über die replace( )Methode der Klasse String nachlesen möchten, müssen Sie unter String.replace() und nicht nur unter replace nachschlagen. Der JavaScript-Sprachkern definiert einige globale Funktionen und Eigenschaften, z.B. eval( ) und NaN. Technisch gesehen sind dies Eigenschaften des globalen Objekts. Da ein
globales Objekt jedoch keinen Namen hat, werden sie in der Referenz unter ihren eigenen Namen aufgeführt. Der Bequemlichkeit halber werden alle globalen Funktionen und Eigenschaften des JavaScript-Sprachkerns in einem speziellen Referenzeintrag unter dem Namen »Global« zusammengefasst, obwohl es eigentlich kein Objekt und keine Klasse dieses Namens gibt. Haben Sie erst den gesuchten Eintrag gefunden, so dürfte das Auffinden der benötigten Informationen keine Schwierigkeiten mehr bereiten. Doch Sie können den Referenzteil noch besser ausnutzen, wenn Sie wissen, wie die Einträge geschrieben und organisiert sind. Im Folgenden sehen Sie einen Beispiel-Referenzeintrag, der die Struktur der einzelnen Referenzeinträge veranschaulicht und Ihnen erklärt, wo Sie die verschiedenen Informationen finden können. Nehmen Sie sich bitte die Zeit, diesen Eintrag zu lesen, ehe Sie sich in den Rest des Referenzmaterials vertiefen.
|
651
491-0.book Seite 652 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Beispiel-Referenzeintrag
Beispiel-Referenzeintrag So werden diese Referenzeinträge gelesen
Verfügbarkeit Erbt von
Titel und Kurzbeschreibung Jeder Referenzeintrag beginnt mit einem vierteiligen Titelblock wie dem oben gezeigten. Die Einträge sind alphabetisch nach Titeln geordnet. Die Kurzbeschreibung unter dem Titel fasst das in dem betreffenden Eintrag dokumentierte Element kurz zusammen und kann Ihnen helfen, rasch zu entscheiden, ob der Rest des Eintrags für Sie interessant ist.
Verfügbarkeit Die Verfügbarkeitsinformationen werden in der rechten oberen Ecke des Titelblocks angezeigt. In früheren Versionen dieses Buchs hat diese Information Ihnen gesagt, welche Version welches Webbrowsers das dokumentierte Element unterstützt. Heutzutage unterstützen die meisten Browser die in diesem Buch dokumentierten Elemente. Deswegen sagt Ihnen der Verfügbarkeitsabschnitt eher, welcher Standard die formelle Spezifikation des Elements liefert. Hier könnten Sie beispielsweise »ECMAScript v1« oder »DOM Level 2 HTML« sehen. Wenn das Element veraltet ist, wird das ebenfalls hier festgehalten. Gelegentlich tauchen hier auch Browsernamen und Versionsnummern auf, üblicherweise wenn das dokumentierte Element ein brandneues Feature ist, das noch nicht allgemein übernommen wurde, oder wenn ein Element ein Internet Explorer-spezifisches Feature ist. Wenn ein Element (wie z.B. das History-Objekt) nie standardisiert wurde, von Browsern, die eine bestimmte JavaScript-Version unterstützen, aber umfassend unterstützt wird, kann in diesem Abschnitt auch die JavaScript-Versionsnummer stehen. Die Verfügbarkeit des HistoryObjekts ist beispielsweise »JavaScript 1.0«. Wenn der Eintrag für eine Methode keine Verfügbarkeitsinformationen enthält, dann heißt das, dass sie die gleiche Verfügbarkeit hat wie die Klasse, die die Methode definiert.
Erbt von Wenn eine Klasse von einer Oberklasse erbt oder eine ihrer Methoden eine Oberklassenmethode überschreibt, finden Sie unten rechts im Titelblock entsprechende Hinweise. Wie in Kapitel 9 bereits erläutert wurde, können JavaScript-Klassen Eigenschaften und Methoden anderer Klassen erben. Beispielsweise erbt die Klasse String von Object und HTMLDocument von Document, das seinerseits von Node erbt. Der Eintrag für String fasst diese Vererbung als »Object ➝ String« zusammen, und der Eintrag für HTMLDocument sagt »Node ➝ Document ➝ HTMLDocument«. Wenn Sie solche Vererbungsinformationen finden, sollten Sie auch die angegebenen Oberklassen nachschlagen. Hat eine Methode denselben Namen wie eine Oberklassenmethode, so überschreibt sie diese. Ein Beispiel finden Sie in Array.toString( ).
652 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 653 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Beispiel-Referenzeintrag
Konstruktor Wenn der Referenzeintrag eine Klasse dokumentiert und die Klasse einen KonstruktorAbschnitt hat, zeigt dieser Abschnitt, wie Sie mit der Konstruktormethode Instanzen der Klasse erzeugen können. Da auch Konstruktoren eine Art von Methoden sind, gleicht der Konstruktor-Abschnitt dem Überblick in einem Methodenreferenzeintrag.
Überblick
array.concat(wert, ...)
Die kursive Schrift weist darauf hin, dass der betreffende Text durch etwas anderes ersetzt wird. array sollte durch eine Variable, die ein Array enthält, oder einen JavaScript-Ausdruck ersetzt werden, dessen Wert ein Array ist. wert ist einfach ein Name für ein Argument, das an das Array übergeben werden soll. Dieses benannte Argument wird später im Überblick beschrieben, und diese Beschreibung enthält Informationen zum Typ und zum Zweck des Arguments. Die Auslassungszeichen (...) deuten an, dass diese Methode beliebig viele wertArgumente entgegennimmt. Da der Begriff concat und die öffnende und schließende Klammer nicht kursiv geschrieben sind, müssen Sie sie genau so, wie sie gezeigt werden, in den JavaScript-Code übernehmen. Viele der Methoden, die im clientseitigen JavaScript-Abschnitt dokumentiert werden, wurden vom W3C standardisiert, und ihre Spezifikationen enthalten definitive Typinformationen für Methodenargumente und Methodenrückgabewerte. Diese Einträge schließen diese Typinformationen in die Synopsis ein. Der Überblick für die Methode Document.getElementById( ) ist beispielsweise: Element getElementById(String elementId);
Dieser Überblick nutzt eine Java-artige Syntax, um anzuzeigen, dass die Methode getElementById( ) ein Element-Objekt zurückliefert und ein Stringargument namens elementId erwartet. Weil es sich um eine Methode von Document handelt, ist impliziert, dass die Methode auf einem Document-Objekt aufgerufen wird. Deswegen wird kein document-Präfix angegeben. Argumente Wenn ein Referenzeintrag eine Funktion, Methode oder Klasse mit einer Konstruktormethode dokumentiert, steht hinter dem Abschnitt »Konstruktor« oder »Überblick« ein Unterabschnitt namens »Argumente«, der die Argumente der betreffenden Methode, Funktion oder Konstruktormethode beschreibt. Gibt es keine Argumente, so fällt dieser Unterabschnitt einfach weg.
Referenz für den Sprachkern von JavaScript |
653
Referenz für den JavaScriptSprachkern
Referenzeinträge zu Funktionen, Methoden und Eigenschaften enthalten einen Überblick, der zeigt, wie Sie diese Funktion, Methode oder Eigenschaft in Ihrem Code benutzen. Die Referenzeinträge in diesem Buch verwenden zwei verschiedene Arten von Überblickzusammenfassungen. Die Einträge in der Kern-JavaScript-Referenz und die clientseitigen Einträge, die Methoden dokumentieren (wie die Window-Methoden), die keinen Bezug zum DOM haben, nutzen einen typlosen Überblick. So ist z.B. Folgendes der Überblick über die Methode Array.concat( ):
491-0.book Seite 654 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Beispiel-Referenzeintrag arg1
Die Argumente werden hier in einer Liste beschrieben. Dies ist z.B. die Beschreibung von arg1. arg2
Und dies ist die Beschreibung von Argument arg2. Rückgabewert Wenn eine Funktion oder eine Methode einen Rückgabewert hat, wird er hier erklärt. Exceptions Wenn ein Konstruktor, eine Funktion oder eine Methode eine Exception auslösen kann, steht hier, welche Typen von Exceptions unter welchen Umständen vorkommen können.
Konstanten Einige Klassen definieren einen Satz von Konstanten, die als Werte für eine Eigenschaft oder als Argument für eine Methode dienen. Das Interface Node definiert beispielsweise wichtige Konstanten, die als zulässige Werte für ihre nodeType-Eigenschaft dienen. Wenn ein Interface Konstanten definiert, werden sie in diesem Abschnitt aufgeführt und dokumentiert. Beachten Sie, dass Konstanten statische Eigenschaften der Klasse selbst und nicht von Instanzen der Klasse sind.
Eigenschaften Wenn der Referenzeintrag eine Klasse dokumentiert, finden Sie im Abschnitt »Eigenschaften« die Eigenschaften, die die Klasse definiert, zusammen mit einer kurzen Erklärung. In Teil III hat auch jede Eigenschaft einen ganzen eigenen Referenzeintrag. In Teil IV werden die meisten Eigenschaften in der Eigenschaftsliste vollständig beschrieben. Die wichtigsten oder komplexesten clientseitigen Eigenschaften haben eine eigene Seite, auf die hier verwiesen wird. In Teil IV schließen die Eigenschaften DOM-bezogener Klassen Typinformationen ein. Eigenschaften anderer Klassen und alle Eigenschaften in Teil III haben keine Typinformationen Die Eigenschaften werden folgendermaßen aufgeführt: eigenschaft1
Dies ist eine Zusammenfassung der typlosen Eigenschaft eigenschaft1. Oben wird nur der Eigenschaftsname aufgeführt, aber die Beschreibung teilt Ihnen den Typ, den Zweck oder die Bedeutung der Eigenschaft mit und enthält Informationen dazu, ob sie schreibgeschützt ist oder nicht. readonly integer eigenschaft2
Dies ist eine Zusammenfassung für die typisierte Eigenschaft eigenschaft2. Neben dem Eigenschaftsnamen wird auch der Typ aufgeführt. Der beschreibende Absatz erklärt den Zweck der Eigenschaft.
Methoden Der Referenzeintrag zu einer Klasse, die Methoden definiert, hat auch einen Abschnitt namens »Methoden«. Dieser gleicht dem Abschnitt »Eigenschaften«, nur dass hier Methoden anstelle von Eigenschaften angegeben werden. Die Methoden haben ebenfalls eigene Referenzeinträge.
654 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 655 Mittwoch, 4. April 2007 9:55 09
e-bol.net
arguments[]
Dieser Zusammenfassungsabschnitt führt nur die Methodennamen auf. Informationen zu Argumenttypen und Rückgabetypen finden Sie auf der Referenzseite zu der entsprechenden Methode.
Beschreibung
In manchen Einträgen ist dieser Abschnitt nur ein kurzer Absatz; in anderen erstreckt er sich über eine Seite oder mehr. Bei manchen einfachen Methoden reichen die Abschnitte »Argumente« und »Rückgabewert« bereits zur Dokumentation aus; dann wird der Beschreibungsabschnitt weggelassen.
Beispiel In manchen Einträgen steht ein typisches Anwendungsbeispiel. Die meisten Einträge enthalten jedoch keine Beispiele; diese stehen in der ersten Hälfte des Buchs.
Fehler Wenn etwas nicht richtig funktioniert, beschreibt dieser Abschnitt die Fehler. Beachten Sie jedoch, dass dieses Buch nicht den Versuch unternimmt, jeden Fehler zu katalogisieren.
Siehe auch Viele Referenzeinträge geben am Ende einen Querverweis auf Referenzeinträge zu verwandten Themen, die von Interesse sein könnten. Manchmal beziehen sich Referenzeinträge auch auf eines der Hauptkapitel des Buchs.
arguments[]
ECMAScript v1
Ein Array von Funktionsargumenten
Überblick arguments
Beschreibung Das Array arguments[] ist nur innerhalb eines Funktionsbodys definiert. Darin bezieht sich arguments auf das Arguments-Objekt für die Funktion. Dieses Objekt hat durchnummerierte Eigenschaften und dient als das Array, das alle an die Funktion übergebenen Argumente enthält. Der Bezeichner arguments ist im Grunde eine lokale Variable, die in jeder Funktion
Referenz für den Sprachkern von JavaScript |
655
Referenz für den JavaScriptSprachkern
Die meisten Referenzeinträge enthalten auch einen Abschnitt namens »Beschreibung, in dem die Grundlagen der dokumentierten Klasse, Methode, Funktion oder Eigenschaft erläutert werden. Dies ist der Kern des Referenzeintrags. Wenn Sie erstmals etwas über eine Klasse, Methode oder Eigenschaft lernen, gehen Sie am besten direkt zu diesem Abschnitt und kehren dann zu den darüber stehenden Abschnitten wie z.B. »Argumente«, »Eigenschaften« und »Methoden« zurück. Wenn Sie die Klasse, Methode oder Eigenschaft schon kennen, brauchen Sie diese Beschreibung eventuell gar nicht zu lesen, sondern schlagen nur rasch eine spezielle Information nach (z.B. im Abschnitt »Argumente« oder »Eigenschaften«).
491-0.book Seite 656 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Arguments
automatisch deklariert und initialisiert wird. Er bezieht sich nur innerhalb des Bodys einer Funktion auf ein Argument-Objekt und ist im globalen Code nicht definiert.
Siehe auch Arguments; Kapitel 8
Arguments Argumente und andere Eigenschaften einer Funktion
ECMAScript v1 Object ➝ Arguments
Überblick arguments arguments[n]
Elemente Das Arguments-Objekt ist nur in einem Funktionsbody definiert. Obwohl es technisch gesehen eigentlich kein Array ist, hat das Arguments-Objekt nummerierte Eigenschaften, die wie ArrayElemente funktionieren, und eine length-Eigenschaft, die die Anzahl der Array-Elemente spezifiziert. Seine Elemente sind die Werte, die der Funktion als Argumente übergeben werden. Element 0 ist das erste Argument, Element 1 das zweite usw. Alle als Argumente übergebenen Werte werden Array-Elemente des Arguments-Objekts, egal ob diese Argumente in der Funktionsdeklaration Namen erhalten oder nicht.
Eigenschaften callee
Eine Referenz auf die Funktion, die gerade ausgeführt wird. length
Die Anzahl der an die Funktion übergebenen Argumente und die Anzahl der ArrayElemente im Arguments-Objekt.
Beschreibung Wenn eine Funktion aufgerufen wird, wird ein Arguments-Objekt für sie erzeugt und die lokale Variable arguments automatisch als Referenz auf dieses Arguments-Objekt initialisiert. Das Arguments-Objekt soll hauptsächlich eine Möglichkeit bieten, die Anzahl der an die Funktion übergebenen Argumente zu ermitteln, und es soll eine Referenz auf unbenannte Argumente geben. Zusätzlich zu den Array-Elementen und der length-Eigenschaft gibt die callee-Eigenschaft einer unbenannten Funktion auch die Möglichkeit, sich selbst zu referenzieren. Meist kann man sich das Arguments-Objekt wie ein Array mit zusätzlicher callee-Eigenschaft vorstellen. Es ist jedoch keine Instanz von Array, und die Eigenschaft Arguments.length zeigt keine der speziellen Verhaltensweisen von Array.length und kann auch nicht dazu verwendet werden, die Array-Größe zu ändern.
656 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 657 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Arguments.callee
Das Arguments-Objekt hat ein sehr ungewöhnliches Merkmal. Wenn eine Funktion benannte Argumente hat, sind die Array-Elemente des Arguments-Objekts synonym zu den lokalen Variablen, die die Funktionsargumente speichern. Das Arguments-Objekt und die Namen der Argumente bieten zwei unterschiedliche Möglichkeiten, dieselbe Variable zu referenzieren. Wenn Sie den Wert eines benannten Arguments ändern, ändert sich auch der Wert, der über das Arguments-Objekt abgerufen wird; und wenn Sie den Wert eines Arguments über das ArgumentsObjekt ändern, ändert sich ebenso der Wert, der über den Argumentnamen abgerufen wird.
Siehe auch Function; Kapitel 8
ECMAScript v1
Die Funktion, die gerade läuft
Überblick arguments.callee
Beschreibung arguments.callee bezieht sich auf die Funktion, die gerade läuft. Diese Eigenschaft ist nur in einem Funktionsbody definiert.
Beispiel // Ein unbenanntes Funktionsliteral referenziert sich mit der callee// Eigenschaft selbst, kann also rekursiv sein var factorial = function(x) { if (x < 2) return 1; else return x * arguments.callee(x-1); } var y = factorial(5); // Gibt 120 zurück
Arguments.length
ECMAScript v1
Die Anzahl der an eine Funktion übergebenen Argumente
Überblick arguments.length
Beschreibung Die length-Eigenschaft des Arguments-Objekts gibt an, wie viele Argumente der aktuellen Funktion übergeben werden. Diese Eigenschaft ist nur in einem Funktionsbody definiert. Beachten Sie, dass diese Eigenschaft nur die Anzahl der tatsächlich übergebenen Argumente angibt und nicht die Anzahl der erwarteten Argumente. Unter Function.length finden Sie die Anzahl der deklarierten Argumente. Außerdem hat diese Eigenschaft keine der speziellen Verhaltensweisen von Array.length.
Referenz für den Sprachkern von JavaScript |
657
Referenz für den JavaScriptSprachkern
Arguments.callee
491-0.book Seite 658 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Array
Beispiel // Prüfe mit einem Arguments-Objekt, ob die richtige Anzahl Argumente // übergeben wurde function check(args) { var actual = args.length; // Tatsächliche Anzahl Argumente var expected = args.callee.length; // Erwartete Anzahl Argumente if (actual != expected) { // Exception, wenn sie nicht übereinstimmen throw new Error("Falsche Anzahl Argumente: erwartet: " + expected + "; übergeben " + actual); } } // Diese Funktion demonstriert die Verwendung der obigen Funktion function f(x, y, z) { check(arguments); // Prüfe auf richtige Anzahl Argumente return x + y + z; // Lass den Rest der Funktion normal laufen }
Siehe auch Array.length, Function.length
Array
ECMAScript v1
Eingebaute Array-Unterstützung
Object ➝ Array
Konstruktor new Array( ) new Array(groesse) new Array(element0, element1, ..., elementn)
Argumente groesse
Die gewünschte Anzahl Array-Elemente. Das length-Feld des Rückgabe-Arrays ist auf groesse gesetzt. element0, ... elementn
Eine Liste von Argumenten mit zwei oder mehr beliebigen Werten. Wenn der Array( )Konstruktor mit diesen Argumenten aufgerufen wird, wird das neu erzeugte Array mit den angegebenen Argumentwerten als Elementen initialisiert und sein length-Feld auf die Anzahl der Argumente gesetzt. Rückgabewert Das neu erzeugte und initialisierte Array. Wenn Array( ) ohne Argumente aufgerufen wird, ist das Rückgabe-Array leer und sein length-Feld 0. Wird Array( ) mit einem einzigen numerischen Argument aufgerufen, so gibt der Konstruktor ein Array mit der angegebenen Anzahl undefinierter Elemente zurück. Wird der Konstruktor mit irgendwelchen anderen Argumenten aufgerufen, so initialisiert er das Array mit den durch diese Argumente angegebenen Werten.
658 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 659 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Array
Wird der Array( )-Konstruktor als Funktion ohne den new-Operator aufgerufen, dann verhält er sich genauso, als sei er mit dem new-Operator aufgerufen worden. Exceptions RangeError
Wenn ein einziges, ganzzahliges groesse-Argument an den Array( )-Konstruktor übergeben wird, wird eine RangeError-Exception ausgelöst, falls groesse negativ oder größer als 232 –1 ist.
Literalsyntax
var a = [1, true, 'abc']; var b = [a[0], a[0]*2, f(x)];
Eigenschaften length
Ein les- und schreibbarer Integer, der die Anzahl der Array-Elemente angibt. Wenn das Array nicht aus aufeinanderfolgenden Elementen besteht, ist dies eine Zahl, die um eins größer als der Index des letzten Array-Elements ist. Wenn Sie den Wert dieser Eigenschaft ändern, wird das Array abgeschnitten oder erweitert.
Verkettet Elemente mit einem Array. Konvertiert alle Array-Elemente in Strings und verkettet diese. Entfernt ein Element vom Array-Ende. Hängt ein Element an das Array-Ende an. Kehrt die Reihenfolge der Elemente innerhalb des Arrays um. Schiebt ein Element aus dem Array-Anfang heraus. Gibt ein Slice (Stück) eines Arrays als Teil-Array zurück. Sortiert die Elemente innerhalb des Arrays. Fügt Array-Elemente ein oder löscht oder ersetzt sie. Konvertiert ein Array in einen lokalisierten String. Konvertiert ein Array in einen String. Fügt Elemente am Array-Anfang ein.
Beschreibung Arrays sind ein grundlegender Bestandteil von JavaScript und werden in Kapitel 7 genau dokumentiert.
Siehe auch Kapitel 7
Referenz für den Sprachkern von JavaScript |
659
Referenz für den JavaScriptSprachkern
ECMAScript v3 spezifiziert eine Array-Literalsyntax. Sie können ein Array auch anlegen und initialisieren, indem Sie eine Liste von durch Kommata getrennten Ausdrücken in eckige Klammern setzen. Die Werte dieser Ausdrücke werden zu den Array-Elementen. Ein Beispiel:
491-0.book Seite 660 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Array.concat( )
Array.concat( )
ECMAScript v3
Verkettet Arrays
Überblick array.concat(wert, ...)
Argumente wert, ...
Eine beliebige Anzahl Werte, die mit array verkettet werden sollen. Rückgabewert Ein neues Array. Es wird durch Verkettung jedes der angegebenen Argumente mit array gebildet.
Beschreibung Die Methode concat( ) erzeugt und liefert ein neues Array, das durch Verkettung jedes ihrer Argumente mit array entsteht. Wenn ein Argument von concat( ) selbst ein Array ist, wird nicht dieses Array selbst, sondern jedes seiner Argumente verkettet.
Beispiel var a = [1,2,3]; a.concat(4, 5) a.concat([4,5]); a.concat([4,5],[6,7]) a.concat(4, [5,[6,7]])
// // // //
Gibt Gibt Gibt Gibt
[1,2,3,4,5] zurück [1,2,3,4,5] zurück [1,2,3,4,5,6,7] zurück [1,2,3,4,5,[6,7]] zurück
Siehe auch Array.join( ), Array.push( ), Array.splice( )
Array.join( )
ECMAScript v1
Verkettet Array-Elemente zu einem String
Überblick array.join( ) array.join(trennzeichen)
Argumente trennzeichen
Ein optionales Zeichen oder ein String, um im Rückgabe-String ein Element des Arrays von dem nächsten zu trennen. Wenn dieses Argument fehlt, wird ein Komma genommen.
660 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 661 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Array.length
Rückgabewert Der String, der sich ergibt, wenn jedes Element des arrays in einen String konvertiert und alle diese Strings dann verkettet werden. Zwischen den Elementen steht jeweils ein trennzeichenString.
Beschreibung join( ) konvertiert alle Elemente eines Arrays in Strings und verkettet dann diese Strings, indem zwischen den Elementen jeweils der String trennzeichen gesetzt wird. Der ErgebnisString wird zurückgegeben.
Beispiel a = new Array(1, 2, 3, "Test"); s = a.join("+"); // s ist der String "1+2+3+Test"
Siehe auch String.split( )
Array.length
ECMAScript v1
Die Größe eines Arrays
Überblick array.length
Beschreibung Die length-Eigenschaft eines Arrays ist immer um eins größer als der Index des größten im Array definierten Elements. Bei traditionellen, »dichten« Arrays mit aufeinanderfolgenden Elementen, die bei 0 beginnen, gibt die length-Eigenschaft die Anzahl der Array-Elemente wieder. Die length-Eigenschaft eines Arrays wird initialisiert, wenn das Array mit dem Konstruktor Array( ) angelegt wird. Werden einem Array neue Elemente hinzugefügt, so wird length wenn nötig geändert: a = new Array( ); b = new Array(10); c = new Array("eins", "zwei", "drei"); c[3] = "vier"; c[10] = "peng";
// // // // //
a.length b.length c.length c.length c.length
mit 0 initialisiert mit 10 initialisiert mit 3 initialisiert mit 4 aktualisiert wird 11
Durch Setzen der length-Eigenschaft können Sie die Größe eines Arrays ändern. Wenn Sie length auf einen kleineren als den bisherigen Wert setzen, wird das Array abgeschnitten, und
Referenz für den Sprachkern von JavaScript |
661
Referenz für den JavaScriptSprachkern
Sie können eine Konvertierung auch in der entgegengesetzten Richtung vornehmen, indem Sie mit der split( )-Methode des String-Objekts einen String in Array-Elemente aufspalten. Einzelheiten hierzu finden Sie unter String.split( ).
491-0.book Seite 662 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Array.pop( )
die letzten Elemente gehen verloren. Setzen Sie length auf einen größeren Wert, so wird das Array größer, und die am Ende des Arrays neu hinzugefügten Werte haben den Wert undefined.
Array.pop( )
ECMAScript v3
Entfernt und liefert das letzte Element eines Arrays
Überblick array.pop( )
Rückgabewert Das letzte Element von array.
Beschreibung pop( ) löscht das letzte Element von array, dekrementiert die Array-Länge und gibt den Wert des gelöschten Elements zurück. Wenn das Array bereits leer ist, ändert pop( ) es nicht und gibt den Wert undefined zurück.
Beispiel pop( ) und sein Gegenstück push( ) ergeben die Funktionalität eines Last-in-first-out-Stacks. Ein
Ein oder mehr Werte, die an array angehängt werden. Rückgabewert Die neue Array-Länge, nachdem die angegebenen Werte angehängt wurden.
662 | Referenz für den Sprachkern von JavaScript
ECMAScript v3
491-0.book Seite 663 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Array.reverse( )
Beschreibung Die Methode push( ) hängt ihre Argumente der Reihe nach am Ende von array an. Sie erzeugt kein neues Array, sondern modifiziert array direkt. Die Methoden push( ) und pop( ) stellen mit Hilfe von Arrays die Funktionalität eines Last-in-first-out-Stacks zur Verfügung. Ein Beispiel finden Sie unter Array.pop( ).
Siehe auch Array.pop( )
ECMAScript v1
Kehrt die Elemente eines Arrays um
Überblick array.reverse( )
Beschreibung Die reverse( )-Methode eines Array-Objekts kehrt die Reihenfolge der Array-Elemente um. Das macht sie vor Ort, indem sie die Elemente des angegebenen arrays umkehrt, ohne ein neues Array anzulegen. Wenn es mehrere Referenzen auf array gibt, kann auf die neue Reihenfolge der Array-Elemente über alle diese Referenzen zugegriffen werden.
Beschreibung shift( ) entfernt und liefert das erste Element von array. Alle Folgeelemente werden um eins nach unten verschoben, um den frei gewordenen Platz am Array-Anfang wieder zu füllen. Wenn das Array leer ist, macht shift( ) überhaupt nichts und gibt den Wert undefined zurück. shift( ) erzeugt kein neues Array, sondern modifiziert unmittelbar das array. shift( ) ist wie Array.pop( ), arbeitet jedoch auf dem Anfang und nicht auf dem Ende des Arrays. Diese Methode wird oft zusammen mit unshift( ) eingesetzt.
Referenz für den Sprachkern von JavaScript |
663
Referenz für den JavaScriptSprachkern
Array.reverse( )
491-0.book Seite 664 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Array.slice( )
Beispiel var a = [1, [2,3], 4] a.shift( ); // Gibt 1 zurück; a = [[2,3], 4] a.shift( ); // Gibt [2,3] zurück; a = [4]
Siehe auch Array.pop( ), Array.unshift( )
Array.slice( )
ECMAScript v3
Gibt einen Teil eines Arrays zurück
Überblick array.slice(anfang, ende)
Argumente anfang
Der Array-Index, bei dem das Stück (Slice) beginnen soll. Ist er negativ, so gibt dieses Argument eine vom Array-Ende ab gemessene Position an. –1 meint also das letzte Element, –2 das vorletzte und so weiter. ende
Der Array-Index, der unmittelbar auf das Ende des Stücks folgt. Ist keiner angegeben, enthält das Stück alle Array-Elemente von anfang bis zum Array-Ende. Ist dieses Argument negativ, so gibt es vom Array-Ende an gemessen ein Array-Element an. Rückgabewert Ein neues Array, das die array-Elemente von dem durch anfang angegebenen Element bis (ausschließlich) zum ende-Element enthält.
Beschreibung slice( ) gibt ein Stück oder ein Teil-Array von array zurück. Das Rückgabe-Array enthält das anfang-Element und alle nachfolgenden Elemente bis hin zum (aber ohne das) ende-Element. Wenn ende nicht angegeben ist, enthält das Rückgabe-Array alle Elemente von anfang bis zum Ende von array.
Beachten Sie, dass slice( ) das Array nicht ändert. Wenn Sie ein Stück des Arrays entfernen möchten, müssen Sie Array.splice( ) verwenden.
Beispiel var a = [1,2,3,4,5]; a.slice(0,3); // Gibt a.slice(3); // Gibt a.slice(1,-1); // Gibt a.slice(-3,-2); // Gibt
[1,2,3] zurück [4,5] zurück [2,3,4] zurück [3] zurück; Bug in IE 4: liefert [1,2,3]
664 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 665 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Array.sort( )
Fehler anfang darf im Internet Explorer 4 keine negative Zahl sein. Dies ist erst in späteren Versionen
des IE geändert worden.
Siehe auch Array.splice( )
Array.sort( )
ECMAScript v1 Referenz für den JavaScriptSprachkern
Optional eine Funktion, die die Sortierreihenfolge festlegt. Rückgabewert Eine Referenz auf das Array. Es wird vor Ort sortiert und nicht kopiert.
Beschreibung Die sort( )-Methode sortiert die array-Elemente vor Ort, ohne das Array zu kopieren. Wird sie ohne Argumente aufgerufen, so werden die Array-Elemente in alphabetischer Reihenfolge (genauer gesagt: in der Reihenfolge, die die Zeichencodierung festlegt) sortiert. Damit ein Vergleich möglich ist, werden die Elemente notfalls zuvor in Strings konvertiert. Wenn Sie die Array-Elemente in eine andere Reihenfolge bringen möchten, müssen Sie eine Vergleichsfunktion angeben, die zwei Werte vergleicht und eine Zahl zurückgibt, die ihre Reihenfolge anzeigt. Die Vergleichsfunktion sollte die beiden Argumente a und b entgegennehmen und eines der folgenden Ergebnisse liefern: • Einen kleineren Wert als null, wenn nach Ihren Sortierkriterien a kleiner als b ist und im sortierten Array vor b stehen soll. • Null, wenn a und b bei dieser Sortierung äquivalent sind. • Einen Wert größer null, wenn a nach Ihren Sortierkriterien größer als b ist. Beachten Sie, dass nicht-definierte Elemente eines Arrays immer an das Array-Ende sortiert werden. Das gilt auch dann, wenn Sie eine eigene Sortierfunktion bereitstellen: Nicht-definierte Werte werden der von Ihnen angegebenen sortierfunktion nicht übergeben.
Referenz für den Sprachkern von JavaScript |
665
491-0.book Seite 666 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Array.splice( )
Beispiel Der folgende Code zeigt, wie Sie beispielsweise eine Vergleichsfunktion schreiben können, um ein Zahlen-Array nicht alphabetisch, sondern numerisch zu sortieren: // Eine Funktion für eine numerische Sortierung function numberorder(a, b) { return a - b; } a = new Array(33, 4, 1111, 222); a.sort( ); // Alphabetische Sortierung: 1111, 222, 33, 4 a.sort(numberorder); // Numerische Sortierung: 4, 33, 222, 1111
Array.splice( )
ECMAScript v3
Fügt Array-Elemente ein oder entfernt oder ersetzt sie
Das Array-Element, mit dem die Einfügung und/oder Löschung anfangen soll. loeschAnzahl
Die Anzahl der Elemente, die aus dem array gelöscht werden sollen, beginnend mit anfang. Dieses Argument ist optional: Wenn nichts angegeben ist, löscht splice( ) alle Elemente von anfang bis zum Ende des Arrays. wert, ...
Null oder mehr Werte, die in array eingefügt werden sollen, beginnend mit dem Index anfang. Rückgabewert Ein Array, das (gegebenenfalls) die aus array gelöschten Elemente enthält.
Beschreibung splice( ) löscht null oder mehr Array-Elemente einschließlich des und beginnend mit dem anfang-Element und ersetzt sie durch null oder mehr Werte, die in der Argumentliste ange-
geben sind. Array-Elemente, die hinter der Einfügung oder Löschung stehen, werden derart verschoben, dass sie an den Rest des Arrays anschließen. Beachten Sie, dass splice( ) im Gegensatz zu der ähnlich klingenden Methode slice( ) das array unmittelbar modifiziert.
Beispiel Die Funktion von splice( ) lässt sich am besten an einem Beispiel erklären: var a = [1,2,3,4,5,6,7,8] a.splice(4); // Gibt a.splice(1,2); // Gibt a.splice(1,1); // Gibt a.splice(1,0,2,3); // Gibt
[5,6,7,8] zurück; a = [1,2,3,4] [2,3] zurück; a = [1,4] [] zurück; a ist [1] [] zurück; a ist [1 2 3]
666 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 667 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Array.toLocaleString( )
Siehe auch Array.slice( )
Array.toLocaleString( ) Konvertiert ein Array in einen lokalisierten String
Rückgabewert Eine lokalisierte String-Darstellung von array. Exceptions TypeError
Wenn diese Methode auf einem Objekt aufgerufen wird, das kein Array ist.
Beschreibung Die toLocaleString( )-Methode eines Arrays gibt eine lokalisierte String-Darstellung eines Arrays zurück. Dies macht sie, indem sie zuerst auf allen Array-Elementen die Methode toLocale-String( ) aufruft und dann die daraus resultierenden Strings verkettet, indem sie ein locale-spezifisches Trennzeichen dazwischensetzt.
Siehe auch Array.toString( ), Object.toLocaleString( )
Array.toString( ) Konvertiert ein Array in einen String
ECMAScript v1 Überschreibt Object.toString( )
Überblick array.toString( )
Rückgabewert Eine String-Darstellung von array. Exceptions TypeError
Wenn die Methode auf einem Objekt aufgerufen wird, das kein Array ist.
Beschreibung Die toString( )-Methode eines Arrays konvertiert ein Array in einen String und gibt diesen String zurück. Wird ein Array in einem String-Kontext benutzt, konvertiert JavaScript es auto-
Referenz für den Sprachkern von JavaScript |
667
491-0.book Seite 668 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Array.unshift( )
matisch in einen String, indem es diese Methode aufruft. In manchen Situationen sollten Sie aber dennoch toString( ) explizit aufrufen. Die Methode toString( ) konvertiert ein Array in einen String, indem sie zuerst jedes einzelne Array-Element (durch Aufruf seiner toString( )-Methode) in einen String umwandelt und diese Ergebnis-Strings dann in Form einer durch Kommata getrennten Liste ausgibt. Dieser Rückgabewert ist derselbe String, den auch ein parameterloser Aufruf der Methode join( ) zurückgeben würde.
Siehe auch Array.toLocaleString( ), Object.toString( )
Array.unshift( )
ECMAScript v3
Fügt am Array-Anfang Elemente ein
Überblick array.unshift(wert, ...)
Argumente wert, ...
Ein oder mehr Werte, die am Anfang von array eingefügt werden sollen. Rückgabewert Die neue Länge des Arrays.
Beschreibung Die Methode unshift( ) fügt ihre Argumente am Anfang von array ein und verschiebt dabei die vorhandenen Elemente auf nachfolgende Indexpositionen, um Platz zu schaffen. Das erste Argument von unshift( ) wird nun das Array-Element mit dem Index 0; das zweite Element wird, falls vorhanden, das Element 1 und so weiter. Beachten Sie, dass unshift( ) kein neues Array anlegt, sondern das vorhandene array unmittelbar modifiziert.
Beispiel unshift( ) wird oft zusammen mit shift( ) verwendet. Ein Beispiel: var a = []; a.unshift(1); a.unshift(22); a.shift( ); a.unshift(33,[4,5]);
// // // // //
a:[] a:[1] a:[22,1] a:[1] a:[33,[4,5],1]
Siehe auch Array.shift( )
668 | Referenz für den Sprachkern von JavaScript
Rückgabe: Rückgabe: Rückgabe: Rückgabe:
1 2 22 3
491-0.book Seite 669 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Boolean
Boolean Unterstützung für Boolesche Werte
ECMAScript v1 Object ➝ Boolean
Konstruktor new Boolean(wert) // Konstruktorfunktion Boolean(wert) // Konvertierungsfunktion
Argumente wert
Rückgabewert Wird die Funktion Boolean( ) als Konstruktor mit dem Operator new aufgerufen, so konvertiert sie ihr Argument in einen Booleschen Wert und gibt ein Boolean-Objekt zurück, das diesen Wert enthält. Wird sie als Funktion und ohne den new-Operator aufgerufen, konvertiert sie nur ihr Argument in einen Booleschen Wert und gibt diesen Wert zurück. Die Werte 0, NaN, null, leerer String "" und undefined werden alle in false konvertiert. Alle anderen elementaren Werte, mit Ausnahme von false (aber einschließlich des Strings »false«), sowie alle Objekte und Arrays werden in true konvertiert.
Methoden toString( )
Gibt je nach dem Booleschen Wert, den das Boolean-Objekt repräsentiert, true oder false zurück. valueOf( )
Gibt den elementaren Boolean-Wert zurück, der in dem Boolean-Objekt enthalten ist.
Beschreibung Boolean-Werte sind in JavaScript ein grundlegender Datentyp. Das Boolean-Objekt ist ein Wrapper-Objekt um den Booleschen Wert. Der Objekttyp Boolean ist vor allem dazu da, eine toString( )-Methode zu liefern, die Boolesche Werte in Strings konvertiert. Wird die toString( )-Methode aufgerufen, um einen Booleschen Wert in einen String zu konvertieren (und JavaScript ruft sie oft implizit auf), konvertiert JavaScript diesen Booleschen Wert intern in ein transientes Boolean-Objekt, auf dem die Methode aufgerufen werden kann.
Siehe auch Object
Referenz für den Sprachkern von JavaScript |
669
Referenz für den JavaScriptSprachkern
Der Wert, der vom Boolean-Objekt gespeichert oder in einen Booleschen Wert konvertiert werden soll.
491-0.book Seite 670 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Boolean.toString( )
Boolean.toString( ) Konvertiert einen Booleschen Wert in einen String
ECMAScript v1 Überschreibt Object.toString( )
Überblick b.toString( )
Rückgabewert Der String »true« oder »false«, je nachdem, welchen Wert der elementare Boolesche Wert oder das Boolean-Objekt b hat. Exceptions TypeError
Wenn diese Methode auf einem Objekt aufgerufen wird, das kein Boolean-Objekt ist.
Boolean.valueOf( ) Der Boolesche Wert eines Boolean-Objekts
ECMAScript v1 Überschreibt Object.valueOf( )
Überblick b.valueOf( )
Rückgabewert Der elementare Boolesche Wert, den das Boolean-Objekt b speichert. Exceptions TypeError
Wenn diese Methode auf einem Objekt aufgerufen wird, das kein Boolean-Objekt ist.
Wenn man ihn ohne Argumente aufruft, erzeugt der Konstruktor Date( ) ein Date-Objekt, das auf das heutige Datum und die momentane Uhrzeit eingestellt ist. Übergibt man ihm ein numerisches Argument, so wird dieses als eine interne, numerische Datumsdarstellung in Millisekunden betrachtet, wie sie von der Methode getTime( ) zurückgegeben wird. Wird ihm ein String-Argument übergeben, so handelt es sich um eine String-Darstellung eines Datums in einem Format, das die Methode Date.parse( ) akzeptiert. Andernfalls werden dem Konstruktor zwei bis sieben numerische Argumente übergeben, die die Inhalte der einzelnen Datums-
670 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 671 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date
und Uhrzeitfelder angeben. Alle außer den ersten beiden Argumenten (Jahr und Monat) sind optional. Beachten Sie, dass diese Datums- und Uhrzeitfelder in der Ortszeit und nicht in UTC (ähnlich wie GMT) spezifiziert werden. Eine Alternative finden Sie unter der statischen Methode Date.UTC( ). Date( ) kann auch als Funktion ohne den Operator new aufgerufen werden. Dann ignoriert Date( ) alle übergebenen Argumente und gibt eine String-Darstellung des heutigen Datums und
der Uhrzeit zurück. Argumente millisekunden
datumsstring
Ein einzelnes Argument, das das Datum und optional auch die Uhrzeit als String angibt. Der String sollte ein Format haben, das von Date.parse( ) akzeptiert wird. jahr
Das vierstellig angegebene Jahr. Für das Jahr 2002 geben Sie z.B. 2002 an. Wenn das Argument zwischen 0 und 99 liegt, wird aus Gründen der Kompatibilität zu Vorläuferimplementierungen von JavaScript 1900 hinzuaddiert. monat
Der Monat, angegeben als Integer zwischen 0 (Januar) und 11 (Dezember). tag
Der Tag des Monats, angegeben als Integer zwischen 1 und 31. Beachten Sie, dass dieses Argument 1 als kleinsten Wert verwendet, während andere Argumente 0 als kleinsten Wert haben. Optional. stunden
Die Stunde, angegeben als Integer zwischen 0 (Mitternacht) und 23 (elf Uhr nachts). Optional. minuten
Die Minuten einer Stunde, angegeben als Integer zwischen 0 und 59. Optional. sekunden
Die Sekunden der Minute, angegeben als Integer zwischen 0 und 59. Optional. ms
Die Millisekunden der Sekunde, angegeben als Integer zwischen 0 und 999. Optional.
Methoden Das Date-Objekt hat keine Eigenschaften, die unmittelbar gelesen und geschrieben werden können. Jeglicher Zugriff auf Datums- und Uhrzeitwerte erfolgt über Methoden. Die meisten Methoden des Date-Objekts haben zwei Formen: eine, die mit der Ortszeit arbeitet, und eine, die mit der Universalzeit (UTC oder GMT) arbeitet. Hat eine Methode den Begriff »UTC« im Namen, dann arbeitet sie mit der Universalzeit. Die Methodenpaare sind nachfolgend aufgelistet. Das Listing für get[UTC]Day( ) bezieht sich beispielsweise auf die beiden Methoden getDay( ) und getUTCDay( ).
Referenz für den Sprachkern von JavaScript |
671
Referenz für den JavaScriptSprachkern
Die Anzahl der Millisekunden zwischen dem gewünschten Datum und dem 1. Januar 1970 um Mitternacht (UTC). Wenn Sie z.B. das Argument 5000 übergeben, so würde ein Datum angelegt, das den Zeitpunkt fünf Sekunden nach Mitternacht am 01.01.1970 repräsentiert.
491-0.book Seite 672 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date
Datumsmethoden können nur auf Date-Objekten aufgerufen werden, und sie lösen bei jedem Versuch, sie auf einem anderen Objekttyp aufzurufen, eine TypeError-Exception aus. get[UTC]Date( )
Gibt den Monatstag eines Date-Objekts in Ortszeit oder Universalzeit zurück. get[UTC]Day( )
Gibt den Wochentag eines Date-Objekts in Ortszeit oder Universalzeit zurück. get[UTC]FullYear( )
Gibt das Jahr des Date-Objekts mit vier Ziffern in Orts- oder Universalzeit zurück. get[UTC]Hours( )
Gibt das Stundenfeld eines Date-Objekts in Ortszeit oder Universalzeit zurück. get[UTC]Milliseconds( )
Gibt das Millisekunden-Feld eines Date-Objekts in Ortszeit oder Universalzeit zurück. get[UTC]Minutes( )
Gibt das Minutenfeld eines Date-Objekts in Ortszeit oder Universalzeit zurück. get[UTC]Month( )
Gibt das Monatsfeld eines Date-Objekts in Ortszeit oder Universalzeit zurück. get[UTC]Seconds( )
Gibt das Sekundenfeld eines Date-Objekts in Ortszeit oder Universalzeit zurück. getTime( )
Gibt die interne Millisekundendarstellung eines Date-Objekts zurück. Beachten Sie, dass dieser Wert nicht von der Zeitzone abhängt und daher keine separate getUTCTime( )Methode vorhanden ist. getTimezoneOffset( )
Gibt die Differenz zwischen der Ortszeit- und der UTC-Darstellung dieses Datums in Minuten zurück. Der Rückgabewert hängt auch davon ab, ob zu dem angegebenen Datum Sommer- oder Winterzeit gilt. getYear( )
Gibt das Jahresfeld eines Date-Objekts zurück. Ist für veraltet erklärt worden. Man verwendet stattdessen getFullYear( ). set[UTC]Date( )
Setzt im Datum den Tag des Monatsfelds entweder in Ortszeit oder in Universalzeit. set[UTC]FullYear( )
Setzt das Jahr (und optional auch Monat und Tag) des Datums entweder in Ortszeit oder in Universalzeit. set[UTC]Hours( )
Setzt die Stunde (und optional die Felder für Minuten, Sekunden und Millisekunden) des Datums entweder in Ortszeit oder in Universalzeit. set[UTC]Milliseconds( )
Setzt das Millisekundenfeld eines Datums entweder in Ortszeit oder in Universalzeit. set[UTC]Minutes( )
Setzt das Minutenfeld (und optional die Felder für Sekunden und Millisekunden) eines Datums entweder in Ortszeit oder in Universalzeit.
672 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 673 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date set[UTC]Month( )
Setzt das Monatsfeld (und optional den Tag des Monats) eines Datums entweder in Ortszeit oder in Universalzeit. set[UTC]Seconds( )
Setzt das Sekundenfeld (und optional das Millisekundenfeld) eines Datums entweder in Ortszeit oder in Universalzeit. setTime( )
Setzt die Felder eines Date-Objekts im Millisekunden-Format. setYear( )
Setzt das Jahresfeld eines Date-Objekts. Heute verwendet man dafür setFullYear( ). Gibt einen String zurück, der den Datumsteil eines Datums in der lokal gültigen Zeitzone ausdrückt. toGMTString( )
Konvertiert ein Date-Objekt in einen String und verwendet dazu die GMT-Zeitzone. Heute verwendet man dafür toUTCString( ). toLocaleDateString( )
Gibt einen String zurück, der den Datumsteil des Datums repräsentiert. Er wird in Ortszeit im lokal üblichen Datumsformat ausgedrückt. toLocaleString( )
Konvertiert ein Date-Objekt in einen String und verwendet dazu die Ortszeit und das lokal übliche Datumsformat. toLocaleTimeString( )
Gibt einen String zurück, der den Uhrzeitteil des Datums repräsentiert, und verwendet dazu die Ortszeit und das lokal übliche Datumsformat. toString( )
Konvertiert ein Date-Objekt in einen String und verwendet dazu die Ortszeit. toTimeString( )
Gibt einen String zurück, der den Uhrzeitteil des Datums repräsentiert, und verwendet dazu die Ortszeit. toUTCString( )
Konvertiert ein Date-Objekt in einen String und verwendet dazu die Universalzeit. valueOf( )
Konvertiert ein Date-Objekt in sein internes Millisekundenformat.
Statische Methoden Neben den vielen bereits aufgeführten Instanzmethoden definiert das Date-Objekt auch zwei statische Methoden. Diese werden über den Date( )-Konstruktor und nicht über einzelne DateObjekte aufgerufen: Date.parse( )
Parst eine String-Darstellung von Datum und Uhrzeit und gibt die interne Millisekundendarstellung des betreffenden Datums zurück.
Referenz für den Sprachkern von JavaScript |
673
Referenz für den JavaScriptSprachkern
toDateString( )
491-0.book Seite 674 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date Date.UTC( )
Gibt die Millisekundendarstellung der UTC-Datums- und Uhrzeitangaben zurück.
Beschreibung Das Date-Objekt ist ein eingebauter Datentyp von JavaScript. Date-Objekte werden mit der Schreibweise new Date( ) erzeugt, die Sie weiter oben finden. Wenn Sie ein Date-Objekt erzeugt haben, dann stehen Ihnen etliche Methoden zur Verfügung, um auf diesem zu arbeiten. Mit den meisten dieser Methoden können Sie einfach nur die Felder, die das Objekt für Jahr, Monat, Tag, Stunde, Minute, Sekunde und Millisekunde hat, mit Werten versehen. Sie verwenden dazu entweder die Ortszeit oder UTC (Universalzeit oder GMT). Die Methode toString( ) und ihre Varianten konvertieren Datumswerte in Strings, die für Menschen lesbar sind. getTime( ) und setTime( ) konvertieren aus der und in die interne Darstellung des Date-Objekts, geben also die Anzahl der Millisekunden seit Mitternacht (GMT) am 1. Januar 1970 an. In diesem standardmäßigen Millisekundenformat stellt ein einziger Integer das Datum und die Uhrzeit dar, was Rechenoperationen mit dem Datum extrem vereinfacht. Der ECMAScript-Standard verlangt, dass das Date-Objekt in der Lage sein muss, jedes Datum und jede Uhrzeit von hundert Millionen Tagen vor bis hundert Millionen Tage nach dem 1.1.1970 millisekundengenau darzustellen. Da dieses Zeitintervall rund 273.785 Jahre beträgt, wird die Uhr von JavaScript bis zum Jahr 275755 problemlos laufen.
Beispiel Auf einem Date-Objekt können Sie mit einer Vielzahl von Methoden arbeiten: d = new Date( ); // Hole das aktuelle Datum samt Uhrzeit document.write('Wir haben den: ' + d.toLocaleDateString( ) + '. '); // document.write('Die Uhrzeit ist: ' + d.toLocaleTimeString( )); // var dayOfWeek = d.getDay( ); // var weekend = (dayOfWeek == 0) || (dayOfWeek == 6); //
Zeige Datum Zeige Uhrzeit Wochentag? Wochenende?
Das Date-Objekt wird auch oft dazu genutzt, die Millisekundendarstellung des jetzigen Zeitpunkts von einem anderen Zeitpunkt zu subtrahieren, um die Zeitspanne zwischen den beiden zu ermitteln. Das folgende clientseitige Beispiel zeigt zwei solche Anwendungen: today = new Date( ); // Notiere das heutige Datum christmas = new Date( ); // Hole ein Datum dieses Jahres christmas.setMonth(11); // Setze den Monat auf Dezember ... christmas.setDate(24); // und den Tag auf den 24. // // // if
Wenn Weihnachten noch nicht vorbei ist, berechne die Anzahl der Millisekunden von jetzt bis Weihnachten, konvertiere das in die Anzahl der Tage, und gib eine Nachricht aus. (today.getTime( ) < christmas.getTime( )) { difference = christmas.getTime( ) - today.getTime( ); difference = Math.floor(difference / (1000 * 60 * 60 * 24)); document.write('Nur noch ' + difference + ' Tage bis Weihnachten!
');
}
674 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 675 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.getDate( ) // ... hier kommt der Rest des HTML-Dokuments hin ... // Hier verwenden wir Date-Objekte zur Zeitmessung // Wir teilen durch 1000, um aus Millisekunden Sekunden zu machen now = new Date( ); document.write('
Es dauerte ' + (now.getTime( )-today.getTime( ))/1000 + 'Sekunden, diese Seite zu laden.');
Siehe auch
Date.getDate( )
ECMAScript v1
Gibt das Monatstag-Feld eines Date-Objekts zurück
Überblick date.getDate( )
Rückgabewert Der Tag des Monats, wie er von dem angegebenen Date-Objekt date spezifiziert wird, in Ortszeit. Die Rückgabewerte liegen zwischen 1 und 31.
Date.getDay( )
ECMAScript v1
Gibt das Wochentagsfeld eines Date-Objekts zurück
Überblick date.getDay( )
Rückgabewert Der Wochentag des angegebenen Date-Objekts date in Ortszeit. Die Rückgabewerte liegen zwischen 0 (Sonntag) und 6 (Samstag).
Date.getFullYear( )
ECMAScript v1
Gibt des Jahresfeld eines Date-Objekts zurück
Überblick date.getFullYear( )
Referenz für den Sprachkern von JavaScript |
675
Referenz für den JavaScriptSprachkern
Date.parse( ), Date.UTC( )
491-0.book Seite 676 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.getHours( )
Rückgabewert Das Jahr, das sich ergibt, wenn date in Ortszeit ausgedrückt wird. Der Rückgabewert ist eine Jahresangabe mit vier Ziffern, die das Jahrhundert einschließt, und keine Abkürzung mit zwei Ziffern.
Date.getHours( )
ECMAScript v1
Gibt das Stundenfeld zurück
Überblick date.getHours( )
Rückgabewert Das Stundenfeld des angegebenen Date-Objekts date in Ortszeit. Die Rückgabewerte liegen zwischen 0 (Mitternacht) und 23 (elf Uhr nachts).
Date.getMilliseconds( )
ECMAScript v1
Gibt das Millisekundenfeld zurück
Überblick date.getMilliseconds( )
Rückgabewert Das Millisekundenfeld eines date in Ortszeit.
Date.getMinutes( )
ECMAScript v1
Gibt das Minutenfeld zurück
Überblick date.getMinutes( )
Rückgabewert Das Minutenfeld des angegebenen Date-Objekts date in Ortszeit. Die Rückgabewerte liegen zwischen 0 und 59.
Date.getMonth( ) Gibt das Monatsfeld zurück
Überblick date.getMonth( )
676 | Referenz für den Sprachkern von JavaScript
ECMAScript v1
491-0.book Seite 677 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.getSeconds( )
Rückgabewert Das Monatsfeld des angegebenen Date-Objekts date in Ortszeit. Die Rückgabewerte liegen zwischen 0 (Januar) und 11 (Dezember).
Date.getSeconds( )
ECMAScript v1
Gibt das Sekundenfeld zurück
Überblick date.getSeconds( )
Date.getTime( )
ECMAScript v1
Gibt ein Date in Millisekunden zurück
Überblick date.getTime( )
Rückgabewert Die Millisekundendarstellung des angegebenen Date-Objekts date, d.h. die Anzahl der Millisekunden zwischen Mitternacht des 1.1.1970 (GMT) und dem durch date angegebenen Datums- und Uhrzeitwert.
Beschreibung getTime( ) konvertiert ein Datum und eine Uhrzeit in einen einzigen Integer. Das ist nützlich, wenn Sie zwei Date-Objekte vergleichen oder den Zeitraum zwischen zwei Zeitpunkten herausfinden möchten. Beachten Sie, dass die Millisekundendarstellung eines Datums zeitzonenunabhängig ist und dass daher auch keine Schwestermethode getUTCTime( ) existiert. Verwechseln Sie diese Methode bitte nicht mit den Methoden getDay( ) und getDate( ), die den Wochentag und den Tag des Monats zurückgeben.
Mit Date.parse( ) und Date.UTC( ) können Sie eine Datums- und Uhrzeitangabe in ihre Millisekundendarstellung konvertieren, ohne dafür extra ein Date-Objekt erzeugen zu müssen.
Siehe auch Date, Date.parse( ), Date.setTime( ), Date.UTC( )
Referenz für den Sprachkern von JavaScript |
677
Referenz für den JavaScriptSprachkern
Rückgabewert Das Sekundenfeld des angegebenen Date-Objekts date in Ortszeit. Die Rückgabewerte liegen zwischen 0 und 59.
491-0.book Seite 678 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.getTimezoneOffset( )
Date.getTimezoneOffset( )
ECMAScript v1
Ermittelt die Zeitdifferenz gegenüber GMT
Überblick date.getTimezoneOffset( )
Rückgabewert Die Differenz zwischen Greenwich Mean Time (GMT) und Ortszeit in Minuten.
Beschreibung getTimezoneOffset( ) gibt zurück, wie viele Minuten zwischen der GMT- oder UTC-Zeit und
der Ortszeit liegen. Letztlich verrät Ihnen diese Funktion, in welcher Zeitzone der JavaScriptCode läuft und ob dort am angegebenen date Sommerzeit oder Winterzeit gilt. Der Rückgabewert wird nicht in Stunden, sondern in Minuten bemessen, da manche Länder Zeitzonen haben, die sich nicht nach vollen Stundenintervallen richten.
Date.getUTCDate( )
ECMAScript v1
Gibt das Monatstag-Feld eines Date-Objekts zurück (Universalzeit)
Überblick date.getUTCDate( )
Rückgabewert Der Tag des Monats (ein Wert zwischen 1 und 31), der sich ergibt, wenn date in Universalzeit ausgedrückt wird.
Date.getUTCDay( )
ECMAScript v1
Gibt das Wochentagsfeld eines Date-Objekts zurück (Universalzeit)
Überblick date.getUTCDay( )
Rückgabewert Der Wochentag, der sich ergibt, wenn date in Universalzeit ausgedrückt wird. Die Rückgabewerte liegen zwischen 0 (Sonntag) und 6 (Samstag).
678 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 679 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.getUTCFullYear( )
Date.getUTCFullYear( )
ECMAScript v1
Gibt das Jahresfeld eines Date-Objekts zurück (Universalzeit)
Überblick date.getUTCFullYear( )
Rückgabewert Das Jahr, das sich ergibt, wenn date in Universalzeit ausgedrückt wird. Der Rückgabewert ist ein Jahr mit vier Ziffern und keine zweistellige Abkürzung.
ECMAScript v1
Gibt das Stundenfeld zurück (Universalzeit)
Überblick date.getUTCHours( )
Rückgabewert Das Stundenfeld von date in Universalzeit. Der Rückgabewert ist ein Integer zwischen 0 (Mitternacht) und 23 (elf Uhr nachts).
Date.getUTCMilliseconds( )
ECMAScript v1
Gibt das Millisekundenfeld zurück (Universalzeit)
Überblick date.getUTCMilliseconds( )
Rückgabewert Das Millisekundenfeld von date in Universalzeit.
Date.getUTCMinutes( )
ECMAScript v1
Gibt das Minutenfeld zurück (Universalzeit)
Überblick date.getUTCMinutes( )
Rückgabewert Das Minutenfeld von date in Universalzeit. Der Rückgabewert ist ein Integer zwischen 0 und 59.
Referenz für den Sprachkern von JavaScript |
679
Referenz für den JavaScriptSprachkern
Date.getUTCHours( )
491-0.book Seite 680 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.getUTCMonth( )
Date.getUTCMonth( )
ECMAScript v1
Gibt das Monat-des-Jahrs-Feld eines Date-Objekts zurück (Universalzeit)
Überblick date.getUTCMonth( )
Rückgabewert Der Monat des Jahres, der sich ergibt, wenn date in Universalzeit ausgedrückt wird. Der Rückgabewert ist ein Integer zwischen 0 (Januar) und 11 (Dezember). Beachten Sie, dass das DateObjekt den ersten Tag des Monats zwar als 1, aber den ersten Monat des Jahres als 0 darstellt.
Date.getUTCSeconds( )
ECMAScript v1
Gibt das Sekundenfeld zurück (Universalzeit)
Überblick date.getUTCSeconds( )
Rückgabewert Das Sekundenfeld von date in Universalzeit. Der Rückgabewert ist ein Integer zwischen 0 und 59.
Date.getYear( )
ECMAScript v1; veraltet seit ECMAScript v3
Gibt das Jahresfeld zurück
Überblick date.getYear( )
Rückgabewert Das Jahresfeld des angegebenen Date-Objekts date minus 1900.
Beschreibung getYear( ) gibt das Jahresfeld eines angegebenen Date-Objekts minus 1900 zurück. Seit ECMAScript v3 ist es für standardkonforme JavaScript-Implementierungen nicht mehr erforderlich. Verwenden Sie stattdessen getFullYear( ).
Date.parse( ) Parst einen Datums/Uhrzeit-String
Überblick Date.parse(date)
680 | Referenz für den Sprachkern von JavaScript
ECMAScript v1
491-0.book Seite 681 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.setDate( )
Argumente date
Ein String, der den zu parsenden Datums- und Uhrzeitwert enthält. Rückgabewert Die Anzahl Millisekunden zwischen dem angegebenen Zeitpunkt und Mitternacht des 1. Januar 1970 GMT.
Beschreibung
nimmt ein einziges String-Argument entgegen. Die Methode parst das darin enthaltene Datum und gibt es im Millisekundenformat zurück. Dieses Format kann entweder direkt benutzt werden, oder man verwendet es, um ein neues Date-Objekt zu erzeugen oder um das Datum in einem vorhandenen Date-Objekt mit der Methode Date.setTime( ) zu setzen. Der ECMAScript-Standard legt das Format der Strings nicht fest, die mit Date.parse( ) geparst werden. Er besagt lediglich, dass diese Methode die von Date.toString( ) und Date.toUTCString( ) zurückgegebenen Strings parsen kann. Leider formatieren diese Funktionen Datumswerte in einer implementierungsabhängigen Weise, sodass Datumsangaben generell nicht in einer Form geschrieben werden können, die auch garantiert von allen JavaScript-Implementierungen verstanden wird.
Siehe auch Date, Date.setTime( ), Date.toGMTString( ), Date.UTC( )
Date.setDate( )
ECMAScript v1
Setzt das Monatstag-Feld eines Date-Objekts
Überblick date.setDate(tag_des_monats)
Argumente tag_des_monats
Ein Integer zwischen 1 und 31, der als neuer (in Ortszeit ausgedrückter) Wert des Monatstag-Felds von date verwendet wird. Rückgabewert Die Millisekundendarstellung des angepassten Datums. Vor der ECMAScript-Standardisierung gab diese Methode gar nichts zurück.
Referenz für den Sprachkern von JavaScript |
681
Referenz für den JavaScriptSprachkern
Date.parse( ) ist eine statische Methode von Date. Sie wird immer als Date.parse( ) über den Date-Konstruktor und nicht als date.parse( ) über ein Date-Objekt aufgerufen. Date.parse( )
491-0.book Seite 682 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.setFullYear( )
Date.setFullYear( )
ECMAScript v1
Setzt das Jahr und optional den Monat und das Datum
Das Jahr in Ortszeit, das in date gesetzt werden soll. Dieses Argument sollte ein Integer sein, der auch das Jahrhundert angibt, also z.B. 1999. Es sollte keine Abkürzung wie 99 sein. monat
Ein optionaler Integer zwischen 0 und 11, der als neuer Wert (in Ortszeit) des Monatsfelds von date benutzt wird. tag
Ein optionaler Integer zwischen 1 und 31, der als neuer Wert (in Ortszeit) des MonatstagFelds von date benutzt wird. Rückgabewert Die interne Millisekundendarstellung des angepassten Datums.
Date.setHours( )
ECMAScript v1
Setzt die Felder für Stunden, Minuten, Sekunden und Millisekunden eines Date-Objekts
Ein Integer zwischen 0 (Mitternacht) und 23 (elf Uhr nachts) Ortszeit, der als neuer Stundenwert von date eingesetzt wird. minuten
Ein optionaler Integer zwischen 0 und 59, der als neuer Wert (in Ortszeit) des Minutenfelds von date verwendet wird. Dieses Argument wird erst seit der ECMAScriptStandardisierung unterstützt. sekunden
Ein optionaler Integer zwischen 0 und 59, der als neuer Wert (in Ortszeit) des Sekundenfelds von date verwendet wird. Dieses Argument wird erst seit der ECMAScriptStandardisierung unterstützt.
682 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 683 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.setMilliseconds( ) millis
Ein optionaler Integer zwischen 0 und 999, der als neuer Wert (in Ortszeit) des Millisekundenfelds von date verwendet wird. Dieses Argument wird erst seit der ECMAScriptStandardisierung unterstützt. Rückgabewert Die Millisekundendarstellung des angepassten Datums. Vor der ECMAScript-Standardisierung gab diese Methode nichts zurück.
Date.setMilliseconds( )
ECMAScript v1 Referenz für den JavaScriptSprachkern
Setzt das Millisekundenfeld eines Date-Objekts
Überblick date.setMilliseconds(millis)
Argumente millis
Das Millisekundenfeld (in Ortszeit), das in date gesetzt werden soll. Dieses Argument sollte ein Integer zwischen 0 und 999 sein. Rückgabewert Die Millisekundendarstellung des angepassten Datums.
Date.setMinutes( )
ECMAScript v1
Setzt die Felder für Minuten, Sekunden und Millisekunden eines Date-Objekts
Ein Integer zwischen 0 und 59, der als Minutenwert (in Ortszeit) des Date-Objekts date gesetzt wird. sekunden
Ein optionaler Integer zwischen 0 und 59, der als neuer Wert (in Ortszeit) des Sekundenfelds von date verwendet wird. Dieses Argument wurde vor der ECMAScript-Standardisierung nicht unterstützt. millis
Ein optionaler Integer zwischen 0 und 999, der als neuer Wert (in Ortszeit) des Millisekundenfelds von date verwendet wird. Dieses Argument wurde vor der ECMAScriptStandardisierung nicht unterstützt.
Referenz für den Sprachkern von JavaScript |
683
491-0.book Seite 684 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.setMonth( )
Rückgabewert Die Millisekundendarstellung des angepassten Datums. Vor der ECMAScript-Standardisierung gab diese Methode nichts zurück.
Date.setMonth( )
ECMAScript v1
Setzt die Felder für Monat und Tag eines Date-Objekts
Ein Integer zwischen 0 (Januar) und 11 (Dezember), der als Monatswert (in Ortszeit) für das Date-Objekt date gesetzt wird. Beachten Sie, dass Monate beginnend mit 0 und Monatstage beginnend mit 1 nummeriert werden. tag
Ein optionaler Integer zwischen 1 und 31, der als neuer Wert (in Ortszeit) des MonatstagFelds von date verwendet wird. Dieses Argument wurde vor der ECMAScript-Standardisierung nicht unterstützt. Rückgabewert Die Millisekundendarstellung des angepassten Datums. Vor der ECMAScript-Standardisierung gab diese Methode nichts zurück.
Date.setSeconds( )
ECMAScript v1
Setzt die Felder für Sekunden und Millisekunden eines Date
Ein Integer zwischen 0 und 59, der als Sekundenwert für das Date-Objekt date gesetzt wird. millis
Ein optionaler Integer zwischen 0 und 999, der als neuer Wert (in Ortszeit) für das Millisekundenfeld von date verwendet wird. Dieses Argument wurde vor der ECMAScriptStandardisierung nicht unterstützt. Rückgabewert Die Millisekundendarstellung des angepassten Datums. Vor der ECMAScript-Standardisierung gab diese Methode nichts zurück.
684 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 685 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.setTime( )
Date.setTime( )
ECMAScript v1
Setzt ein Date in Millisekunden
Überblick date.setTime(millisekunden)
Argumente millisekunden
Rückgabewert Das Argument millisekunden. Vor der ECMAScript-Standardisierung gab diese Methode nichts zurück.
Date.setUTCDate( )
ECMAScript v1
Setzt das Monatstag-Feld eines Date-Objekts (Universalzeit)
Überblick date.setUTCDate(tag_des_monats)
Argumente tag_des_monats
Der Monatstag in Universalzeit, der in date gesetzt werden soll. Dieses Argument sollte ein Integer zwischen 1 und 31 sein. Rückgabewert Die interne Millisekundendarstellung des angepassten Datums.
Date.setUTCFullYear( )
ECMAScript v1
Setzt Jahr, Monat und Tag eines Date-Objekts (Universalzeit)
Das Jahr in Universalzeit, das in date gesetzt werden soll. Dieses Argument sollte ein Integer sein, der auch das Jahrhundert einschließt, z.B. 1999, und keine Abkürzung wie etwa 99.
Referenz für den Sprachkern von JavaScript |
685
Referenz für den JavaScriptSprachkern
Die Anzahl der Millisekunden zwischen dem gewünschten Zeitpunkt und Mitternacht des 1. Januar 1970 GMT. Ein Millisekundenwert dieses Typs kann auch dem Date( )Konstruktor übergeben und durch Aufruf der Methoden Date.UTC( ) und Date.parse( ) beschafft werden. Wenn Sie ein Datum in diesem Millisekundenformat darstellen, machen Sie es zeitzonenunabhängig.
491-0.book Seite 686 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.setUTCHours( ) monat
Ein optionaler Integer zwischen 0 und 11, der als neuer (Universalzeit-)Wert des Monatsfelds von date verwendet wird. Beachten Sie, dass die Nummerierung von Monaten bei 0 beginnt, während die Nummerierung von Monatstagen mit 1 beginnt. tag
Ein optionaler Integer zwischen 1 und 31, der als neuer (Universalzeit-)Wert des Monatstag-Felds von date verwendet wird. Rückgabewert Die interne Millisekundendarstellung des angepassten Datums.
Date.setUTCHours( )
ECMAScript v1
Setzt die Felder für Stunden, Minuten, Sekunden und Millisekunden eines Date-Objekts (Universalzeit)
Das Stundenfeld in Universalzeit, das in date gesetzt werden soll. Dieses Argument sollte ein Integer zwischen 0 (Mitternacht) und 23 (elf Uhr nachts) sein. minuten
Ein optionaler Integer zwischen 0 und 59, der als neuer Wert (in Universalzeit) des Minutenfelds von date verwendet wird. seconds
Ein optionaler Integer zwischen 0 und 59, der als neuer Wert (in Universalzeit) des Sekundenfelds von date verwendet wird. millis
Ein optionaler Integer zwischen 0 und 999, der als neuer Wert (in Universalzeit) des Millisekundenfelds von date verwendet wird. Rückgabewert Die Millisekundendarstellung des angepassten Datums.
Date.setUTCMilliseconds( ) Setzt das Millisekundenfeld eines Date-Objekts (Universalzeit)
Überblick date.setUTCMilliseconds(millis)
686 | Referenz für den Sprachkern von JavaScript
ECMAScript v1
491-0.book Seite 687 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.setUTCMinutes( )
Argumente millis
Das Millisekundenfeld in Universalzeit, das in date gesetzt werden soll. Dieses Argument sollte ein Integer zwischen 0 und 999 sein. Rückgabewert Die Millisekundendarstellung des angepassten Datums.
Date.setUTCMinutes( )
ECMAScript v1
Setzt die Felder für Minuten, Sekunden und Millisekunden eines Date-Objekts (Universalzeit) Referenz für den JavaScriptSprachkern
Das Minutenfeld in Universalzeit, das in date gesetzt werden soll. Dieses Argument sollte ein Integer zwischen 0 und 59 sein. sekunden
Ein optionaler Integer zwischen 0 und 59, der als der neue Wert (in Universalzeit) des Sekundenfelds von date verwendet wird. millis
Ein optionaler Integer zwischen 0 und 999, der als der neue Wert (in Universalzeit) des Millisekundenfelds von date verwendet wird. Rückgabewert Die Millisekundendarstellung des angepassten Datums.
Date.setUTCMonth( )
ECMAScript v1
Setzt die Felder für Monat und Tag eines Date-Objekts (Universalzeit)
Der Monat in Universalzeit, der in date gesetzt werden soll. Dieses Argument sollte ein Integer zwischen 0 (Januar) und 11 (Dezember) sein. Beachten Sie, dass die Monate beginnend mit 0 und die Monatstage beginnend mit 1 nummeriert sind.
Referenz für den Sprachkern von JavaScript |
687
491-0.book Seite 688 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.setUTCSeconds( ) tag
Ein optionaler Integer zwischen 1 und 31, der als neuer Wert (in Universalzeit) des Monatstag-Felds von date benutzt wird. Rückgabewert Die Millisekundendarstellung des angepassten Datums.
Date.setUTCSeconds( )
ECMAScript v1
Setzt die Felder für Sekunden und Millisekunden eines Date-Objekts (Universalzeit)
Das Sekundenfeld in Universalzeit, das in date gesetzt werden soll. Dieses Argument sollte ein Integer zwischen 0 und 59 sein. millis
Ein optionaler Integer zwischen 0 und 999, der als neuer Wert (in Universalzeit) des Millisekundenfelds von date benutzt wird. Rückgabewert Die Millisekundendarstellung des angepassten Datums.
Date.setYear( )
ECMAScript v1; veraltet seit ECMAScript v3
Setzt das Jahresfeld eines Date-Objekts
Überblick date.setYear(jahr)
Argumente jahr
Ein Integer, der als Jahreswert (in Ortszeit) für das Date-Objekt date gesetzt wird. Wenn dieser Wert zwischen 0 und einschließlich 99 liegt, wird 1900 hinzuaddiert, und der Wert wird als Jahr zwischen 1900 und 1999 behandelt. Rückgabewert Die Millisekundendarstellung des angepassten Datums. Vor der ECMAScript-Standardisierung gab diese Methode nichts zurück.
688 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 689 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.toDateString( )
Beschreibung setYear( ) setzt das Jahresfeld eines angegebenen Date-Objekts und bietet für die Jahre 1900 bis 1999 ein spezielles Verhalten.
Seit ECMAScript v3 ist diese Funktion für standardkonforme JavaScript-Implementierungen nicht mehr erforderlich. Verwenden Sie stattdessen setFullYear( ).
Date.toDateString( )
ECMAScript v3
Gibt den Datumsteil eines Date-Objekts als String zurück
date.toDateString( )
Rückgabewert Eine implementierungsabhängige, für Menschen lesbare Darstellung des Datumsteils von date, ausgedrückt in Ortszeit.
Siehe auch Date.toLocaleDateString( ), Date.toLocaleString( ), String( ), Date.toTimeString( )
Date.toGMTString( )
Date.toLocaleTimeString( ),
Date.to
ECMAScript v1; veraltet seit ECMAScript v3
Konvertiert ein Date-Objekt in einen Universalzeit-String
Überblick date.toGMTString( )
Rückgabewert Eine String-Darstellung des Zeitpunkts, der durch das Date-Objekt date spezifiziert ist. Das Datum wird von der Ortszeit in GMT konvertiert, bevor es in einen String umgewandelt wird.
Beschreibung toGMTString( ) wurde durch die identische Methode Date.toUTCString( ) ersetzt.
Seit ECMAScript v3 brauchen standardkonforme JavaScript-Implementierungen diese Methode nicht mehr zur Verfügung zu stellen. Verwenden Sie stattdessen toUTCString( ).
Siehe auch Date.toUTCString( )
Referenz für den Sprachkern von JavaScript |
689
Referenz für den JavaScriptSprachkern
Überblick
491-0.book Seite 690 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.toLocaleDateString( )
Date.toLocaleDateString( )
ECMAScript v3
Gibt den Datumsteil eines Date-Objekts als String im ortsüblichen Format aus
Überblick date.toLocaleDateString( )
Rückgabewert Eine implementierungsabhängige, für Menschen lesbare Darstellung des Datumsteils von date in Ortszeit und im ortsüblichen Format.
Siehe auch Date.toDateString( ), Date.toTimeString( )
Date.toLocaleString( ),
Date.toLocaleTimeString( ),
Date.toLocaleString( )
Date.toString( ),
ECMAScript v1
Konvertiert ein Date-Objekt in einen String im ortsüblichen Format
Überblick date.toLocaleString( )
Rückgabewert Eine String-Darstellung des durch date spezifizierten Zeitpunkts. Datum und Uhrzeit werden in Ortszeit und im ortsüblichen Format dargestellt.
Verwendung toLocaleString( ) konvertiert ein Datum gemäß der Ortszeit in einen String. Außerdem hält
sich diese Methode bei der Formatierung von Datum und Uhrzeit an die lokalen Gepflogenheiten, sodass sich das Format von Plattform zu Plattform und von Land zu Land ändern kann. toLocaleString( ) gibt den String zurück, der wahrscheinlich dem vom Benutzer bevorzugten Datums- und Uhrzeitformat entspricht.
Siehe auch Date.toLocaleDateString( ), Date.toLocaleTimeString( ), Date.toString( ), Date.toUTCString( )
Date.toLocaleTimeString( ) Gibt den Uhrzeitteil eines Date-Objekts als String im ortsüblichen Format zurück
Überblick date.toLocaleTimeString( )
690 | Referenz für den Sprachkern von JavaScript
ECMAScript v3
491-0.book Seite 691 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.toString( )
Rückgabewert Eine implementierungsabhängige, für Menschen lesbare Darstellung des Uhrzeitteils von date in Ortszeit und im ortsüblichen Format.
Siehe auch Date.toDateString( ), Date.toTimeString( )
Date.toLocaleDateString( ),
Date.toLocaleString( ),
Date.toString( )
Date.toString( ),
ECMAScript v1 Überschreibt Object.toString( )
Überblick date.toString( )
Rückgabewert Eine für Menschen lesbare String-Darstellung von date in Ortszeit.
Beschreibung toString( ) gibt eine für Menschen lesbare, implementierungsabhängige String-Darstellung von date zurück. Im Gegensatz zu toUTCString( ) drückt toString( ) das Datum in Ortszeit aus, und im Gegensatz zu toLocaleString( ) gibt toString( ) das Datum und die Uhrzeit möglicherweise
nicht in einem locale-spezifischen Format zurück.
Siehe auch Date.parse( ), toUTCString( )
Date.toDateString( ),
Date.toLocaleString( ),
Date.toTimeString( ),
Date.toTimeString( )
Date.
ECMAScript v3
Gibt den Uhrzeitteil eines Date-Objekts als String zurück
Überblick date.toTimeString( )
Rückgabewert Eine implementierungsabhängige, für Menschen lesbare String-Darstellung des Uhrzeitteils eines date, ausgedrückt in Ortszeit.
Siehe auch Date.toString( ), Date.toDateString( ), Date.toLocaleTimeString( )
Date.toLocaleDateString( ),
Date.toLocaleString( ),
Referenz für den Sprachkern von JavaScript |
691
Referenz für den JavaScriptSprachkern
Konvertiert ein Date-Objekt in einen String
491-0.book Seite 692 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.toUTCString( )
Date.toUTCString( )
ECMAScript v1
Konvertiert ein Date-Objekt in einen String (Universalzeit)
Überblick date.toUTCString( )
Rückgabewert Eine für Menschen lesbare String-Darstellung von date in Universalzeit.
Beschreibung toUTCString( ) gibt einen implementierungsabhängigen String zurück, der date in Universalzeit
darstellt.
Siehe auch Date.toLocaleString( ), Date.toString( )
Vierstellige Jahresangabe. Wenn dieses Argument zwischen 0 und einschließlich 99 liegt, wird 1900 hinzuaddiert, und es wird als eine Jahreszahl zwischen 1900 und 1999 behandelt. monat
Der Monat als Integer zwischen 0 (Januar) und 11 (Dezember). tag
Der Monatstag als Integer zwischen 1 und 31. Beachten Sie, dass dieses Argument als kleinsten Wert 1 verwendet, während andere Argumente 0 als kleinsten Wert haben. Dieses Argument ist optional. stunden
Die Stunde als Integer zwischen 0 (Mitternacht) und 23 (elf Uhr nachts). Dieses Argument ist optional. minuten
Die Minuten der Stunde, angegeben als Integer zwischen 0 und 59. Dieses Argument ist optional. sekunden
Die Sekunden der Minute, angegeben als Integer zwischen 0 und 59. Dieses Argument ist optional.
692 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 693 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Date.valueOf( ) ms
Die Anzahl der Millisekunden, angegeben als Integer zwischen 0 und 999. Dieses Argument ist optional und wird erst seit der ECMAScript-Standardisierung berücksichtigt. Rückgabewert Die Millisekundendarstellung des angegebenen Zeitpunkts in Universalzeit. Folglich gibt diese Methode die Millisekunden zurück, die zwischen Mitternacht am 1. Januar 1970 GMT und dem angegebenen Zeitpunkt verstrichen sind.
Beschreibung Date.UTC( ) ist eine statische Methode, die über den Date( )-Konstruktor und nicht über ein
Die Argumente von Date.UTC( ) geben ein Datum und eine Uhrzeit an und werden als UTC (Universal Coordinated Time) interpretiert, also als GMT-Zeitangabe. Die angegebene UTCZeit wird in das Millisekundenformat konvertiert, das von der Konstruktormethode Date( ) und der Methode Date.setTime( ) verstanden wird. Die Konstruktormethode Date( ) kann dieselben Datums- und Uhrzeitargumente entgegennehmen wie Date.UTC( ). Der Unterschied besteht darin, dass der Konstruktor Date( ) von der Ortszeit ausgeht, während Date.UTC( ) die Universalzeit (GMT) zugrunde legt. Mit Code wie diesem können Sie ein Date-Objekt anlegen, das eine UTC-Zeitangabe verwendet: d = new Date(Date.UTC(1996, 4, 8, 16, 30));
Siehe auch Date, Date.parse( ), Date.setTime( )
Date.valueOf( ) Konvertiert ein Date-Objekt in Millisekunden
ECMAScript v1 Überschreibt Object.valueOf( )
Überblick date.valueOf( )
Rückgabewert Die Millisekundendarstellung von date. Der Rückgabewert ist derselbe wie bei Date. getTime( ).
decodeURI( )
ECMAScript v3
Entfernt Escape-Zeichen aus einer URI
Überblick decodeURI(uri)
Referenz für den Sprachkern von JavaScript |
693
Referenz für den JavaScriptSprachkern
einzelnes Date-Objekt aufgerufen wird.
491-0.book Seite 694 Mittwoch, 4. April 2007 9:55 09
e-bol.net
decodeURIComponent( )
Argumente uri
Ein String, der eine codierte URI oder einen anderen Text enthält, der decodiert werden soll. Rückgabewert Eine Kopie von uri, in der hexadezimale Escape-Sequenzen durch die von diesen dargestellten Zeichen ersetzt wurden. Exceptions URIError
Besagt, dass eine oder mehrere Escape-Sequenzen in uri nicht wohlgeformt sind und daher nicht korrekt decodiert werden können.
Beschreibung decodeURI( ) ist eine globale Funktion, die eine decodierte Kopie ihres uri-Arguments zurückliefert. Sie macht die von encodeURI( ) vorgenommene Codierung rückgängig. Weitere Einzelheiten finden Sie unter encodeURI( ).
Argumente s Ein String, der einen codierten URI-Bestandteil oder anderen zu decodierenden Text enthält. Rückgabewert Eine Kopie von s, in der hexadezimale Escape-Sequenzen durch die Zeichen ersetzt werden, die sie repräsentieren. Exceptions URIError
Zeigt an, dass eine oder mehrere der Escape-Sequenzen in s nicht wohlgeformt sind und daher auch nicht korrekt decodiert werden können.
694 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 695 Mittwoch, 4. April 2007 9:55 09
e-bol.net
encodeURI( )
Beschreibung decodeURIComponent( ) ist eine globale Funktion, die eine decodierte Kopie ihres Arguments s zurückgibt. Sie macht die von encodeURIComponent( ) vorgenommene Codierung rückgängig. Näheres dazu finden Sie im Referenzeintrag zu encodeURIComponent( ).
ECMAScript v3 Referenz für den JavaScriptSprachkern
Ersetzt Zeichen in einer URI durch Escape-Sequenzen
Überblick encodeURI(uri)
Argumente uri
Ein String, der die URI oder einen anderen zu codierenden Text enthält. Rückgabewert Eine Kopie von uri, in der bestimmte Zeichen durch hexadezimale Escape-Sequenzen ersetzt wurden. Exceptions URIError
Zeigt an, dass uri nicht-wohlgeformte Unicode-Surrogatpaare enthält und nicht codiert werden kann.
Beschreibung encodeURI( ) ist eine globale Funktion, die eine codierte Kopie ihres uri-Arguments zurückgibt.
ASCII-Buchstaben und Ziffern werden ebenso wenig codiert wie die folgenden ASCIIInterpunktionszeichen: - _ . ! ~ * ' ( )
Da encodeURI( ) dafür gedacht ist, vollständige URIs zu codieren, werden auch die folgenden ASCII-Interpunktionszeichen, die in URIs eine Sonderbedeutung haben, nicht mit EscapeZeichen versehen: ; / ? : @ & = + $ , #
Alle anderen Zeichen in uri werden ersetzt, indem jedes Zeichen in seine UTF-8-Codierung konvertiert und dann jedes der resultierenden ein, zwei oder drei Bytes durch eine hexadezimale Escape-Sequenz der Form %xx codiert wird. Bei diesem Codierschema werden ASCIIZeichen durch eine einzige Escape-Sequenz der Form %xx ersetzt. Zeichen mit einer Codierung zwischen \u0080 und \u07ff werden durch zwei Escape-Sequenzen ersetzt, und alle anderen 16Bit-Unicode-Zeichen werden durch drei Escape-Sequenzen ersetzt.
Referenz für den Sprachkern von JavaScript |
695
491-0.book Seite 696 Mittwoch, 4. April 2007 9:55 09
e-bol.net
encodeURIComponent( )
Wenn Sie eine URI mit dieser Methode codieren, müssen Sie ganz sicher sein, dass keine der URI-Komponenten (wie z.B. der Abfrage-String) URI-Trennzeichen wie etwa ? oder # enthält. Wenn die Bestandteile solche Zeichen enthalten müssen, sollten Sie jeden Bestandteil separat mit encodeURIComponent( ) codieren. Mit decodeURI( ) können Sie die Codierung, die diese Methode vornimmt, rückgängig machen. Vor der ECMAScript v3-Standardisierung konnten Sie die (mittlerweile veralteten) Methoden escape( ) und unescape( ) verwenden, um eine ähnliche Codierung und Decodierung vorzunehmen.
Beispiel // Rückgabe: http://www.isp.com/app.cgi?arg1=1&arg2=hello%20world encodeURI("http://www.isp.com/app.cgi?arg1=1&arg2=hello world"); encodeURI("\u00a9"); // Das Copyright-Zeichen wird als %C2%A9 codiert
Ersetzt Zeichen in einem URI-Bestandteil durch Escape-Sequenzen
Überblick encodeURIComponent(s)
Argumente s Ein String, der einen Teil einer URI oder eines anderen zu codierenden Texts enthält. Rückgabewert Eine Kopie von s, in der bestimmte Zeichen durch hexadezimale Escape-Sequenzen ersetzt wurden. Exceptions URIError
Zeigt an, dass s nicht-wohlgeformte Unicode-Surrogatpaare enthält und nicht codiert werden kann.
Beschreibung encodeURIComponent( ) ist eine globale Funktion, die eine codierte Kopie ihres Arguments s
zurückgibt. ASCII-Buchstaben und Ziffern werden ebenso wenig codiert wie die folgenden ASCII-Interpunktionszeichen: - _ . ! ~ * ' ( )
Alle anderen Zeichen einschließlich der Interpunktionszeichen wie /, : und #, mit denen die einzelnen URI-Bestandteile voneinander getrennt werden, werden durch eine oder mehrere hexadezimale Escape-Sequenzen ersetzt. Unter encodeURI( ) finden Sie eine Beschreibung des verwendeten Codierungsschemas.
696 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 697 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Error
Es gibt einen Unterschied zwischen encodeURIComponent( ) und encodeURI( ): Die Methode encodeURIComponent( ) geht davon aus, dass ihr Argument ein Teil einer URI ist (z.B. Protokoll, Hostname, Pfad oder Abfrage-String). Daher setzt sie für die Interpunktionszeichen, die als Trennzeichen zwischen den einzelnen Teilen einer URI dienen, Escape-Sequenzen ein.
Eine optionale Fehlermeldung, die Einzelheiten über die Exception mitteilt. Rückgabewert Ein neu erzeugtes Error-Objekt. Wenn das Argument meldung angegeben ist, verwendet das Error-Objekt dieses als Wert seiner message-Eigenschaft. Andernfalls verwendet es als Wert dieser Eigenschaft einen implementierungsabhängigen Standard-String. Wenn der Error( )Konstruktor als Funktion ohne den new-Operator aufgerufen wird, verhält er sich genauso, wie wenn er mit dem new-Operator aufgerufen wird.
Eigenschaften message
Eine Fehlermeldung, die Einzelheiten über die Exception angibt. Diese Eigenschaft speichert den String, der an den Konstruktor übergeben wurde, oder einen implementierungsspezifischen Standard-String. name
Ein String, der den Exception-Typ angibt. Bei Instanzen der Klasse Error und ihrer Unterklassen gibt diese Eigenschaft den Namen des Konstruktors an, mit dem die Instanz erzeugt wurde.
Methoden toString( )
Gibt einen je nach Implementierung definierten String zurück, der dieses Error-Objekt repräsentiert.
Referenz für den Sprachkern von JavaScript |
697
Referenz für den JavaScriptSprachkern
Error
491-0.book Seite 698 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Error.message
Beschreibung Instanzen der Klasse Error stellen Fehler oder Exceptions dar, die in der Regel zusammen mit den Anweisungen throw und try/catch benutzt werden. Die Eigenschaft name gibt den Exception-Typ an, und mit der Eigenschaft message können Sie Einzelheiten über den Fehler in einer für Menschen lesbaren Form angeben. Der JavaScript-Interpreter löst nie ein Error-Objekt direkt aus, sondern verwendet immer Instanzen einer Unterklasse von Error, also beispielsweise SyntaxError oder RangeError. Bequem ist es, in eigenem Code Exceptions durch die Auslösung von Error-Objekten zu signalisieren oder einfach nur eine Fehlermeldung oder einen Fehlercode als String bzw. numerischen Grundtyp auszulösen. Beachten Sie, dass die ECMAScript-Spezifikation eine toString( )-Methode für die Klasse Error definiert (die von allen Unterklassen von Error geerbt wird). Die Spezifikation fordert jedoch nicht, dass diese toString( )-Methode einen String mit dem Inhalt der Eigenschaft message zurückgibt. Daher dürfen Sie nicht davon ausgehen, dass toString( ) ein Error-Objekt in einen für Menschen lesbaren String konvertiert. Um einem Benutzer eine Fehlermeldung anzuzeigen, sollten Sie explizit die Eigenschaften name und message des Error-Objekts verwenden.
Beispiel Eine Exception können Sie mit Code wie diesem signalisieren: function factorial(x) { if (x < 0) throw new Error("factorial: x muss >= 0 sein"); if (x auf Strings angewendet werden, vergleichen sie diese Strings anhand der Unicode-Codierungen der Zeichen und lassen die Sortierreihenfolge gemäß dem örtlichen Locale außer acht. Auf diese Weise erhält man nicht immer die richtige Reihenfolge. In Spanien werden z.B. die Buchstaben »ch« traditionell so eingeordnet, als seien sie ein einzelner Buchstabe, der zwischen den Buchstaben »c« und »d« steht. localeCompare( ) bietet eine Möglichkeit, Strings in einer Weise zu vergleichen, die die Sortier-
reihenfolge gemäß dem örtlichen Locale berücksichtigt. Der ECMAScript-Standard sagt nicht, wie der locale-spezifische Vergleich vorgenommen werden soll, sondern verlangt nur, dass diese Funktion die Sortierreihenfolge anwendet, die das zugrunde liegende Betriebssystem vorgibt.
Beispiel Mit Code wie diesem können Sie ein String-Array in eine locale-spezifische Reihenfolge bringen: var strings; // Das zu sortierende String-Array; anderswo initialisiert strings.sort(function(a,b) { return a.localeCompare(b) });
762 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 763 Mittwoch, 4. April 2007 9:55 09
e-bol.net
String.match( )
String.match( )
ECMAScript v3
Sucht eine oder mehrere Übereinstimmungen mit einem regulären Ausdruck
Überblick string.match(regexp)
Argumente regexp
Rückgabewert Ein Array mit den Ergebnissen der Mustererkennung. Der Array-Inhalt hängt davon ab, ob regexp das globale Attribut »g« hat. In der Beschreibung finden Sie noch mehr Einzelheiten über den Rückgabewert.
Beschreibung match( ) sucht im string nach einem oder mehreren Auftreten von regexp. Das Verhalten dieser Methode hängt stark davon ab, ob regexp das Attribut »g« hat oder nicht. In Kapitel 11 finden Sie Erläuterungen zu regulären Ausdrücken.
Wenn regexp nicht das Attribut »g« hat, sucht match( ) in string nach einer einzigen Übereinstimmung. Ist keine zu finden, gibt match( ) den Wert null zurück. Andernfalls wird ein Array mit Informationen über die gefundene Übereinstimmung zurückgegeben. Das Array-Element 0 enthält den übereinstimmenden Text, und die übrigen Elemente enthalten Text, der mit eventuell vorhandenen, in Klammern stehenden Teilausdrücken in dem regulären Ausdruck übereinstimmt. Zusätzlich zu diesen normalen Array-Elementen hat das Rückgabe-Array auch zwei Objekteigenschaften. Die Eigenschaft index des Arrays gibt an, an welcher Zeichenposition in string der übereinstimmende Text beginnt, und die Eigenschaft input des RückgabeArrays ist eine Referenz auf string selbst. Wenn regexp das Flag »g« hat, führt die Methode match( ) eine globale Suche durch, indem sie string nach allen passenden Teilstrings durchsucht. Wenn keiner gefunden wird, ist die Rückgabe null, und wenn eine oder mehrere Übereinstimmungen gefunden werden, ist die Rückgabe ein Array. Der Inhalt dieses Rückgabe-Arrays ist allerdings ganz anders als bei globalen Mustererkennungen. Hier enthalten die Array-Elemente alle Teilstrings, die in string eine Übereinstimmung erbracht haben. Das Rückgabe-Array hat in diesem Fall nicht die Eigenschaften index oder input. Beachten Sie, dass match( ) bei globalen Mustererkennungen weder etwas über in Klammern stehende Teilausdrücke aussagt noch angibt, wo in string die einzelnen Übereinstimmungen aufgetreten sind. Wenn Sie für eine globale Suche diese Informationen benötigen, müssen Sie RegExp.exec( ) verwenden.
Beispiel Die folgende globale Mustererkennung findet alle Zahlen in einem String: "1 plus 2 gleich 3".match(/\d+/g)
// Rückgabe ["1", "2", "3"]
Referenz für den Sprachkern von JavaScript |
763
Referenz für den JavaScriptSprachkern
Ein RegExp-Objekt, das das zu erkennende Muster angibt. Ist dieses Argument kein RegExp-Objekt, wird es zunächst durch Übergabe an den RegExp( )-Konstruktor in ein solches konvertiert.
491-0.book Seite 764 Mittwoch, 4. April 2007 9:55 09
e-bol.net
String.replace( )
Die folgende, nicht-globale Mustererkennung verwendet einen komplexeren regulären Ausdruck mit mehreren in Klammern stehenden Teilausdrücken. Er erkennt eine URL, und seine Teilausdrücke erkennen die einzelnen URL-Teile für das Protokoll, den Host und den Pfad: var url = /(\w+):\/\/([\w.]+)\/(\S*)/; var text = "Visit my home page at http://www.isp.com/~david"; var result = text.match(url); if (result != null) { var fullurl = result[0]; // Enthält "http://www.isp.com/~david" var protocol = result[1]; // Enthält "http" var host = result[2]; // Enthält "www.isp.com" var path = result[3]; // Enthält "~david" }
Ersetzt zu einem regulären Ausdruck passende(n) Teilstring(s)
Überblick string.replace(regexp, ersatz)
Argumente regexp
Das RegExp-Objekt, das das zu ersetzende Muster angibt. Wenn dieses Argument ein String ist, wird es wie ein zu suchendes wörtliches Textmuster behandelt und nicht erst in ein RegExp-Objekt konvertiert. ersatz
Ein String, der den Ersetzungstext spezifiziert, oder eine Funktion, die aufgerufen wird, um den Ersetzungstext zu generieren. Einzelheiten finden Sie im Abschnitt »Beschreibung«. Rückgabewert Ein neuer String, in dem die erste oder alle Übereinstimmungen mit regexp durch ersatz ersetzt wurden.
Beschreibung replace( ) führt eine Suchen-und-ersetzen-Operation auf string aus. Sie sucht in string einen oder mehrere Teilstrings, die mit regexp übereinstimmen, und ersetzt sie durch ersatz. Wenn regexp das globale Attribut »g« hat, ersetzt replace( ) alle passenden Teilstrings. Andernfalls
ersetzt die Methode nur den ersten passenden Teilstring.
764 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 765 Mittwoch, 4. April 2007 9:55 09
e-bol.net
String.replace( ) ersatz kann ein String oder eine Funktion sein. Ist er ein String, so wird jede Übereinstimmung durch diesen String ersetzt. Beachten Sie, dass das Zeichen $ im ersatz-String eine Sonderbedeutung hat. Wie die folgende Tabelle zeigt, weist dieses Zeichen darauf hin, dass ein von einer Mustererkennung abgeleiteter String in den Ersatz einfließen soll.
Ersatz
$1, $2, ... $99
Der mit dem ersten bis 99. in Klammern stehenden Teil-Ausdruck in regexp übereinstimmende Teilstring
$&
Der Teilstring, der mit regexp übereinstimmte
$`
Der Text links von dem erkannten Teilstring
$'
Der Text rechts von dem erkannten Teilstring
$$
Ein Dollarzeichenliteral
ECMAScript v3 besagt, dass das ersatz-Argument von replace( ) auch eine Funktion statt eines Strings sein kann. In diesem Fall wird bei jeder Übereinstimmung die Funktion aufgerufen und der von ihr zurückgegebene String als Ersetzungstext verwendet. Das erste Argument der Funktion ist der String, der mit dem Muster übereinstimmt. Die nächsten Argumente sind die Strings, die mit den in Klammern stehenden Teilausdrücken des Ausdrucks übereinstimmen. Von diesen Argumenten können null oder mehr vorhanden sein. Das nächste Argument ist ein Integer, der angibt, wo in string die Übereinstimmung auftrat, und das letzte Argument der ersatz-Funktion ist der string selbst.
Beispiel Sicherstellen, dass die Groß-/Kleinschreibung im Wort »JavaScript« richtig ist: text.replace(/javascript/i, "JavaScript");
Einen Namen aus dem Format »Doe, John« in das Format »John Doe« konvertieren: name.replace(/(\w+)\s*,\s*(\w+)/, "$2 $1");
Alle doppelten Anführungszeichen durch doppelte vor- und rückwärts gerichtete einfache Anführungszeichen ersetzen: text.replace(/"([^"]*)"/g, "``$1''");
Den ersten Buchstaben aller Wörter eines Strings großschreiben: text.replace(/\b\w+\b/g, function(word) { return word.substring(0,1).toUpperCase( ) + word.substring(1); });
491-0.book Seite 766 Mittwoch, 4. April 2007 9:55 09
e-bol.net
String.search( )
String.search( )
ECMAScript v3
Sucht nach einem regulären Ausdruck
Überblick string.search(regexp)
Argumente regexp
Ein RegExp-Objekt, das das Muster angibt, das in string gesucht werden soll. Wenn dieses Argument nicht bereits ein RegExp-Objekt ist, wird es mit dem Konstruktor RegExp( ) in ein solches konvertiert. Rückgabewert Die Position, an der der erste Teilstring von string beginnt, der mit regexp übereinstimmt, oder –1, wenn keine Übereinstimmung gefunden wurde.
Beschreibung search( ) sucht nach einem auf regexp passenden Teilstring von string und gibt die Position des ersten Zeichens dieses Teilstrings zurück oder –1, wenn keine Übereinstimmung gefunden wurde. search( ) führt keine globalen Mustererkennungen durch und ignoriert das g-Flag. Außerdem ignoriert die Methode auch die Eigenschaft lastIndex von regexp und beginnt die Suche immer am Anfang des Strings. Das bedeutet, dass sie immer die Position der ersten Übereinstimmung in string zurückgibt.
Beispiel var s = "JavaScript macht Spaß"; s.search(/script/i) // Gibt 4 zurück s.search(/a(.)a/) // Gibt 1 zurück
491-0.book Seite 767 Mittwoch, 4. April 2007 9:55 09
e-bol.net
String.slice( )
Argumente anfang
Der String-Index, an dem das Slice (das Stück) anfangen soll. Ist dieses Argument negativ, so gibt es eine Position ab dem Ende des Strings an. –1 meint also das letzte Zeichen, –2 das vorletzte usw. ende
Der String-Index unmittelbar hinter dem Ende des Stücks. Ist keiner angegeben, so enthält das Stück alle Zeichen von anfang bis zum Ende des Strings. Ist dieses Argument negativ, so gibt es eine Position gemessen vom Ende des Strings an.
Beschreibung slice( ) gibt einen String mit einem Stück oder einem Teilstring von string zurück. string wird
dabei nicht modifiziert. Die String-Methoden slice( ), substring( ) und die veraltete substr( )-Methode geben Teile eines Strings zurück. slice( ) ist flexibler als substring( ), da sie auch Argumente mit negativem Wert gestattet. slice( ) unterscheidet sich von substr( ) insofern, als sie einen Teilstring mit zwei Zeichenpositionen spezifiziert, wogegen substr( ) eine Position und eine Länge angibt. Beachten Sie auch, dass String.slice( ) analog zu Array.slice( ) ist.
Beispiel var s = "abcdefg"; s.slice(0,4) // s.slice(2,4) // s.slice(4) // s.slice(3,-1) // s.slice(3,-2) // s.slice(-3,-1) // //
Gibt "abcd" zurück Gibt "cd" zurück Gibt "efg" zurück Gibt "def" zurück Gibt "de" zurück Sollte "ef" zurückgeben, gibt aber in IE 4 "abcdef" zurück
Fehler Negative Werte für anfang funktionieren nicht im Internet Explorer 4 (aber dafür in neueren Versionen des IE). Sie geben dort nicht eine vom String-Ende gemessene Zeichenposition, sondern die Zeichenposition 0 an.
Siehe auch Array.slice( ), String.substring( )
Referenz für den Sprachkern von JavaScript |
767
Referenz für den JavaScriptSprachkern
Rückgabewert Ein neuer String, der alle Zeichen von string von einschließlich anfang bis ausschließlich ende enthält.
491-0.book Seite 768 Mittwoch, 4. April 2007 9:55 09
e-bol.net
String.split( )
String.split( )
ECMAScript v3
Zerlegt einen String in ein String-Array
Überblick string.split(begrenzer, grenze)
Argumente begrenzer
Der String oder reguläre Ausdruck, bei dem string zerlegt wird. grenze
Dieser optionale Integer gibt die maximale Länge des Rückgabe-Arrays an. Wenn er spezifiziert wurde, wird nur maximal diese Anzahl Teilstrings zurückgegeben. Fehlt dieser Parameter, so wird der gesamte String ohne Rücksicht auf seine Länge zerlegt. Rückgabewert Ein String-Array, das entsteht, wenn string an den durch begrenzer spezifizierten Stellen in Teilstrings zerlegt wurde. Die Teilstrings im Rückgabe-Array enthalten die begrenzer selbst nicht, außer in dem Fall, der in der Beschreibung geschildert wird.
Beschreibung Die Methode split( ) erzeugt und liefert ein Array mit bis zu grenze Teilstrings des angegebenen Strings. Diese Teilstrings entstehen, wenn der String von Anfang bis Ende nach einem Text durchsucht wird, der mit begrenzer übereinstimmt, und dann vor und hinter diesem übereinstimmenden Text aufgespalten wird. Der begrenzer-Text selbst wird, außer in der Form, die am Ende dieses Abschnitts beschrieben wird, nicht in diese Teilstrings aufgenommen. Wenn der Begrenzer mit dem Anfang des Strings übereinstimmt, ist das erste Element des RückgabeArrays der leere String, also der Text, der vor dem Begrenzer steht. In gleicher Weise wird als letztes Array-Element der leere String zurückgeliefert, wenn der Begrenzer mit dem Ende des Strings übereinstimmt (und es keinen Konflikt mit grenze gibt). Ist kein begrenzer angegeben, so wird der String nicht zerlegt und das Rückgabe-Array enthält nur ein einziges, ununterbrochenes String-Element. Wenn begrenzer der leere String oder ein auf den leeren String passender regulärer Ausdruck ist, wird der String nach jedem Zeichen zerlegt, und das Rückgabe-Array hat dieselbe Länge wie der String, sofern keine kleinere grenze angegeben wurde. (Dies ist allerdings ein Sonderfall, da der leere String vor dem ersten und hinter dem letzten Zeichen nicht von der Mustererkennung erfasst wird.) Wie bereits erwähnt wurde, enthalten die Teilstrings in dem Rückgabe-Array dieser Methode nicht den Begrenzungstext, mit dem der String aufgespalten wird. Ist begrenzer jedoch ein regulärer Ausdruck mit in Klammern eingefassten Teilausdrücken, so werden die Teilstrings, die mit diesen Teilausdrücken übereinstimmen, in das Rückgabe-Array aufgenommen (nicht aber der Text, der mit dem regulären Ausdruck als Ganzes übereinstimmt). Die Methode String.split( ) ist das Gegenstück zu Array.join( ).
768 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 769 Mittwoch, 4. April 2007 9:55 09
e-bol.net
String.substr( )
Beispiel Die Methode split( ) ist am nützlichsten, wenn Sie mit stark strukturierten Strings arbeiten. Ein Beispiel: "1:2:3:4:5".split(":"); "|a|b|c|".split("|");
Außerdem wird die Methode split( ) oft zum Parsen von Befehlen und ähnlichen Strings verwendet, die in durch Leerzeichen getrennte Wörter zerlegt werden: var words = sentence.split(' ');
Es ist leichter, einen String mit einem regulären Ausdruck als Begrenzer in Wörter zu zerlegen: Um einen String in ein Zeichen-Array zu zerlegen, verwenden Sie als Begrenzer den leeren String. Wenn Sie nur ein Präfix des Strings in ein Zeichen-Array zerlegen möchten, können Sie dazu das Argument grenze verwenden: "hello".split(""); "hello".split("", 3);
Wenn Sie möchten, dass die Begrenzer oder ein oder mehrere Teile davon in das RückgabeArray aufgenommen werden, müssen Sie einen regulären Ausdruck mit geklammerten Teilausdrücken verwenden. Der folgende Code zerlegt z.B. einen String an den HTML-Tags und lässt diese Tags in das Rückgabe-Array mit einfließen: var text = "hello world"; text.split(/(]*>)/); // Rückgabe ["hello ","","world","",""]
Siehe auch Array.join( ), RegExp; Kapitel 11
String.substr( )
veraltet
Extrahiert einen Teilstring
Überblick string.substr(anfang, laenge)
Argumente anfang
Der Anfang des Teilstrings. Wenn dieses Argument negativ ist, gibt es eine vom StringEnde an gemessene Position an: –1 meint das letzte Zeichen, –2 das vorletzte und so weiter. laenge
Die Anzahl der Zeichen im Teilstring. Wenn dieses Argument fehlt, enthält der zurückgegebene Teilstring alle Zeichen vom Anfang bis zum Ende des Strings.
Referenz für den Sprachkern von JavaScript |
769
Referenz für den JavaScriptSprachkern
var words = sentence.split(/\s+/);
491-0.book Seite 770 Mittwoch, 4. April 2007 9:55 09
e-bol.net
String.substring( )
Rückgabewert Eine Kopie des Teils von string, der an der Position anfang beginnt, einschließlich dieses Zeichens, und der um laenge Zeichen oder, falls laenge nicht angegeben ist, bis zum Ende des Strings weitergeht.
Beschreibung substr( ) holt und liefert einen Teilstring von string, wobei string nicht modifiziert wird.
Sie sehen, dass substr( ) den gewünschten Teilstring mit einer Zeichenposition und einer Länge spezifiziert. Dies ist eine nützliche Alternative zu den Methoden String.substring( ) und String.splice( ), die einen String durch zwei Zeichenpositionen spezifizieren. Beachten Sie jedoch, dass diese Methode nicht von ECMAScript standardisiert wurde und daher veraltet ist.
Beispiel var s = "abcdefg"; s.substr(2,2); // s.substr(3); // s.substr(-3,2); // //
Gibt "cd" zurück Gibt "defg" zurück Sollte "ef" zurückgeben, gibt aber in IE 4 "ab" zurück
Fehler Negative anfang-Werte funktionieren nicht im Internet Explorer 4 (dies ist erst in späteren IEVersionen behoben). Sie geben keine vom String-Ende ab gemessene Zeichenposition an, sondern die Zeichenposition 0.
Siehe auch String.slice( ), String.substring( )
String.substring( )
ECMAScript v1
Gibt einen Teilstring eines Strings zurück
Überblick string.substring(von, bis)
Argumente von
Ein nicht-negativer Integer, der angibt, wo in string das erste Zeichen des gewünschten Teilstrings liegt. bis
Ein nicht-negativer optionaler Integer, der um eins größer als die Position des letzten Zeichens des gewünschten Teilstrings ist. Fehlt dieses Argument, so geht der zurückgegebene Teilstring bis zum String-Ende.
770 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 771 Mittwoch, 4. April 2007 9:55 09
e-bol.net
String.toLocaleLowerCase( )
Rückgabewert Ein neuer String der Länge bis–von mit einem Teilstring von string. Der neue String enthält die von den Positionen von bis bis–1 kopierten Zeichen von string.
Beschreibung String.substring( ) gibt einen aus den Zeichen zwischen den Positionen von und bis bestehenden Teilstring von string zurück. Das Zeichen an der Position von ist dabei, nicht aber das Zeichen an der Position bis.
Bitte vergessen Sie nicht, dass das Zeichen an der Position von in den Teilstring einfließt und das Zeichen an der Position bis nicht. Das mag zunächst willkürlich oder verwirrend aussehen, aber es ist ein wichtiges Merkmal dieses Systems, dass die Länge des zurückgegebenen Teilstrings immer bis −von beträgt. Beachten Sie, dass Sie auch mit String.slice( ) und der nicht-standardisierten Methode String.substr( ) Teilstrings aus einem String extrahieren können. Anders als diese Methoden akzeptiert String.substring( ) keine negativen Argumente.
Rückgabewert Eine in locale-spezifische Kleinschreibung konvertierte Kopie von string. Nur wenige Sprachen, wie z.B. Türkisch, haben locale-spezifische Zuordnungen für die Groß- und Kleinschreibung. Daher gibt diese Methode normalerweise denselben Wert wie toLowerCase( ) zurück.
Siehe auch String.toLocaleUpperCase( ), String.toLowerCase( ), String.toUpperCase( )
Referenz für den Sprachkern von JavaScript |
771
Referenz für den JavaScriptSprachkern
Ist von gleich bis, so gibt diese Methode den leeren String (mit der Länge 0) zurück. Ist von größer als bis, so vertauscht diese Methode zuerst die beiden Argumente und gibt dann den dazwischenliegenden Teilstring zurück.
491-0.book Seite 772 Mittwoch, 4. April 2007 9:55 09
e-bol.net
String.toLocaleUpperCase( )
String.toLocaleUpperCase( )
ECMAScript v3
Konvertiert einen String in Großschreibung
Überblick string.toLocaleUpperCase( )
Rückgabewert Eine in locale-spezifische Großschreibung konvertierte Kopie von string. Nur wenige Sprachen, wie z.B. Türkisch, haben locale-spezifische Zuordnungen für die Groß- und Kleinschreibung. Daher gibt diese Methode normalerweise denselben Wert wie toUpperCase( ) zurück.
Siehe auch String.toLocaleLowerCase( ), String.toLowerCase( ), String.toUpperCase( )
String.toLowerCase( )
ECMAScript v1
Konvertiert einen String in Kleinschreibung
Überblick string.toLowerCase( )
Rückgabewert Eine Kopie von string, in der jeder Großbuchstabe in den entsprechenden Kleinbuchstaben konvertiert wurde, falls ein solcher existiert.
String.toString( ) Gibt den String zurück
ECMAScript v1 Überschreibt Object.toString( )
Überblick string.toString( )
Rückgabewert Der elementare Stringwert von string. Diese Methode muss fast nie aufgerufen werden. Exceptions TypeError
Tritt auf, wenn diese Methode auf einem anderen als einem String-Objekt aufgerufen wird.
Siehe auch String.valueOf( )
772 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 773 Mittwoch, 4. April 2007 9:55 09
e-bol.net
String.toUpperCase( )
String.toUpperCase( )
ECMAScript v1
Konvertiert einen String in Großbuchstaben
Überblick string.toUpperCase( )
Rückgabewert Eine Kopie von string, in der jeder Kleinbuchstabe in den entsprechenden Großbuchstaben konvertiert wurde, falls ein solcher existiert.
Gibt den String zurück
ECMAScript v1 Überschreibt Object.valueOf( )
Überblick string.valueOf( )
Rückgabewert Der elementare Stringwert von string. Exceptions TypeError
Tritt auf, wenn diese Methode auf einem anderen als einem String-Objekt aufgerufen wird.
Siehe auch String.toString( )
SyntaxError Signalisiert einen Syntaxfehler
ECMAScript v3 Object ➝ Error ➝ SyntaxError
Konstruktor new SyntaxError( ) new SyntaxError(meldung)
Argumente meldung
Eine optionale Fehlermeldung, die Einzelheiten über die Exception verrät. Wenn dieses Argument angegeben ist, dient es als Wert der message-Eigenschaft des SyntaxErrorObjekts.
Referenz für den Sprachkern von JavaScript |
773
Referenz für den JavaScriptSprachkern
String.valueOf( )
491-0.book Seite 774 Mittwoch, 4. April 2007 9:55 09
e-bol.net
TypeError
Rückgabewert Ein neu erzeugtes SyntaxError-Objekt. Wenn das Argument meldung angegeben ist, wird es vom Error-Objekt als Wert der message-Eigenschaft verwendet; andernfalls erhält diese Eigenschaft einen implementierungsspezifischen Standard-String als Wert. Wenn der Konstruktor SyntaxError( ) als Funktion ohne den Operator new aufgerufen wird, verhält er sich genau wie bei einem Aufruf mit dem Operator new.
Eigenschaften message
Eine Fehlermeldung, die Einzelheiten über die Exception verrät. Diese Eigenschaft speichert den String, der an den Konstruktor übergeben wurde, oder einen implementierungsspezifischen Standard-String. Einzelheiten finden Sie unter Error.message. name
Ein String, der den Exception-Typ angibt. Alle SyntaxError-Objekte erben für diese Eigenschaft den Wert »SyntaxError«.
Beschreibung Eine Instanz der Klasse SyntaxError wird ausgelöst, um einen Syntaxfehler in JavaScript-Code anzuzeigen. Die Methode eval( ), der Konstruktor Function( ) und der Konstruktor RegExp( ) können Exceptions dieses Typs auslösen. Unter Error wird das Auslösen und Abfangen von Exceptions genauer beschrieben.
Siehe auch Error, Error.message, Error.name
TypeError Zeigt an, dass ein Wert den falschen Typ hat
ECMAScript v3 Object ➝ Error ➝ TypeError
Konstruktor new TypeError( ) new TypeError(meldung)
Argumente meldung
Eine optionale Fehlermeldung, die Einzelheiten über die Exception verrät. Wenn dieses Argument angegeben ist, dient es als Wert der message-Eigenschaft des TypeError-Objekts. Rückgabewert Ein neu erzeugtes TypeError-Objekt. Wenn das Argument meldung angegeben ist, wird es vom Error-Objekt als Wert der message-Eigenschaft verwendet; andernfalls erhält diese Eigenschaft einen implementierungsspezifischen Standard-String als Wert. Wenn der Konstruktor TypeError( ) als Funktion ohne den Operator new aufgerufen wird, verhält er sich genau wie bei einem Aufruf mit dem Operator new.
774 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 775 Mittwoch, 4. April 2007 9:55 09
e-bol.net
undefined
Eigenschaften message
Eine Fehlermeldung, die Einzelheiten über die Exception verrät. Diese Eigenschaft speichert den String, der an den Konstruktor übergeben wurde, oder einen implementierungsspezifischen Standard-String. Einzelheiten finden Sie unter Error.message. name
Ein String, der den Exception-Typ angibt. Alle TypeError-Objekte erben für diese Eigenschaft den Wert »TypeError«.
Beschreibung
Siehe auch Error, Error.message, Error.name
undefined
ECMAScript v3
Der Wert undefined
Überblick undefined
Beschreibung undefined ist eine globale Eigenschaft, die den JavaScript-Wert undefined speichert. Derselbe Wert wird zurückgegeben, wenn Sie versuchen, den Wert einer nicht vorhandenen Objekteigenschaft zurückzugeben. Die undefined-Eigenschaft ist nicht mit for/in-Schleifen aufzählbar und lässt sich auch nicht mit dem delete-Operator löschen. Beachten Sie, dass die undefinedEigenschaft keine Konstante ist, sondern auf einen anderen Wert gesetzt werden kann. Dies sollten Sie allerdings besser unterlassen.
Wenn Sie prüfen möchten, ob ein Wert nicht definiert ist, verwenden Sie den Operator ===, denn der Operator == unterscheidet nicht zwischen dem Wert undefined und dem Wert null.
Referenz für den Sprachkern von JavaScript |
775
Referenz für den JavaScriptSprachkern
Eine Instanz der Klasse TypeError wird ausgelöst, wenn ein Wert nicht den erwarteten Typ hat. Am häufigsten geschieht dies, wenn Sie versuchen, auf eine Eigenschaft mit dem Wert null oder auf einen nicht definierten Wert zuzugreifen. Es kann auch passieren, wenn Sie z.B. eine Methode, die durch eine bestimmte Klasse definiert wird, auf einem Objekt aufrufen, das eine Instanz einer anderen Klasse ist, oder wenn Sie den Operator new mit einem Wert verwenden, der keine Konstruktorfunktion ist. JavaScript-Implementierungen dürfen auch dann TypeErrorObjekte auslösen, wenn eine eingebaute Funktion oder Methode mit mehr Argumenten als erwartet aufgerufen wird. Einzelheiten über das Auslösen und Abfangen von Exceptions finden Sie unter Error.
491-0.book Seite 776 Mittwoch, 4. April 2007 9:55 09
e-bol.net
unescape( )
unescape( )
ECMAScript v1; veraltet in ECMAScript v3
Decodiert einen String mit Escape-Sequenzen
Überblick unescape(s)
Argumente s Der zu decodierende String. Rückgabewert Eine decodierte Kopie von s.
Beschreibung unescape( ) ist eine globale Funktion, die einen mit escape( ) codierten String wieder decodiert. Dies tut sie, indem sie Zeichenfolgen der Form %xx bzw. %uxxxx findet (wobei x eine Hexadezimalzahl darstellt) und durch die Unicode-Zeichen \u00xx und \uxxxx ersetzt. unescape( ) wurde zwar in der ersten Version von ECMAScript standardisiert, aber seither wieder verworfen und aus dem ECMAScript v3-Standard herausgenommen. Implementierungen von ECMAScript dürften diese Funktion zwar normalerweise noch unterstützen, aber sie müssen es nicht mehr. Sie sollten decodeURI( ) und decodeURIComponent( ) anstelle von unescape( ) verwenden. Einzelheiten und ein Beispiel finden Sie unter escape( ).
Siehe auch decodeURI( ), decodeURIComponent( ), escape( ), String
URIError Wird von Methoden zum Codieren und Decodieren von URIs ausgelöst
ECMAScript v3 Object ➝ Error ➝ URIError
Konstruktor new URIError( ) new URIError(meldung)
Argumente meldung
Eine optionale Fehlermeldung, die Einzelheiten über die Exception verrät. Wenn dieses Argument angegeben ist, dient es als Wert der message-Eigenschaft des URIError-Objekts. Rückgabewert Ein neu erzeugtes URIError-Objekt. Wenn das Argument meldung angegeben ist, wird es vom Error-Objekt als Wert der message-Eigenschaft verwendet; andernfalls erhält diese Eigenschaft einen implementierungsspezifischen Standard-String als Wert. Wenn der Konstruktor URIError( ) als Funktion ohne den Operator new aufgerufen wird, verhält er sich genau wie bei einem Aufruf mit dem Operator new.
776 | Referenz für den Sprachkern von JavaScript
491-0.book Seite 777 Mittwoch, 4. April 2007 9:55 09
e-bol.net
URIError
Eigenschaften message
Eine Fehlermeldung, die Einzelheiten über die Exception verrät. Diese Eigenschaft speichert den String, der an den Konstruktor übergeben wurde, oder einen implementierungsspezifischen Standard-String. Einzelheiten finden Sie unter Error.message. name
Ein String, der den Exception-Typ angibt. Alle URIError-Objekte erben für diese Eigenschaft den Wert »URIError«.
Beschreibung
Siehe auch Error, Error.message, Error.name
Referenz für den Sprachkern von JavaScript |
777
Referenz für den JavaScriptSprachkern
Eine Instanz der Klasse URIError wird von den Methoden decodeURI( ) und decodeURI Component( ) ausgelöst, wenn der angegebene String unzulässige hexadezimale Escape-Symbole enthält. Sie kann auch von encodeURI( ) und encodeURIComponent( ) ausgelöst werden, wenn der angegebene String unzulässige Unicode-Surrogatpaare enthält. Einzelheiten über das Auslösen und Abfangen von Exceptions finden Sie unter Error.
491-0.book Seite 778 Mittwoch, 4. April 2007 9:55 09
e-bol.net
491-0.book Seite 779 Mittwoch, 4. April 2007 9:55 09
e-bol.net
TEIL IV IV.
Referenz für clientseitiges JavaScript
Dieser Teil des Buchs ist eine vollständige Referenz der Objekte, Eigenschaften, Funktionen, Methoden und Event-Handler von clientseitigem JavaScript. Hinweise für die Benutzung dieser Referenz erhalten Sie im Beispiel-Referenzeintrag am Anfang von Teil III dieses Buchs. Die in diesem Teil dokumentierten Klassen und Objekte beinhalten: Anchor
ExternalInterface
Applet
FlashPlayer
ProcessingInstruction
Attr
Form
Range
Canvas
Frame
RangeException
CanvasGradient
History
Screen
CanvasPattern
HTMLCollection
Select
CanvasRenderingContext2D
HTMLDocument
Table
CDATASection
HTMLElement
TableCell
CharacterData
IFrame
TableRow
Comment
Image
TableSection
CSS2Properties
Input
Text
CSSRule
JSObject
Textarea
CSSStyleSheet
KeyEvent
UIEvent
Document
Link
Window
DocumentFragment
Location
XMLHttpRequest
DocumentType
MimeType
XMLSerializer
DOMException
MouseEvent
XPathExpression
DOMImplementation
Navigator
XPathResult
DOMParser
Node
XSLTProcessor
Element
NodeList
Event
Option
Plugin
491-0.book Seite 780 Mittwoch, 4. April 2007 9:55 09
e-bol.net
491-0.book Seite 781 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Referenz für clientseitiges JavaScript
Dieser Teil des Buchs ist eine Referenz, die die im clientseitigen JavaScript definierten Klassen, Methoden, Eigenschaften und Event-Handler dokumentiert. Diese Einleitung und die am Anfang von Teil III stehende Beispiel-Referenzseite erklären die Benutzung dieser Referenzdokumentation und helfen Ihnen dabei, sie voll auszuschöpfen. Wenn Sie sich die Zeit nehmen, dieses Material sorgfältig zu lesen, können Sie die benötigten Informationen leichter finden und besser einsetzen. Dieser Referenzteil ist alphabetisch aufgebaut. Die Referenzeinträge zu Klassenmethoden und -eigenschaften werden alphabetisch nach deren vollem Namen aufgeführt, der auch die Namen der Klassen einschließt, in denen sie definiert sind. Wenn Sie z.B. die submit( )-Methode der Klasse Form nachschlagen möchten, schauen Sie nicht unter »submit«, sondern unter »Form.submit« nach. Die meisten JavaScript-Eigenschaften auf der Clientseite haben keine eigenen Referenzeinträge (alle Methoden und Event-Handler haben aber einen eigenen Eintrag). Einfache Eigenschaften werden stattdessen im Referenzeintrag der Klasse, die sie definiert, vollständig dokumentiert. Die images[]-Eigenschaft der Klasse HTMLDocument können Sie z.B. im Referenzeintrag zu HTMLDocument nachschlagen. Nicht-triviale Eigenschaften, die erklärungsbedürftig sind, haben allerdings eigene Referenzeinträge. Im Referenzeintrag zu der Klasse oder dem Interface, in dem solche Eigenschaften definiert sind, finden Sie dann einen entsprechenden Querverweis. Wenn Sie beispielsweise die cookie-Eigenschaft in der HTMLDocument-Referenzseite nachschlagen, finden Sie eine Kurzbeschreibung der Eigenschaft und unter HTMLDocument.cookie einen Verweis auf weitere Informationen. JavaScript auf der Clientseite hat diverse globale Eigenschaften und Funktionen, wie z.B. window, history und alert( ). In clientseitigem JavaScript dient ein Window-Objekt als
globales Objekt, und die »globalen« Eigenschaften und Funktionen von clientseitigem JavaScript sind eigentlich Eigenschaften der Klasse Window. Deshalb sind globale Eigenschaften und Funktionen im Window-Referenzeintrag dokumentiert oder unter Namen wie z.B. Window.alert( ).
|
781
491-0.book Seite 782 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Anchor
Haben Sie erst den gesuchten Referenzeintrag gefunden, so dürfte das Auffinden der benötigten Informationen keine Schwierigkeiten mehr bereiten. Doch Sie können den Referenzteil noch besser ausnutzen, wenn Sie wissen, wie die Einträge geschrieben und organisiert sind. Teil III beginnt mit einem Beispiel-Referenzeintrag unter dem Titel »Beispiel-Referenzeintrag«. Dieser Eintrag erklärt die Struktur aller Referenzeinträge und zeigt, wie Sie in ihnen die gesuchten Informationen finden.
Anchor
DOM Level 0
Das Ziel eines Hypertext-Links
Node ➝ Element ➝ HTMLElement ➝ Anchor
Eigenschaften String name
Enthält den Namen eines Anchor-Objekts. Der Wert dieser Eigenschaft wird vom Attribut name des Tags gesetzt.
Methoden focus( )
Scrollt das Dokument so, dass der Ort des Ankers sichtbar wird.
HTML-Syntax Ein Anchor-Objekt wird von jedem normalen HTML-Tag erzeugt, das ein name-Attribut enthält: ...
// Über diesen Namen können sich Links auf diesen Anker beziehen
Beschreibung Ein Anker ist eine benannte Stelle in einem HTML-Dokument. Anker werden mit einem Tag erzeugt, für das ein name-Attribut angegeben ist. Das Document-Objekt hat eine ArrayEigenschaft namens anchors[], die für jeden Anker im Dokument ein Anchor-Objekt enthält. Anchor-Objekte können in diesem Array über Index oder Namen referenziert werden. Der Browser zeigt den Ort des Ankers an, wenn Sie die hash-Eigenschaft des Location-Objekts auf ein #-Zeichen setzen, dem der Name des Ankers folgt. Alternativ können Sie einfach die focus( )-Methode des Anchor-Objekts selbst aufrufen. Mit demselben -Tag, mit dem Sie Anker erzeugen, legen Sie auch Hypertext-Links an. Zwar werden im Sprachgebrauch von HTML auch Hypertext-Links oft als Anker bezeichnet, aber in JavaScript werden sie nicht durch das Anchor-, sondern durch das Link-Objekt dargestellt.
Beispiel // Scrolle das Dokument so, dass der Anker namens "_bottom_" sichtbar ist document.anchors['_bottom_'].focus( );
782 | Referenz für clientseitiges JavaScript
491-0.book Seite 783 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Anchor.focus( )
Siehe auch Document, Link, Location
Anchor.focus( )
DOM Level 0
Scrolle, um den Ort des Anchors sichtbar zu machen
Überblick void focus( );
Beschreibung Diese Methode scrollt das Dokument so, dass die Lokation des Anchor-Objekts sichtbar wird.
Applet
DOM Level 0 Referenz für clientseitiges JavaScript
Ein in eine Webseite eingebettetes Applet
Überblick document.applets[i] document.appletName
Eigenschaften Das Applet-Objekt hat Eigenschaften, die die HTML-Attribute des -Tags widerspiegeln (Details siehe HTMLElement). Es hat außerdem Eigenschaften, die den öffentlichen Feldern des von ihm repräsentierten Java-Applets entsprechen.
Methoden Die Methoden eines Applet-Objekts entsprechen den öffentlichen Methoden des dazugehörigen Java-Applets.
Beschreibung Das Applet-Objekt stellt ein Java-Applet dar, das in ein HTML-Dokument eingebettet ist. Sie können sich Applet-Objekte eines Dokuments über die applets[]-Collection des DocumentObjekts beschaffen. Die Eigenschaften des Applet-Objekts entsprechen den öffentlichen Feldern und seine Methoden den öffentlichen Methoden des Applets. Denken Sie daran, dass Java eine stark typisierte Sprache ist. Daher muss jedes Feld eines Applets mit einem konkreten Datentyp deklariert werden. Wenn Sie seinen Wert auf einen anderen Typ setzen, wird ein Laufzeitfehler ausgelöst. Dasselbe trifft auf Appletmethoden zu: Jedes Argument hat einen spezifischen Typ, und Argumente können, anders als in JavaScript, nicht weggelassen werden. Eine genaue Beschreibung finden Sie in Kapitel 23.
Referenz für clientseitiges JavaScript |
783
491-0.book Seite 784 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Attr
Siehe auch JSObject; JavaObject in Teil III; Kapitel 12, Kapitel 23
Attr Ein Attribut eines Dokumentelements
DOM Level 1 Core Node ➝ Attr
Eigenschaften readonly String name
Der Name des Attributs. readonly Element ownerElement [DOM Level 2]
Das Element-Objekt, das dieses Attribut enthält, oder null, wenn das Attr-Objekt gegenwärtig nicht mit einem Element verbunden ist. readonly boolean specified true, wenn das Attribut explizit im Dokumentquelltext angegeben oder durch ein Skript eingestellt wurde. false, wenn das Attribut zwar nicht explizit angegeben wurde, aber in
der DTD des Dokuments ein Voreinstellungswert festgelegt wurde. String value
Der Attributwert. Wenn diese Eigenschaft gelesen wird, wird der Attributwert als String zurückgegeben. Wenn Sie diese Eigenschaft als String einstellen, erzeugt sie automatisch einen Text-Knoten mit demselben Textinhalt und macht ihn zum einzigen Kind des AttrObjekts.
Beschreibung Ein Attr-Objekt repräsentiert ein Attribut eines Element-Knotens. Attr-Objekte sind mit Element-Knoten assoziiert, gehören aber nicht unmittelbar zum Dokumentenbaum (und haben eine parentNode-Eigenschaft mit dem Wert null). Sie können ein Attr-Objekt entweder über die attributes-Eigenschaft des Node-Interfaces erhalten oder, indem Sie die getAttributeNode( )- oder getAttributeNodeNS( )-Methoden des Element-Interfaces aufrufen. Der Wert eines Attributs wird durch die Kindknoten eines Attr-Nodes dargestellt. In HTMLDokumenten hat ein Attr-Knoten immer nur ein Textnode-Kind, wobei die value-Eigenschaft eine Abkürzung zum Lesen und Schreiben des Wertes dieses Kindknotens liefert. Die XML-Grammatik erlaubt in XML-Dokumenten Attribute, die aus Textknoten und EntityReference-Knoten bestehen. Deshalb kann ein Attributwert durch einen String nicht vollständig dargestellt werden. In der Praxis erweitern Webbrowser allerdings alle beliebigen Entity-Referenzen zu XML-Attributwerten, ohne dabei das EntityReference-Interface zu implementieren (das in diesem Buch nicht dokumentiert wird). Folglich wird in clientseitigem JavaScript zum Lesen und Schreiben von Attributwerten lediglich die value-Eigenschaft benötigt. Da Attributwerte vollständig durch Strings dargestellt werden können, ist es normalerweise nicht notwendig, die Attr-Schnittstelle zu verwenden. In den meisten Fällen ist die Arbeit mit Attributen am einfachsten, wenn Sie die Methoden Element.getAttribute( ) und Element. setAttribute( ) nutzen. Diese Methoden verwenden für die Attributwerte Strings und vermeiden den Einsatz von Attr-Knoten.
784 | Referenz für clientseitiges JavaScript
491-0.book Seite 785 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Button
Siehe auch Element
Button Siehe Input
Canvas Ein HTML-Element zum skriptgesteuerten Zeichnen
Firefox 1.5, Safari 1.3, Opera 9 Node ➝ Element ➝ HTMLElement ➝ Canvas
Eigenschaften String hoehe
String breite
Die Canvasbreite. Wie bei einem Bild kann die Höhe als ein ganzzahliger Pixelwert oder in Prozent der Fensterbreite angegeben werden. Bei der Änderung dieses Werts wird eine ggf. bereits auf dem Canvas befindliche Zeichnung gelöscht. Der Standardwert ist 300.
Methoden getContext( )
Gibt ein CanvasRenderingContext2D-Objekt zurück, mit den auf den Canvas gezeichnet werden kann. Sie müssen den String »2d« an diese Methode übergeben, um zweidimensional zu zeichnen.
Beschreibung Das Canvas-Objekt stellt ein HTML-Canvas-Element dar. Es hat kein eigenes Verhalten, sondern definiert eine API, die geskriptete Zeichenvorgänge auf der Clientseite unterstützt. Sie können die breite und hoehe direkt am Objekt eingeben, aber die meisten anderen Funktionalitäten werden über das CanvasRenderingContext2D-Objekt festgelegt. Das Objekt erhalten Sie, indem Sie die getContext( )-Methode des Canvas-Objekts aufrufen und den Textstring »2d« als einziges Argument übergeben. Das -Tag wurde mit Safari 1.3 eingeführt und wurde, als dieses Buch geschrieben wurde, auch von Firefox 1.5 und Opera 9 unterstützt. Das -Tag und seine API lassen sich in IE mit dem ExplorerCanvas Open-Source-Projekt unter http://excanvas.sourceforge.net/ simulieren.
Siehe auch CanvasRenderingContext2D; Kapitel 22
Referenz für clientseitiges JavaScript |
785
Referenz für clientseitiges JavaScript
Die Höhe des Canvas. Wie bei einem Bild kann die Höhe als ein ganzzahliger Pixelwert oder in Prozent der Fensterhöhe angegeben werden. Bei der Änderung dieses Werts wird eine ggf. bereits auf dem Canvas befindliche Zeichnung gelöscht. Der Standardwert ist 300.
491-0.book Seite 786 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Canvas.getContext( )
Canvas.getContext( ) Liefert einen Context zum Schreiben auf dem Canvas zurück
Dieses Argument gibt die Art der Zeichnung an, die Sie auf dem Canvas durchführen wollen. Zurzeit ist »2d« der einzig gültige Wert. Er legt zweidimensionales Zeichnen fest und veranlasst diese Methode, ein Context-Objekt zurückzugeben, das eine 2-D-Zeichnungs-API exportiert. Rückgabewert Ein CanvasRenderingContext2D-Objekt, mit dem Sie im Canvas-Element zeichnen können.
Beschreibung Gibt einen Kontext aus, der den zum Zeichnen zu benutzenden Kontexttyp darstellt. Die Absicht ist, für verschiedene Zeichnungstypen (2-D, 3-D) unterschiedliche Kontexte verfügbar zu machen. Zurzeit wird lediglich der »2d«-Typ unterstützt. Er liefert ein CanvasRenderingContext2D-Objekt aus, das die meisten von einem Canvas verwendeten Methoden implementiert.
Siehe auch CanvasRenderingContext2D
CanvasGradient Ein Farbgradient, der auf einem Canvas verwendet wird
Firefox 1.5, Safari 1.3, Opera 9 Object ➝ CanvasGradient
Methoden addColorStop( )
Gibt eine Farbe und Position für den Gradienten an.
Beschreibung Ein CanvasGradient-Objekt stellt einen Farbgradienten dar, der sowohl den strokeStyle- als auch den fillStyle-Eigenschaften eines CanvasRenderingContext2D-Objektes zugewiesen werden kann. Sowohl die createLinearGradient( )- als auch die createRadialGradient( )Methoden von CanvasRenderingContext2D geben CanvasGradient-Objekte zurück. Nach der Erstellung eines CanvasGradient-Objektes verwenden Sie addColorStop( ), um festzulegen, welche Farben an welcher Position im Gradienten erscheinen sollen. Zwischen den von Ihnen festgelegten Positionen werden die Farben interpoliert, um einen fließenden Gradienten oder Farbübergang zu erreichen. Am Start- und Endpunkt des Gradienten werden automatisch transparente schwarze Stopps erstellt.
786 | Referenz für clientseitiges JavaScript
491-0.book Seite 787 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasGradient.addColorStop( )
Siehe auch CanvasRenderingContext2D.createLinearGradient( ) CanvasRenderingContext2D.createRadialGradient( )
CanvasGradient.addColorStop( ) Hinzufügen einer Farbänderung zum Gradienten
Ein Gleitkommazahlwert im Bereich zwischen 0,0 und 1,0, der einen Bruchteil zwischen den Start- und Endpunkten des Gradienten darstellt. Ein Offset von 0 entspricht dem Startpunkt und ein Offset von 1 dem Endpunkt. Gibt die Farbe, die am festgelegten Offset angezeigt werden soll, als CSS-Farbstring an. Farben an anderen Punkten entlang des Gradienten werden auf der Basis dieses und weiterer Farbstützpunkte (Stops) interpoliert.
Beschreibung addColorStop( ) stellt den Mechanismus zur Beschreibung von Farbänderungen in einem Gradi-
enten zur Verfügung. Diese Methode kann ein- oder mehrmals aufgerufen werden, um die Farbe an bestimmten Prozentualstellen zwischen dem Start- und Endpunkt des Gradienten zu ändern. Wenn diese Methode an einem Gradienten nie aufgerufen wird, ist der Gradient transparent. Um einen sichtbaren Farbverlauf zu erhalten, muss mindestens ein Farbstützpunkt (Stop) festgelegt werden.
CanvasPattern Ein auf einem Bild basierendes Muster zur Verwendung auf einem Canvas
Firefox 1.5, Safari 1.3, Opera 9 Object ➝ CanvasPattern
Beschreibung Ein CanvasPattern-Objekt wird von der createPattern( )-Methode eines CanvasRenderingContext2D-Objekts ausgegeben. Ein CanvasPattern-Objekt kann als Wert der strokeStyle- und fillStyle-Eigenschaften eines CanvasRenderingContext2D-Objekts verwendet werden. Ein CanvasPattern-Objekt hat keine eigenen Eigenschaften oder Methoden. Einzelheiten zum Erstellen dieses Objekts finden Sie unter CanvasRenderingContext2D.createPattern( ).
Referenz für clientseitiges JavaScript |
787
Referenz für clientseitiges JavaScript
color
491-0.book Seite 788 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D
Siehe auch CanvasRenderingContext2D.createPattern( )
CanvasRenderingContext2D Das Objekt wird zum Zeichnen auf einem Canvas verwendet
Firefox 1.5, Safari 1.3, Opera 9 Object ➝ CanvasRenderingContext2D
Eigenschaften readonly Canvas canvas
Das Canvas-Element, auf das dieser Kontext zeichnen wird. Object fillStyle
Die Farbe, das Muster oder der Gradient, die/das/der derzeit zum Ausfüllen von Pfaden verwendet wird. Diese Eigenschaft kann auf einen String, ein CanvasGradient- oder ein CanvasPattern-Objekt gesetzt werden. Als String wird sie als CSS-Farbwert geparst und für massive Farbfüllungen verwendet. Als CanvasGradient- oder CanvasPattern-Objekt werden Farbfüllungen mit Hilfe des angegebenen Gradienten oder Musters ausgefüllt. Siehe CanvasRenderingContext2D.createLinearGradient( ), CanvasRenderingContext2D.createRadialGradient( ) und CanvasRenderingContext2D.createPattern( ). float globalAlpha
Gibt die Deckkraft des auf den Canvas gezeichneten Inhalts an. Der Wertebereich liegt zwischen 0,0 (vollständig transparent) und 1,0 (keine zusätzliche Transparenz). Der Standardwert dieser Eigenschaft ist 1,0. String globalCompositeOperation
Gibt an, wie gerade gezeichnete Farben mit bereits auf dem Canvas vorhandenen Farben kombiniert werden. Mögliche Werte finden Sie unter dem individuellen Eintrag für diese Eigenschaft. String lineCap
Gibt an, wie die Linienenden wiedergegeben werden. Gültige Werte sind »butt« (stumpf), »round« (rund) und »square« (eckig). Der Defaultwert ist »butt«. Weitere Einzelheiten zu dieser Eigenschaft finden Sie in ihrem individuellen Referenzeintrag. String lineJoin
Gibt an, wie zwei Linien zusammengefügt werden. Gültige Werte sind »round« (rund), »bevel« (schräg) und »miter« (auf Gehrung). Der Defaultwert ist »miter«. Weitere Einzelheiten zu dieser Eigenschaft finden Sie in ihrem individuellen Referenzeintrag. float lineWidth
Gibt die Linienbreite für Strichfunktionen (Linienzeichnungen) an. Die Standardeinstellung ist 1,0, und die Eigenschaft muss größer als 0,0 sein. Breite Linien werden über dem Pfad zentriert, sodass jeweils die halbe Linienbreite links und rechts der Mitte liegt. float miterLimit Ist die lineJoin-Eigenschaft »miter«, dann gibt diese Eigenschaft das maximale Verhältnis
zwischen Gehrungslänge zu Linienbreite an. Weitere Einzelheiten zu dieser Eigenschaft finden Sie in ihrem individuellen Referenzeintrag.
788 | Referenz für clientseitiges JavaScript
491-0.book Seite 789 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D float shadowBlur
Gibt an, wie weit Schatten auslaufen sollen. Die Standardeinstellung ist 0. Safari unterstützt Schatten, Firefox 1.5 und Opera 9 tun das jedoch nicht. String shadowColor
Gibt die Schattenfarbe als CSS- oder Web-Style-String an und kann eine Alpha-Komponente für die Transparenz enthalten. Die Standardeinstellung ist »black«. Safari unterstützt Schatten, Firefox 1.5 und Opera 9 tun das jedoch nicht. float shadowOffsetX, shadowOffsetY
Gibt den horizontalen und vertikalen Offset der Schatten an. Größere Werte lassen das schattierte Objekt vor dem Hintergrund höher erscheinen. Die Standardeinstellung ist 0. Safari unterstützt Schatten, Firefox 1.5 und Opera 9 tun das jedoch nicht. Object strokeStyle
Methoden arc( )
Ein Kreisbogen wird mit Hilfe eines Mittelpunktes und eines Radius zum bestehenden Subpfad eines Canvas hinzugefügt. arcTo( )
Ein Kreisbogen wird mit Hilfe eines Tangentenpunktes und eines Radius zum bestehenden Subpfad hinzugefügt. beginPath( )
Beginnt einen neuen Pfad (oder mehrere Subpfade) in einem Canvas. bezierCurveTo( )
Fügt dem derzeitigen Subpfad eine dreidimensionale Bézierkurve hinzu. clearRect( )
Löscht die Pixel in einem rechteckigen Bereich auf einem Canvas. clip( )
Verwendet den derzeitigen Pfad als Clip-Region für nachfolgende Zeichnungsfunktionen. closePath( )
Schließt den derzeitigen Subpfad, sofern er geöffnet ist. createLinearGradient( )
Gibt ein CanvasGradient-Objekt aus, das einen linearen Farbgradienten darstellt. createPattern( )
Gibt ein CanvasPattern-Objekt aus, das ein gekacheltes Bild darstellt.
Referenz für clientseitiges JavaScript |
789
Referenz für clientseitiges JavaScript
Gibt die Farbe, das Muster oder den Gradienten an, die/das/der für die Striche (das Zeichnen) von Pfaden verwendet wird. Diese Eigenschaft kann ein String, ein CanvasGradient- oder ein CanvasPattern-Objekt sein. Ist sie ein String, wird sie als CSS-Farbwert interpretiert und die Linienzeichnung wird mit der resultierenden deckenden Farbe durchgeführt. Ist der Wert dieser Eigenschaft ein CanvasGradient- oder CanvasPattern-Objekt, wird die Linienzeichnung über den Gradienten oder das Muster durchgeführt. Siehe CanvasRenderingContext2D.createLinearGradient( ), CanvasRenderingContext2D.createRadialGradient( ) und CanvasRenderingContext2D.createPattern( ).
491-0.book Seite 790 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D createRadialGradient( )
Gibt ein CanvasGradient-Objekt aus, das einen radialen Farbgradienten widerspiegelt. drawImage( )
Zeichnet ein Bild. fill( )
Färbt oder füllt den Innenraum des derzeitigen Pfads mit der von der fillStyle-Eigenschaft vorgegebenen Farbe, dem Gradienten oder dem Muster. fillRect( )
Färbt oder füllt ein Rechteckt. lineTo( )
Fügt dem derzeitigen Subpfad ein gerades Liniensegment hinzu. moveTo( )
Legt die derzeitige Position fest und beginnt mit einem neuen Subpfad. quadraticCurveTo( )
Fügt dem derzeitigen Subpfad eine zweidimensionale Bézier-Kurve hinzu. rect( )
Fügt dem derzeitigen Pfad einen rechteckigen Subpfad hinzu. restore( )
Setzt den Canvas auf den zuletzt gespeicherten Grafikzustand zurück. rotate( )
Dreht den Canvas. save( )
Speichert die Eigenschaften, Clip-Region und Transformationsmatrix des CanvasRenderingContext2D-Objekts. scale( )
Skaliert das Benutzerkoordinatensystem des Canvas. stroke( )
Zeichnet oder strichelt eine Linie entlang des momentanen Pfads. Die Linie wird nach Vorgabe der Eigenschaften lineWidth, lineJoin, lineCap und strokeStyle sowie weiteren Eigenschaften gezeichnet. strokeRect( )
Zeichnet ein Rechteck (füllt es aber nicht). translate( )
Verschiebt das Benutzerkoordinatensystem des Canvas.
Beschreibung Das CanvasRenderingContext2D-Objekt stellt einen Satz von Grafikfunktionen zum Zeichnen auf einem Canvas zur Verfügung. Obwohl leider kein Text unterstützt wird, sind die vorhandenen Funktionen recht umfangreich. Sie können in mehrere Kategorien unterteilt werden. Rechtecke zeichnen Mit strokeRect( ) und fillRect( ) lassen sich Rechtecke zeichnen und füllen. Außerdem können Sie die von einem Rechteck definierte Fläche mit clearRect( ) löschen.
790 | Referenz für clientseitiges JavaScript
491-0.book Seite 791 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D
Bilder zeichnen In der Canvas-API werden Bilder mit Hilfe von Image-Objekten definiert, die für HTML-Elemente oder Offscreen-Bilder stehen, die mit dem Image( )-Konstruktor erzeugt wurden. (Einzelheiten entnehmen Sie bitte dem Referenzeintrag zu Image.) Ein Canvas-Objekt kann auch als Bildquelle verwendet werden. Mit der drawImage( )-Methode lässt sich ein Bild auf den Canvas zeichnen. In ihrer allgemeinsten Form ermöglicht sie das Skalieren jedes beliebigen, rechteckigen Bereichs des Orginalbildes und seine Wiedergabe auf dem Canvas. Pfade erstellen und wiedergeben Ein leistungsstarkes Feature des Canvas ist seine Fähigkeit, aus einfachen Zeichenfunktionen Formen aufzubauen und dann entweder ihre Umrisse zu zeichnen (mit stroke) oder ihre Fläche auszufüllen (mit fill). Die Gesamtheit der angefallenen Operationen wird als momentaner Pfad bezeichnet. Ein Canvas folgt nur einem einzigen momentanen Pfad.
Sie können mehrere unzusammenhängende Formen im momentanen Pfad erstellen, die dann mit den gleichen Zeichnungsparametern zusammen dargestellt werden. Um Formen voneinander zu trennen, verwenden Sie die moveTo( )-Methode; dadurch wird die derzeitige Position auf eine neue Stelle verschoben, ohne dass eine Verbindungslinie hinzugefügt wird. Durch diesen Vorgang erstellen Sie einen neuen Subpfad, die Canvas-Bezeichnung für eine Gruppe von Operationen, die miteinander verbunden sind. Wenn der Pfad Ihren Bedürfnissen entspricht, können Sie seine Umrisse mit stroke( ) zeichnen und/oder seine Fläche über fill( ) mit Farbe füllen. Die zur Verfügung stehenden Operationen sind lineTo( ) zum Zeichnen von geraden Linien, rect( ) zum Zeichnen von Rechtecken, arc( ) oder arcTo( ) zum Zeichnen von Kreissegmenten und bezierCurveTo( ) oder quadraticCurveTo( ) zum Zeichnen von Kurven. Zusätzlich zur Linienzeichnung und Farbfüllung ist der Pfad bei der Festlegung der für die Wiedergabe des Canvas verwendeten Clip-Region von Nutzen. Pixel innerhalb der Region werden angezeigt; außerhalb liegende Pixel nicht. Die Clip-Region ist kumulativ; beim Aufruf von clip( ) wird die Schnittmenge zwischen momentanem Pfad und momentaner Clip-Region gebildet, wodurch eine neue Region entsteht. Leider kann die Clip-Region nicht direkt auf den gesamten Canvas zurückgesetzt werden; dazu müssen Sie den gesamten Grafikstatus des Canvas speichern und auf den Anfangswert zurücksetzen (das wird weiter unten in diesem Eintrag beschrieben).
Referenz für clientseitiges JavaScript |
791
Referenz für clientseitiges JavaScript
Um mehrere Segmente zu einer Form zusammenzufügen, brauchen wir einen Verbindungspunkt zwischen den Zeichenoperationen. Für diesen Zweck verwaltet der Canvas eine momentane Position. Die Canvas-Zeichenoperationen verwenden diese implizit als ihren Startpunkt und ändern sie typischerweise auf die Position, die ihren jeweiligen Endpunkten entsprechen. Sie können sich das wie das Zeichnen mit einem Stift auf Papier vorstellen: Nach dem Zeichnen einer bestimmten Linie oder Kurve ist die momentane Position dort, wo der Stift nach der Operation zum Stehen kommt.
491-0.book Seite 792 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D
Wenn die Segmente in einem Subpfad keine geschlossene Form bilden, fügen die fill( )- und clip( )-Operationen implizit ein virtuelles Liniensegment zwischen dem Anfangs- und dem Endpunkt des Subpfads ein und schließen damit die Form. Sie können dieses Liniensegment auch explizit mit einem Aufruf von closePath( ) hinzufügen. Farben, Gradienten und Muster Beim Ausfüllen oder Zeichnen von Pfaden können Sie mit den Eigenschaften fillStyle und strokeStyle festlegen, wie die Linien oder gefüllten Flächen wiedergegeben werden. Beide Eigenschaften akzeptieren sowohl Farbstrings im CSS-Stil als auch CanvasGradient- und CanvasPatternObjekte, die Gradienten und Muster beschreiben. Um einen Gradienten zu erzeugen, verwenden Sie die Methoden createLinearGradient( ) oder createRadialGradient( ). Um ein Muster zu erzeugen, verwenden Sie createPattern( ). Um über die CSS-Notation eine Deckfarbe festzulegen, verwenden Sie einen String im Format »#RRGGBB«, wobei RR, GG und BB Hexadezimalzahlen sind, die die Rot-, Blau- und Grünkomponenten der Farbe als Hexadezimalwerte zwischen 00 und FF angeben. Beispielsweise ist »#FF0000« ein leuchtendes Rot. Um eine teilweise transparente Farbe zu erzeugen, verwenden Sie einen String im Format »rgba(R,G,B,A)«. Bei diesem Format geben R, G und B die Rot-, Grün- und Blaukomponenten der Farbe als dezimale Ganzzahlen zwischen 0 und 255 an, und A legt die Alphakomponente (Deckkraft) als Gleitkommazahl zwischen 0.0 (vollständig transparent) und 1.0 (vollständig deckend) fest. Beispielsweise ist »rgba(255,0,0,0.5)« ein halbtransparentes, leuchtendes Rot. Linienbreite, Linienabschlüsse und Linienverbindungen Canvas bietet mehrere Optionen für das Erscheinungsbild von Linien. Mit der Eigenschaft lineWidth legen Sie die Linienbreite fest, mit der Eigenschaft lineCap definieren Sie, wie die Endpunkte der Linien gezeichnet werden, und mit der Eigenschaft lineJoin regeln Sie das Zusammenfügen von Linien. Koordinatensystem und -transformationen Standardmäßig hat das Koordinatensystem eines Canvas seinen Ursprung bei (0,0) in der linken, oberen Ecke des Canvas. Die x-Werte erhöhen sich nach rechts, und die y-Werte erhöhen sich nach unten. Eine einzelne Einheit in diesem Koordinatenraum stellt normalerweise ein einzelnes Pixel dar. Sie können jedoch das Koordinatensystem mit transform so transformieren, dass beliebige von Ihnen festgelegte Koordinaten oder Längen in Zeichenoperationen verschoben, skaliert oder gedreht werden. Das geht mit den Methoden translate( ), scale( ) und rotate( ), die die Transformationsmatrix des Canvas beeinflussen. Da das Koordinatensystem also transformiert werden kann, werden Koordinaten, die von Ihnen an Methoden wie z.B. lineTo( ) übergeben werden, nicht immer in Pixeln gemessen. Aus diesem Grund verwendet die Canvas-API Gleitkommazahlen statt ganzer Zahlen. Transformationen werden in umgekehrter Reihenfolge zu ihrer Festlegung abgearbeitet. Beispielsweise wird bei einem Aufruf von scale( ), dem ein Aufruf von translate( ) folgt, das Koordinatensystem zuerst verschoben und dann skaliert.
792 | Referenz für clientseitiges JavaScript
491-0.book Seite 793 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D.arc( )
Compositing Meistens werden Formen übereinander gezeichnet, wobei die neue Form die vorhergehende, darunter gezeichnete Form überdeckt. Das ist das Defaultverhalten eines Canvas. Sie können jedoch viele interessante Operationen durchführen, indem Sie für die globalCompositeOperation-Eigenschaft unterschiedliche Werte festlegen. Diese reichen von Exklusiv-ODEROperationen bis zur Aufhellung oder Verdunkelung von geformten Regionen; eine Liste aller Optionen finden Sie unter CanvasRenderingContext2D.globalCompositeOperation. Schatten Die Canvas-API enthält Eigenschaften, die jeder von Ihnen gezeichneten Form automatisch einen geworfenen Schatten hinzufügen. Als dieses Buch geschrieben wurde, war Safari allerdings der einzige Browser, der diese API implementiert hatte. Die Farbe des Schattens kann mit shadowColor festgelegt und seine Verschiebung mit shadowOffsetX und shadowOffsetY verändert werden. Wie weit der Schatten am Schattenrand ausfransen soll, kann mit shadowBlur festgelegt werden.
Alle Eigenschaften des CanvasRenderingContext2D-Objekts sind Bestandteil des gespeicherten Status (mit Ausnahme der canvas-Eigenschaft, die eine Konstate ist). Die Transformationsmatrix und die Clip-Region sind ebenfalls Teil des Status, der momentane Pfad und die momentane Position aber nicht.
Siehe auch Canvas
CanvasRenderingContext2D.arc( ) Ein Kreisbogen wird mit Hilfe eines Mittelpunktes und eines Radius zum bestehenden Subpfad eines Canvas hinzugefügt.
Die Koordinaten des Kreismittelpunktes, der den Kreisbogen beschreibt. radius
Der Radius des Kreises, der den Kreisbogen beschreibt.
Referenz für clientseitiges JavaScript |
793
Referenz für clientseitiges JavaScript
Den Grafikstatus speichern Mit den Methoden save( ) und restore( ) lässt sich der Status eines CanvasRenderingContext2D-Objekts speichern und zurücksetzen. save( ) schiebt den derzeitigen Status auf einen Stapelspeicher. restore( ) nimmt den zuletzt gespeicherten Status aus dem Stapelspeicher und setzt den momentanen Zeichnungsstatus auf Basis dieser gespeicherten Werte fest.
491-0.book Seite 794 Mittwoch, 4. April 2007 9:55 09
Die Winkel, die die Start- und Endpunkte des Kreisbogens entlang des Kreises festlegen. Diese Winkel werden im Bogenmaß angegeben. Die 3-Uhr-Position entlang der positiven X-Achse entspricht einem Winkel von 0, und die Winkel vergrößern sich im Uhrzeigersinn. gegenUhrzeigersinn
Gibt an, ob der Kreisbogen gegen (true) oder im (false) Uhrzeigersinn auf dem Kreis durchlaufen wird.
Beschreibung Die ersten fünf Argumente dieser Methode geben einen Start- und einen Endpunkt auf einem Kreis an. Beim Aufruf dieser Methode wird eine gerade Linie zwischen dem momentanen Punkt und dem Startpunkt zum momentanen Subpfad hinzugefügt. Dann wird der Kreisbogen entlang des Kreises zwischen Start- und Endpunkt zum Subpfad hinzugefügt. Das letzte Argument gibt die Richtung an, in der der Kreis beim Verbinden der Start- und Endpunkte durchlaufen werden soll. Diese Methode belässt den momentanen Punkt auf dem Endpunkt des Kreisbogens.
Siehe auch CanvasRenderingContext2D.arcTo( ) CanvasRenderingContext2D.beginPath( ) CanvasRenderingContext2D.closePath( )
CanvasRenderingContext2D.arcTo( ) Fügt dem momentanen Subpfad einen Kreisbogen unter Verwendung von Tangentenpunkten und eines Radius hinzu
Der Radius des Kreises, der den Kreisbogen definiert.
Beschreibung Diese Methode fügt dem momentanen Subpfad einen Kreisbogen hinzu, beschreibt diesen Kreisbogen aber ganz anders als die arc( )-Methode. Der Kreisbogen, der zum Pfad hinzugefügt wird, ist ein Kreissegment mit dem angegebenen radius. Der Kreisbogen hat einen Punkt,
794 | Referenz für clientseitiges JavaScript
491-0.book Seite 795 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D.beginPath( )
der die Linie zwischen der momentanen Position und P1 tangiert, und einen Punkt, der die Linie von P1 nach P2 tangiert. Der Kreisbogen beginnt und endet an diesen zwei Tangentenpunkten und wird in der Richtung gezeichnet, die diese zwei Punkte mit dem kürzesten Kreisbogen verbindet. Bei vielen Anwendungen beginnt der Kreisbogen an der momentanen Position und endet bei P2, was aber nicht immer der Fall ist. Wenn die derzeitige Position nicht mit dem Startpunkt des Kreisbogens übereinstimmt, fügt diese Methode eine gerade Linie zwischen der momentanen Position und der Startposition des Kreisbogens ein. Diese Methode belässt die momentane Position auf dem Endpunkt des Kreisbogens.
Beispiel Mit dem folgenden Code können Sie die rechte, obere Ecke eines Rechtecks zeichnen und ihr eine abgerundete Ecke geben: // // // //
oben links beginnen horizontale Linie bis zum Beginn der abgerundeten Ecke abgerundete Ecke senkrechte Linie nach rechts unten
Fehler Firefox 1.5 unterstützt diese Methode nicht.
Siehe auch CanvasRenderingContext2D.arc( )
CanvasRenderingContext2D.beginPath( ) Beginnt eine neue Gruppe von Subpfaden auf einem Canvas
Überblick void beginPath( )
Beschreibung beginPath( ) löscht alle bisher definierten Pfade und beginnt einen neuen Pfad. Der momentane Punkt wird auf (0,0) gesetzt.
Beim ersten Erstellen des Kontextes für einen Canvas wird automatisch beginPath( ) aufgerufen.
Siehe auch CanvasRenderingContext2D.closePath( ) CanvasRenderingContext2D.fill( ) CanvasRenderingContext2D.stroke( )
Die Koordinaten des Kontrollpunkts, der mit dem Startpunkt der Kurve assoziiert wird (die momentane Position). cpX2, cpY2
Die Koordinaten des Kontrollpunkts, der mit dem Endpunkt der Kurve assoziiert wird. x, y
Die Koordinaten des Kurvenendpunktes.
Beschreibung bezierCurveTo( ) fügt dem momentanen Subpfad eines Canvas eine kubische Bézierkurve
hinzu. Der Startpunkt der Kurve ist der momentane Punkt auf dem Canvas, und der Endpunkt ist (x,y). Die zwei Bézier-Kontrollpunkte (cpX1, cpY1) und (cpX2, cpY2) bestimmen die Kurvenform. Nach dem Ausführen der Methode liegt die momentane Position auf (x,y).
Siehe auch CanvasRenderingContext2D.quadraticCurveTo( )
CanvasRenderingContext2D.clearRect( ) Löschen eines rechteckigen Bereichs auf dem Canvas
Überblick void clearRect(float x, float y, float breite, float hoehe)
Argumente x, y
Die Koordinaten der linken oberen Ecke des Rechtecks. breite, hoehe
Die Abmessungen des Rechtecks.
Beschreibung clearRect( ) löscht das angegebene Rechteck durch Füllen mit einer transparenten Farbe.
796 | Referenz für clientseitiges JavaScript
491-0.book Seite 797 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D.clip( )
CanvasRenderingContext2D.clip( ) Legt den Clippingpfad des Canvas fest
Überblick void clip( )
Beschreibung Diese Methode begrenzt den momentanen Pfad mit Hilfe des momentanen Clippingpfades und verwendet dann den begrenzten Pfad als den neuen Clippingpfad. Beachten Sie, dass es keine Möglichkeit gibt, den Clippingpfad zu vergrößern. Falls Sie einen temporären Clippingpfad brauchen, sollten Sie zuerst save( ) aufrufen, um dann mit restore( ) den ursprünglichen Clippingpfad wiederherstellen zu können. Der Default-Clippingpfad für einen Canvas ist das Canvas-Rechteck selbst. Diese Methode setzt den momentanen Pfad auf einen leeren Pfad zurück. Referenz für clientseitiges JavaScript
CanvasRenderingContext2D.closePath( ) Schließt einen offenen Subpfad
Überblick void closePath( )
Beschreibung Wenn der momentane Subpfad des Canvas offen ist, so schließt ihn die Methode closePath( ), indem sie eine Linie einfügt, die den momentanen Punkt mit dem Startpunkt des Subpfades verbindet. Wenn der Subpfad bereits geschlossen ist, hat diese Methode keine Auswirkung. Nach dem Schließen eines Subpfades können ihm keine weiteren Linien oder Kurven hinzugefügt werden. Um den Pfad weiter zu vergrößern, müssen Sie durch Aufruf von moveTo( ) einen neuen Subpfad beginnen. Sie müssen closePath( ) nicht aufrufen, bevor Sie einen Pfad zeichnen oder füllen. Beim Füllen eines Pfads wird er implizit geschlossen (wie auch beim Aufruf von clip( )).
Siehe auch CanvasRenderingContext2D.beginPath( ) CanvasRenderingContext2D.moveTo( ) CanvasRenderingContext2D.stroke( ) CanvasRenderingContext2D.fill( )
Referenz für clientseitiges JavaScript |
797
491-0.book Seite 798 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D.createLinearGradient( )
CanvasRenderingContext2D.createLinearGradient( ) Einen linearen Farbgradienten erzeugen
Die Koordinaten des Gradientenanfangspunkts. xEnde, yEnde
Die Koordinaten des Gradientenendpunkts. Rückgabewert Ein CanvasGradient-Objekt, das einen linearen Farbgradienten darstellt.
Beschreibung Diese Methode erzeugt und gibt ein neues CanvasGradient-Objekt zurück, das die Farbe linear zwischen dem angegebenen Start- und Endpunkt interpoliert. Beachten Sie, dass diese Methode keine Farben für den Gradienten festlegt. Dazu verwenden Sie die addColorStop( )-Methode des zurückgegebenen Objekts. Um mit Hilfe eines Gradienten Linien zu zeichnen oder Flächen auszufüllen, weisen Sie der strokeStyle oder fillStyle-Eigenschaft ein CanvasGradient-Objekt zu.
Siehe auch CanvasGradient.addColorStop( ), CanvasRenderingContext2D.createRadialGradient( )
CanvasRenderingContext2D.createPattern( ) Erzeugt ein Muster aus gekachelten Bildern
Das zu kachelnde Bild. Dieses Argument ist in der Regel ein Image-Objekt. Sie können aber auch ein Canvas-Element verwenden. wiederholStil
Gibt an, wie das Bild gekachelt wird. Mögliche Werte sind folgende: Wert
Bedeutung
repeat
Kachele das Bild in beide Richtungen. Das ist der Defaultwert.
repeat-x
Kachele das Bild nur in X-Richtung.
repeat-y
Kachele das Bild nur in Y-Richtung.
no-repeat
Kachele das Bild nicht; verwende es nur einmal.
798 | Referenz für clientseitiges JavaScript
491-0.book Seite 799 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D.createRadialGradient( )
Rückgabewert Ein CanvasPattern-Objekt, das das Muster darstellt.
Beschreibung Diese Methode erzeugt und gibt ein CanvasPattern-Objekt zurück, das das von einem gekachelten Bild definierte Muster repräsentiert. Um ein Muster zum Zeichnen von Linien oder zum Füllen von Flächen zu verwenden, setzen Sie ein CanvasPattern-Objekt als Wert für die strokeStyle oder fillStyle-Eigenschaft.
Fehler Firefox 1.5 unterstützt lediglich den "repeat"-Stil. Andere Stile werden ignoriert.
Siehe auch CanvasPattern
Referenz für clientseitiges JavaScript
CanvasRenderingContext2D.createRadialGradient( ) Erzeugt einen radialen Farbgradienten
Die Koordinaten des Startkreismittelpunkts. radiusStart
Der Radius des Startkreises. xEnde, yEnde
Die Koordinaten des Endkreismittelpunkts. radiusEnde
Der Radius des Endkreises. Rückgabewert Ein CanvasGradient-Objekt, das einen radialen Farbgradienten widerspiegelt.
Beschreibung Diese Methode erzeugt und gibt ein neues CanvasGradient-Objekt zurück, das Farben zwischen den Umfängen der zwei angegebenen Kreise radial interpoliert. Beachten Sie, dass diese Methode keine Farben für den Gradienten festlegt. Dazu verwenden Sie die addColorStop( )-Methode des zurückgegebenen Objekts. Um mit Hilfe eines Gradienten Linien zu zeichnen oder Flächen auszufüllen, weisen Sie der strokeStyle oder fillStyle-Eigenschaft ein CanvasGradient-Objekt zu.
Referenz für clientseitiges JavaScript |
799
491-0.book Seite 800 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D.drawImage( )
Radialgradienten werden wiedergegeben, indem die Farbe bei Offset 0 für den Umfang des ersten Kreises verwendet wird, die Farbe bei Offset 1 für den zweiten Kreis und interpolierte Farbwerte (Rot, Grün, Blau und Alpha) für Kreise zwischen diesen beiden Kreisen.
Siehe auch CanvasGradient.addColorStop( ), CanvasRenderingContext2D.createLinearGradient( )
CanvasRenderingContext2D.drawImage( ) Zeichnet ein Bild
Das zu zeichnende Bild. Dieses muss ein Image-Objekt sein, das ein -Tag repräsentiert, oder auch ein Offscreen-Bild oder ein Canvas-Objekt. x, y
Der Punkt, an dem die linke obere Ecke des Bildes gezeichnet wird. breite, hoehe
Die Größe, in der das Bild gezeichnet werden soll. Die Spezifikation dieser Argumente skaliert das Bild. sourceX, sourceY
Die linke obere Ecke der zu zeichnenden Bildregion. Diese ganzzahligen Argumente werden in Bildpixeln angegeben. sourceBreite, sourceHoehe
Die Abmessungen der zu zeichnenden Bildregion, angegeben in Bildpixeln. destX, destY
Die Canvas-Koordinaten, an denen die linke obere Ecke der Bildregion gezeichnet werden soll. destBreite, destHoehe
Die Canvas-Dimensionen, mit denen die Bildregion gezeichnet werden soll.
Beschreibung Bei dieser Methode gibt es drei Varianten. Bei der ersten Variante wird das gesamte Bild auf den Canvas kopiert: Die linke, obere Ecke wird auf den angegebenen Punkt gesetzt, und jeder
800 | Referenz für clientseitiges JavaScript
491-0.book Seite 801 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D.fill( )
Bildpixel wird auf eine Einheit im Canvas-Koordinatensystem abgebildet. Bei der zweiten Variante wird ebenfalls das gesamte Bild auf den Canvas kopiert, Sie können die gewünschte Breite und Höhe des Bildes jedoch in Canvas-Einheiten festlegen. Die dritte Variante ist ganz variabel: Mit ihr können Sie jede beliebige, rechteckige Bildregion festlegen und kopieren, wobei das Bild beliebig auf jeder Position im Canvas skaliert werden kann. Das an diese Methode übergebene Bild muss ein Image- oder Canvas-Objekt sein. Ein ImageObjekt kann ein -Tag im Dokument oder ein über den Image( )-Konstruktor erstelltes Offscreen-Bild repräsentieren.
Siehe auch Image
CanvasRenderingContext2D.fill( ) Füllt den Pfad Referenz für clientseitiges JavaScript
Überblick void fill( )
Beschreibung fill( ) füllt den momentanen Pfad mit der/dem von der fillStyle-Eigenschaft festgelegten Farbe bzw. Gradienten oder Muster. Jeder Subpfad des Pfades wird getrennt gefüllt. Alle nicht geschlossenen Subpfade werden so gefüllt, als wäre die closePath( )-Methode für sie aufgerufen worden. (Beachten Sie dabei, dass diese Subpfade dadurch aber nicht geschlossen werden.)
Über die sogenannte »non-zero winding rule« stellt der Canvas fest, welche Punkte innerhalb und welche außerhalb des Pfades liegen. Die Details dieser Regel sprengen den Umfang dieses Buches, sind aber normalerweise nur für komplizierte Pfade von Bedeutung, die sich selbst überkreuzen. Durch das Füllen eines Pfades wird dieser nicht gelöscht. Nach dem Aufruf von fill( ) können Sie stroke( ) aufrufen, ohne den Pfad neu zu definieren.
Siehe auch CanvasRenderingContext2D.fillRect( )
CanvasRenderingContext2D.fillRect( ) Füllt ein Rechteck
Überblick void fillRect(float x, float y, float breite, float hoehe)
Referenz für clientseitiges JavaScript |
801
491-0.book Seite 802 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D.globalCompositeOperation
Argumente x, y
Die Koordinaten der linken oberen Ecke eines Rechtecks. breite, hoehe
Die Abmessungen des Rechtecks.
Beschreibung fillRect( ) füllt das angegebene Rechteck mit der/dem von der fillStyle-Eigenschaft festgelegten Farbe bzw. Gradienten oder Muster.
Derzeitige Implementierungen von fillRect( ) löschen außerdem den Pfad, so als ob beginPath( ) aufgerufen worden wäre. Dieses überraschende Verhalten ist nicht unbedingt standardisiert, sodass Sie sich nicht darauf verlassen sollten.
Siehe auch CanvasRenderingContext2D.fill( ) CanvasRenderingContext2D.rect( ) CanvasRenderingContext2D.strokeRect( )
CanvasRenderingContext2D.globalCompositeOperation Legt fest, wie Farben auf dem Canvas kombiniert werden
Überblick String globalCompositeOperation
Beschreibung Diese Eigenschaft legt fest, wie Farben, die auf dem Canvas wiedergegeben werden, mit den bereits auf dem Canvas vorhandenen Farben kombiniert werden. Die möglichen Werte und ihre Bedeutungen werden in der unten stehenden Tabelle aufgeführt. Der Begriff Ursprung in diesen Werten bezieht sich auf die auf den Canvas zu zeichnenden Farben, und der Begriff Ziel bezieht sich auf die auf dem Canvas bereits vorhandenen Farben. Der Defaultwert ist »source-over«. Wert
Bedeutung
copy
Zeichnet nur die neue Form und löscht alles andere.
darker
Für die Überlappungsflächen der beiden Formen wird die Farbe durch Subtraktion der Farbwerte bestimmt.
destination-atop
Der bereits vorhandene Inhalt wird nur dort beibehalten, wo er mit der neuen Form überlappt. Die neue Form wird hinter dem Inhalt gezeichnet.
destination-in
Vorhandener Inhalt wird dort beibehalten, wo die neue Form mit dem vorhandenen Canvas-Inhalt überlappt . Alle anderen Bereiche werden transparent.
destination-out
Vorhandener Inhalt wird dort beibehalten, wo er nicht mit der neuen Form überlappt. Alle anderen Bereiche werden transparent.
802 | Referenz für clientseitiges JavaScript
491-0.book Seite 803 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D.lineCap Wert
Bedeutung
destination-over
Die neue Form wird hinter vorhandenem Inhalt gezeichnet.
lighter
Wo beide Formen überlappen, wird die Farbe durch Addition der beiden Farbwerte bestimmt.
source-atop
Die neue Form wird nur dort gezeichnet, wo sie den vorhandenen Inhalt überdeckt.
source-in
Die neue Form wird nur dort gezeichnet, wo die neue Form mit dem vorhandenen Inhalt überlappt. Alle anderen Bereiche werden transparent.
source-out
Die neue Form wird dort gezeichnet, wo sie nicht mit bestehendem Inhalt überlappt.
source-over
Die neue Form wird über den bestehenden Inhalt gezeichnet. Das ist der Defaultwert.
xor
Formen werden an den Stellen transparent angezeigt, an denen beide überlappen. In anderen Bereichen werden sie normal gezeichnet.
Fehler Firefox 1.5 unterstützt die Werte »copy« und »darker« nicht. Referenz für clientseitiges JavaScript
CanvasRenderingContext2D.lineCap Gibt an, wie die Linienenden wiedergegeben werden.
Überblick String lineCap
Beschreibung Die lineCap-Eigenschaft gibt an, wie Linien enden sollen. Das ist nur beim Zeichnen von breiten Linien von Bedeutung. Die unten stehende Tabelle führt die zulässigen Werte für diese Eigenschaft auf. Der Standardwert ist »butt«. Wert
Bedeutung
butt
Dieser Defaultwert gibt an, dass die Linie am Ende nicht abgerundet wird. Der Linienabschluss ist gerade und rechtwinklig zur Linienrichtung. Die Linie wird nicht über ihren Endpunkt hinaus erweitert.
round
Dieser Wert legt fest, dass Linien mit einem Halbkreis abgerundet werden, dessen Durchmesser der Linienbreite entspricht und der um die halbe Linienbreite über das Linienende hinausragt.
square
Dieser Wert legt fest, dass Linien mit einem Rechteck enden sollen. Der Wert entspricht »butt«, aber die Linie wird um eine halbe Linienbreite erweitert.
Fehler Firefox 1.5 implementiert den Stil »butt« für Linienabschlüsse nicht richtig. Die »butt«-Linienenden werden wie »square«-Linienabschlüsse dargestellt.
Siehe auch CanvasRenderingContext2D.lineJoin
Referenz für clientseitiges JavaScript |
803
491-0.book Seite 804 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D.lineJoin
CanvasRenderingContext2D.lineJoin Legt fest, wie Eckpunkte wiedergeben werden
Überblick String lineJoin
Beschreibung Bei Pfaden, die Eckpunkte enthalten, an denen Liniensegmente und/oder Kurven zusammentreffen, gibt die Eigenschaft lineJoin an, wie diese Eckpunkte gezeichnet werden. Die Eigenschaft wirkt sich nur dann sichtbar aus, wenn breite Linien gezeichnet werden. Der Defaultwert der Eigenschaft ist »miter«; ist er gesetzt, werden die äußeren Kanten der beiden Liniensegmente so lange verlängert, bis sie aufeinandertreffen. Treffen die Linien spitzwinklig zusammen, können die Gehrungsverbindungen recht lang werden. Die Eigenschaft miterLimit legt eine obere Grenze für die Gehrungslänge fest. Wird diese Grenze erreicht, wird die Gehrung schräg abgeschnitten. Beim Wert »round« wird an die Außenkanten des Scheitelpunktes ein ausgefüllter Kreisbogen mit einem Durchmesser in der Linienbreite angefügt. Beim Wert »bevel« werden die Außenkanten der Eckpunkte mit Hilfe eines ausgefüllten Dreiecks verbunden.
Fehler Firefox 1.5 implementiert »bevel« falsch und zeigt eine runde Verbindung an. Außerdem werden Gehrungsverbindungen nicht richtig angezeigt, wenn sie in einer teilweise transparenten Farbe gezeichnet werden.
Siehe auch CanvasRenderingContext2D.lineCap, CanvasRenderingContext2D.miterLimit
CanvasRenderingContext2D.lineTo( ) Fügt dem momentanen Subpfad eine gerade Linie hinzu
Überblick void lineTo(float x, float y)
Argumente x, y
Die Koordinaten des Linienendpunkts.
804 | Referenz für clientseitiges JavaScript
491-0.book Seite 805 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D.miterLimit
Beschreibung lineTo( ) fügt dem momentanen Subpfad eine gerade Linie hinzu. Die Linie beginnt am momentanen Punkt und endet bei (x,y). Nach dem Ausführen der Methode liegt die momentane Position auf (x,y).
Siehe auch CanvasRenderingContext2D.beginPath( ), CanvasRenderingContext2D.moveTo( )
CanvasRenderingContext2D.miterLimit Verhältnis zwischen der maximalen Gehrungslänge und der Linienbreite
Überblick float miterLimit
Wenn breite Linien gezeichnet werden, die Eigenschaft lineJoin auf »miter« festgelegt ist und sich zwei Linien im spitzen Winkel treffen, kann die entstehende Gehrung recht lang sein. Zu lange Gehrungen sind optisch irritierend. Die Eigenschaft miterLimit legt eine obere Schranke für die Gehrungslänge fest. Die Eigenschaft gibt ein Verhältnis zwischen der Gehrungslänge und der Linienbreite an. Der Defaultwert ist 10, was bedeutet, dass die Gehrung nicht länger als die zehnfache Linienbreite sein soll. Erreicht eine Gehrung diese Länge, wird sie schräg abgeschnitten. Die Eigenschaft hat keine Auswirkung, wenn lineJoin auf »round« oder »bevel« gesetzt ist.
Fehler Firefox 1.5 implementiert diese Eigenschaft nicht richtig. Wenn eine Gehrungsverbindung die Grenze miterLimit überschreitet, werden die Linien rund statt per Gehrung verbunden.
Siehe auch CanvasRenderingContext2D.lineJoin
CanvasRenderingContext2D.moveTo( ) Legt die derzeitige Position fest und beginnt mit einem neuen Subpfad.
Überblick void moveTo(float x, float y)
Argumente x, y
Die Koordinaten des neuen momentanen Punkts.
Referenz für clientseitiges JavaScript |
805
Referenz für clientseitiges JavaScript
Beschreibung
491-0.book Seite 806 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D.quadraticCurveTo( )
Beschreibung moveTo( ) setzt die momentane Position auf (x,y) und erzeugt einen neuen Subpfad, dessen erster Punkt dieser Punkt ist. Falls ein vorhergehender Subpfad vorhanden war, der aus nur einem Punkt bestand, wird dieser Subpfad aus dem Pfad entfernt.
Siehe auch CanvasRenderingContext2D.beginPath( )
CanvasRenderingContext2D.quadraticCurveTo( ) Fügt dem momentanen Subpfad eine quadratische Bézierkurve hinzu
Beschreibung Diese Methode fügt dem momentanen Subpfad ein Segment einer quadratischen Bézierkurve hinzu. Die Kurve beginnt am momentanen Punkt und endet bei (x,y). Der Kontrollpunkt (cpX, cpY) legt die Kurvenform zwischen den beiden Punkten fest. (Eine Beschreibung der mathematischen Eigenschaften von Bézierkuven würde den Umfang dieses Buches allerdings sprengen.) Nach dem Ausführen der Methode liegt die momentane Position auf (x,y).
Fehler Firefox 1.5 implementiert diese Methode nicht richtig.
Siehe auch CanvasRenderingContext2D.bezierCurveTo( )
CanvasRenderingContext2D.rect( ) Fügt dem Pfad einen rechteckigen Subpfad hinzu
Überblick void rect(float x, float y, float breite, float hoehe)
806 | Referenz für clientseitiges JavaScript
491-0.book Seite 807 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D.restore( )
Argumente x, y
Die Koordinaten der linken oberen Ecke des Rechtecks. breite, hoehe
Die Abmessungen des Rechtecks.
Beschreibung Diese Methode fügt ein Rechteck zum Pfad hinzu. Dieses Rechteck sitzt in einem eigenständigen Subpfad und ist mit keinem anderen Subpfad im Pfad verbunden. Nach dem Ausführen der Methode liegt die momentane Position auf (0,0).
Siehe auch CanvasRenderingContext2D.fillRect( ), CanvasRenderingContext2D.strokeRect( )
Referenz für clientseitiges JavaScript
CanvasRenderingContext2D.restore( ) Setzt den Zeichnungsstatus auf die gespeicherten Werte zurück
Überblick void restore( )
Beschreibung Diese Methode holt den obersten Eintrag vom Stapel der gespeicherten Grafikzustände und setzt die Werte der Eigenschaften CanvasRenderingContext2D, den Clippingpfad und die Transformationsmatrix zurück. Weitere Informationen finden Sie unter der save( )-Methode.
Fehler Firefox 1.5 speichert und setzt die Eigenschaft strokeStyle nicht richtig zurück.
Siehe auch CanvasRenderingContext2D.save( )
CanvasRenderingContext2D.rotate( ) Dreht das Koordinatensystem des Canvas
Überblick void rotate(float winkel)
Argumente winkel
Der Drehumfang in Bogenmaß. Positive Werte ergeben eine Drehung im Uhrzeigersinn und negative Werte eine Drehung gegen den Uhrzeigersinn.
Referenz für clientseitiges JavaScript |
807
491-0.book Seite 808 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D.save( )
Beschreibung Diese Methode ändert die Abbildung von Canvas-Koordinaten auf Pixel im -Element im Webbrowser, wodurch alle folgenden Zeichnungen im Canvas um den angegeben Winkel gedreht erscheinen. Das -Element selbst wird dabei nicht gedreht. Beachten Sie, dass der Winkel im Bogenmaß angegeben wird. Um Grad ins Bogenmaß umzurechnen, multiplizieren Sie sie mit Math.PI und teilen das Ergebnis durch 180.
Siehe auch CanvasRenderingContext2D.scale( ), CanvasRenderingContext2D.translate( )
CanvasRenderingContext2D.save( ) Speichert eine Kopie des momentanen Grafikstatus
Überblick void save( )
Beschreibung save( ) schiebt den momentanen Grafikstatus auf einen Stapelspeicher, der aus den gespeicherten Grafikzuständen besteht. Dadurch können Sie den Grafikstatus vorübergehend ändern und dann die vorherigen Werte durch den Aufruf von restore( ) wiederherstellen.
Der Grafikstatus eines Canvas enthält alle Eigenschaften des CanvasRenderingContext2DObjekts (mit Ausnahme der schreibgeschützten Eigenschaft canvas). Er enthält außerdem die Transformationsmatrix, die sich aus den Aufrufen von rotate( ), scale( ) und translate( ) ergibt. Zusätzlich enthält er den Clippingpfad, der durch die clip( )-Methode festgelegt wird. Beachten Sie, dass der momentane Pfad und die momentane Position nicht Teil des Grafikstatus sind und von dieser Methode nicht gespeichert werden.
Fehler Firefox 1.5 speichert die Eigenschaft strokeStyle nicht und setzt sie auch nicht zurück.
Siehe auch CanvasRenderingContext2D.restore( )
CanvasRenderingContext2D.scale( ) Skaliert das Benutzerkoordinatensystem des Canvas.
Überblick void scale(float sx, float sy)
808 | Referenz für clientseitiges JavaScript
491-0.book Seite 809 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D.stroke( )
Argumente sx, sy
Die horizontalen und vertikalen Skalierfaktoren.
Beschreibung scale( ) fügt der momentanen Transformationsmatrix des Canvas eine Skaliertransformation hinzu. Die Skalierung findet mit Hilfe von unabhängigen horizontalen und vertikalen Skalierfaktoren statt. Werden beispielsweise die Werte 2,0 und 0,5 übergeben, wird der anschließend gezeichnete Pfad doppelt so breit und halb so hoch. Bei negativen Werten für sx werden die XKoordinaten an der Y-Achse gespiegelt. Bei negativen Werten für sy werden die Y-Koordinaten an der X-Achse gespiegelt.
Siehe auch CanvasRenderingContext2D.rotate( ), CanvasRenderingContext2D.translate( )
Referenz für clientseitiges JavaScript
CanvasRenderingContext2D.stroke( ) Zeichnet den momentanen Pfad
Überblick void stroke( )
Beschreibung Die Methode stroke( ) zeichnet den Umriss des momentanen Pfads. Der Pfad bestimmt die Geometrie der erzeugten Linie, die optische Erscheinung dieser Linie wird aber von den Eigenschaften strokeStyle, lineWidth, lineCap, lineJoin und miterLimit bestimmt. Der Begriff stroke bezieht sich auf einen Stift- oder Pinselstrich. Er bedeutet »zeichne den Umriss von«. Beachten Sie den Unterschied zwischen der stroke( )-Methode, die den Umriss eines Pfads zeichnet, und der fill( )-Methode, die das Innere eines Pfads ausfüllt.
Siehe auch CanvasRenderingContext2D.fill( ) CanvasRenderingContext2D.lineCap CanvasRenderingContext2D.lineJoin CanvasRenderingContext2D.strokeRect( )
CanvasRenderingContext2D.strokeRect( ) Zeichnet ein Rechteck
Überblick void strokeRect(float x, float y, float breite, float hoehe)
Referenz für clientseitiges JavaScript |
809
491-0.book Seite 810 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CanvasRenderingContext2D.translate( )
Argumente x, y
Die Koordinaten der linken oberen Ecke des Rechtecks. breite, hoehe
Die Abmessungen des Rechtecks.
Beschreibung Diese Methode zeichnet den Umriss eines Rechtecks mit der angegebenen Position und Größe (füllt das Innere aber nicht aus). Die Linienfarbe und -breite werden über die Eigenschaften strokeStyle und lineWidth festgelegt. Die Eckform des Rechtecks wird über die Eigenschaft lineJoin angegeben. Derzeitige Implementierungen von strokeRect( ) löschen den Pfad, so als ob beginPath( ) aufgerufen worden wäre. Dieses überraschende Verhalten ist nicht unbedingt standardisiert, sodass Sie sich nicht darauf verlassen sollten.
Siehe auch CanvasRenderingContext2D.fillRect( ) CanvasRenderingContext2D.lineJoin CanvasRenderingContext2D.rect( ) CanvasRenderingContext2D.stroke( )
CanvasRenderingContext2D.translate( ) Verschiebt das Benutzerkoordinatensystem des Canvas
Überblick void translate(float dx, float dy)
Argumente dx, dy
Die Beträge, um die in der X- und Y-Dimension verschoben werden soll.
Beschreibung translate( ) fügt der Transformationsmatrix des Canvas horizontale und vertikale Offsets hinzu. Die Argumente dx und dy werden allen Punkten bei anschließend definierten Pfaden
hinzugefügt.
Siehe auch CanvasRenderingContext2D.rotate( ), CanvasRenderingContext2D.scale( )
810 | Referenz für clientseitiges JavaScript
491-0.book Seite 811 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CDATASection
CDATASection Ein CDATA-Knoten in einem XML-Dokument
DOM Level 1 XML Node ➝ CharacterData ➝ Text ➝ CDATASection
Beschreibung Dieses nur selten benutzte Interface stellt einen CDATA-Abschnitt in einem XML-Dokument dar. Programmierer, die mit HTML-Dokumenten arbeiten, stoßen nie auf Knoten dieses Typs und brauchen auch dieses Interface nicht zu benutzen. CDATASection ist ein Subinterface von Text und definiert keine eigenen Eigenschaften oder Methoden. Auf den Textinhalt des CDATA-Abschnitts wird mit der aus Node geerbten nodeValue-Eigenschaft oder der aus CharacterData geerbten data-Eigenschaft zugegriffen. Sie können CDATASection-Knoten zwar oft wie Text-Knoten behandeln, müssen aber dabei beachten, dass die Methode Node.normalize( ) keine benachbarten CDATA-Abschnitte miteinander verschmilzt. CDATASection erzeugt mit Document.createCDATASection( ) eine CDATASection. Referenz für clientseitiges JavaScript
Siehe auch CharacterData, Text
CharacterData
DOM Level 1 Core
Gemeinsame Funktionalität für Text- und Kommentarknoten
Node ➝ CharacterData
Subinterfaces Comment, Text
Eigenschaften String data
Der Textinhalt dieses Knotens. readonly unsigned long length
Die Anzahl der Zeichen in diesem Knoten.
Methoden appendData( )
Hängt den angegebenen String an den Textinhalt dieses Knotens an. deleteData( )
Löscht Text aus diesem Knoten. Beginnt mit dem Zeichen am angegebenen Offset und löscht ab dort die angegebene Anzahl Zeichen. insertData( )
Fügt den angegebenen String in den Text dieses Knotens an dem Zeichen ein, das durch den Offset angegeben ist.
Referenz für clientseitiges JavaScript |
811
491-0.book Seite 812 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CharacterData.appendData( ) replaceData( )
Ersetzt die Zeichen ab dem angegebenen Zeichen-Offset bis zur angegebenen Anzahl von Zeichen durch den spezifizierten String. substringData( )
Gibt eine Kopie des Texts vom angegebenen Zeichen-Offset bis zur spezifizierten Zeichenzahl zurück.
Beschreibung CharacterData ist das Superinterface für Text- und Kommentarknoten. Dokumente enthalten nie CharacterData-Knoten, sondern nur Text- und Kommentarknoten. Da jedoch diese beiden Knotentypen eine ähnliche Funktionalität haben, ist diese Funktionalität hier definiert, damit Text und Comment sie beide erben können. Beachten Sie, dass es nicht notwendig ist, die von diesem Interface definierten Methoden zur Stringmanipulation zu verwenden. Die data-Eigenschaft ist ein normaler JavaScript-String, den Sie mit dem +-Operator (bei Stringverknüpfungen) und verschiedenen String- und RegExpMethoden ändern können.
Siehe auch Comment, Text
CharacterData.appendData( )
DOM Level 1 Core
Hängt einen String an einen Text- oder Kommentarknoten an
Der String, der an den Text- oder Kommentarknoten angehängt wird. Exceptions Diese Methode löst eine DOMException mit dem code NO_MODIFICATION_ALLOWED_ERR aus, wenn sie auf einem schreibgeschützten Knoten aufgerufen wird.
Beschreibung Diese Methode hängt den String arg an das Ende der data-Eigenschaft dieses Knotens an.
812 | Referenz für clientseitiges JavaScript
491-0.book Seite 813 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CharacterData.deleteData( )
CharacterData.deleteData( )
DOM Level 1 Core
Löscht Zeichen aus einem Text- oder Kommentarknoten
Überblick void deleteData(unsigned long offset, unsigned long anzahl) throws DOMException;
Argumente offset
Die Position des ersten zu löschenden Zeichens. anzahl
Die Anzahl der zu löschenden Zeichen. Exceptions Diese Methode kann eine DOMException mit einem der folgenden code-Werte auslösen: Das Argument offset oder anzahl ist negativ, oder offset ist größer als die Länge des Textoder Kommentarknotens. NO_MODIFICATION_ALLOWED_ERR
Der Knoten ist schreibgeschützt und darf nicht geändert werden.
Beschreibung Diese Methode löscht Zeichen aus diesem Text- oder Kommentarknoten. Sie beginnt mit dem durch offset angegebenen Zeichen und fährt für anzahl Zeichen mit dem Löschen fort. Ist offset plus anzahl größer als die Anzahl der Zeichen des Text- oder Kommentarknotens, so werden ab offset alle Zeichen bis zum Ende des Strings gelöscht.
CharacterData.insertData( )
DOM Level 1 Core
Fügt einen String in einen Text- oder Kommentarknoten ein
Überblick void insertData(unsigned long offset, String arg) throws DOMException;
Argumente offset
Die Zeichenposition im Text- oder Kommentarknoten, an der der String eingefügt werden soll. arg
Der einzufügende String.
Referenz für clientseitiges JavaScript |
813
Referenz für clientseitiges JavaScript
INDEX_SIZE_ERR
491-0.book Seite 814 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CharacterData.replaceData( )
Exceptions Diese Methode kann unter den folgenden Umständen eine DOMException mit einem der folgenden code-Werte auslösen: INDEX_SIZE_ERR offset ist negativ oder größer als die Länge des Text- oder Kommentarknotens. NO_MODIFICATION_ALLOWED_ERR
Der Knoten ist schreibgeschützt und darf nicht geändert werden.
Beschreibung Diese Methode fügt den angegebenen String arg in den Text eines Text- oder Kommentarknotens an der durch offset angegebenen Position ein.
CharacterData.replaceData( )
DOM Level 1 Core
Ersetzt Zeichen eines Text- oder Kommentarknotens durch einen String
Überblick void replaceData(unsigned long offset, unsigned long anzahl, String arg) throws DOMException;
Argumente offset
Die Zeichenposition im Text- oder Kommentarknoten, an der die Ersetzung beginnen soll. anzahl
Die Anzahl der zu ersetzenden Zeichen. arg
Der String, der die durch offset und anzahl angegebenen Zeichen ersetzen soll. Exceptions Diese Methode kann unter den folgenden Umständen eine DOMException mit einem der folgenden code-Werte auslösen: INDEX_SIZE_ERR offset ist negativ oder größer als die Länge des Text- oder Kommentarknotens, oder anzahl ist negativ. NO_MODIFICATION_ALLOWED_ERR
Der Knoten ist schreibgeschützt und darf nicht geändert werden.
Beschreibung Diese Methode ersetzt anzahl Zeichen, beginnend mit der Position offset, durch den Inhalt des Strings arg. Ist die Summe von offset und anzahl größer als die Länge des Text- oder Kommentarknotens, werden beginnend mit offset alle Zeichen ersetzt.
814 | Referenz für clientseitiges JavaScript
491-0.book Seite 815 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CharacterData.substringData( )
Beachten Sie, dass sowohl die insertData( )-Methode als auch die deleteData( )-Methode Spezialfälle dieses Falles darstellen.
CharacterData.substringData( )
DOM Level 1 Core
Extrahiert einen Teilstring aus einem Text- oder Kommentarknoten
Überblick String substringData(unsigned long offset, unsigned long anzahl) throws DOMException;
Argumente offset
Die Position des ersten zurückzugebenden Zeichens. anzahl
Rückgabewert Ein String, der aus anzahl Zeichen des Text- oder Kommentarknotens besteht und der mit dem Zeichen an der Position offset beginnt. Exceptions Diese Methode kann eine DOMException mit einem der folgenden code-Werte auslösen: INDEX_SIZE_ERR offset ist negativ oder größer als die Länge des Text- oder Kommentarknotens, oder anzahl ist negativ. DOMSTRING_SIZE_ERR
Der angegebene Textbereich ist zu lang, um in einen String der JavaScript-Implementierung des Browsers zu passen.
Beschreibung Diese Methode extrahiert aus einem Text- oder Kommentarknoten den Teilstring, der bei der Position offset beginnt und nach anzahl Zeichen endet. Sie nützt nur dann, wenn die Textmenge im Knoten größer als die maximale Zeichenzahl ist, die in einen String einer browserspezifischen JavaScript-Implementierung hineinpasst. In diesem Fall kann ein JavaScript-Programm die data- Eigenschaft des Text- oder Kommentarknotens nicht unmittelbar nutzen, sondern muss mit kürzeren Teilstrings des Knotentexts arbeiten. In der Praxis tritt diese Situation so gut wie nie auf.
Referenz für clientseitiges JavaScript |
815
Referenz für clientseitiges JavaScript
Die Anzahl der Zeichen des zurückzugebenden Teilstrings.
491-0.book Seite 816 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Checkbox
Checkbox Siehe Input
Comment Ein HTML- oder XML-Kommentar
DOM Level 1 Core Node ➝ CharacterData ➝ Comment
Beschreibung Ein Kommentarknoten repräsentiert einen Kommentar in einem HTML- oder XML-Dokument. Auf den Inhalt des Kommentars (also den Text zwischen ) können Sie über die data-Eigenschaft zugreifen, die aus dem Interface CharacterData geerbt wurde, oder auch über die nodeValue-Eigenschaft aus dem Node-Interface. Dieser Inhalt kann mit den aus CharacterData geerbten Methoden bearbeitet werden. Sie erzeugen mit Document. createComment( ) ein Kommentar-Objekt.
Siehe auch CharacterData
CSS2Properties Eine Menge von CSS-Attributen und ihren Werten
DOM Level 2 CSS2 Object ➝ CSS2Properties
Eigenschaften String cssText
Die Textdarstellung eines Sets von Stilattributen und ihren Werten. Der Text wird wie in einem CSS-Stylesheet formatiert, ohne den Elementselektor und die geschwungenen Klammern, die die Attribute und Werte umgeben. Wenn Sie diese Eigenschaft auf einen unzulässigen Wert setzen, wird eine DOMException mit dem code SYNTAX_ERR ausgelöst. Ist das CSS2Properties-Objekt schreibgeschützt und Sie versuchen die Eigenschaft zu setzen, so wird eine DOMException mit einem code von NO_MODIFICATION_ALLOWED_ERR ausgelöst. Zusätzlich zur cssText-Eigenschaft hat ein CSS2Properties-Objekt auch eine Eigenschaft für jedes CSS-Attribut, das vom Browser unterstützt wird. Diese Eigenschaftsnamen sind eng an die CSS-Attributnamen angelehnt. Geringfügige Abweichungen dienen nur zur Vermeidung von Syntaxfehlern in JavaScript. Attribute, die aus mehreren Wörtern bestehen und Bindestriche enthalten (z.B. »font-family«), werden in JavaScript ohne Bindestriche geschrieben, und jedes Wort hinter dem ersten beginnt mit einem Großbuchstaben: fontFamily. Da auch das Attribut »float« mit dem reservierten Wort float in Konflikt steht, wird es als Eigenschaft cssFloat übersetzt. Die CSS2Properties-Eigenschaftsnamen, die den jeweiligen von der CSS2-Spezifikation definierten Attributen entsprechen, werden in der nachfolgenden Tabelle aufgeführt. Beachten Sie jedoch, dass manche Browser nicht alle CSS-Attribute unterstützen und möglicherweise nicht alle aufgeführten Eigenschaften implementieren. Da die Eigenschaften direkt den CSS-Attri-
816 | Referenz für clientseitiges JavaScript
491-0.book Seite 817 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CSS2Properties
buten entsprechen, werden sie hier nicht einzeln dokumentiert. Angaben zur Bedeutung und zu den zulässigen Werten einzelner Eigenschaften entnehmen Sie bitte einer CSS-Referenz, wie z.B. CSS – Das umfassende Handbuch von Eric A. Meyer (O’Reilly Verlag). Alle Eigenschaften sind Strings. Das Setzen einer beliebigen dieser Eigenschaften kann die gleichen Exceptions auslösen wie das Setzen der cssText-Eigenschaft: azimuth
background
backgroundAttachment
backgroundColor
backgroundImage
backgroundPosition
backgroundRepeat
border
borderBottom
borderBottomColor
borderBottomStyle
borderBottomWidth
borderCollapse
borderColor
borderLeft
borderLeftColor
borderLeftStyle
borderLeftWidth
borderRight
borderRightColor
borderRightStyle
borderRightWidth
borderSpacing
borderStyle
borderTop
borderTopColor
borderTopStyle
borderTopWidth
bottom
captionSide
clear
color
content
counterIncrement
counterReset
cssFloat
cue
cueAfter
cueBefore
cursor
direction
display
elevation
emptyCells
font
fontFamily
fontSize
fontSizeAdjust
fontStretch
fontStyle
fontVariant
fontWeight
height
left
letterSpacing
lineHeight
listStyle
listStyleImage
listStylePosition
listStyleType
margin
marginBottom
marginLeft
marginRight
marginTop
markerOffset
marks
maxHeight
maxWidth
minHeight
minWidth
orphans
outline
outlineColor padding
outlineStyle
outlineWidth
overflow
paddingBottom
paddingLeft
paddingRight
paddingTop
page
pageBreakAfter
pageBreakBefore
pageBreakInside
pause
pauseAfter
pauseBefore
pitch
pitchRange
playDuring
position
quotes
richness
right
size
speak
speakHeader
speakNumeral
speakPunctuation
speechRate
stress
tableLayout
textAlign
textDecoration top
textIndent
textShadow
textTransform
unicodeBidi
verticalAlign
visibility
voiceFamily
volume
whiteSpace
widows
width
wordSpacing
zIndex
Referenz für clientseitiges JavaScript |
Referenz für clientseitiges JavaScript
borderWidth clip
817
491-0.book Seite 818 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CSSRule
Beschreibung Das Interface CSS2Properties stellt ein Set von CSS-Stilattributen und ihren Werten dar. Es definiert für jedes von der CSS2-Spezifikation definierte CSS-Attribut eine JavaScriptEigenschaft. Die style-Eigenschaft eines HTMLElements und die style-Eigenschaft eines CSSRule-Objekts sind les- und schreibbare CSS2Properties-Objekte. Der Rückgabewert von Window.getComputedStyle( ) ist aber ein CSS2Properties-Objekt, dessen Eigenschaften schreibgeschützt sind.
Siehe auch CSSRule, HTMLElement, Window.getComputedStyle( ); Kapitel 16
CSSRule Eine Regel in einem CSS-Stylesheet
DOM Level 2 CSS, IE 5 Object ➝ CSSRule
Eigenschaften String selectorText
Der Selektor, der angibt, auf welche Dokumentelemente sich diese Stilregel bezieht. Das Setzen dieser Eigenschaft löst eine DOMException mit dem code NO_MODIFICATION_ ALLOWED_ERR aus, wenn die Regel schreibgeschützt ist, oder mit dem code SYNTAX_ERR, wenn der neue Wert nicht den CSS-Syntaxregeln entspricht. readonly CSS2Properties style
Die Stilwerte, die für die in selectorText angegebenen Elemente gelten sollen. Beachten Sie, dass die style-Eigenschaft selbst zwar schreibgeschützt ist, die Eigenschaften des SS2Properties-Objekts, auf die sie sich bezieht, aber les- und schreibbar sind.
Beschreibung Ein CSSRule-Objekt repräsentiert eine Regel in einem CSS-Stylesheet: Es repräsentiert Stilinformationen, die auf einen speziellen Satz von Dokumentelementen angewendet werden. selectorText ist die String-Repräsentation des Elementselektors für diese Regel, und style ist ein CSS2Properties-Objekt, das den Satz von Stilattributen und -werten repräsentiert, der auf die ausgewählten Elemente angewandt werden soll. Die DOM Level 2 CSS-Spezifikation definiert im Grunde eine etwas komplexe Hierarchie von CSSRule-Interfaces, um verschiedene Arten von Regeln darzustellen, die in einem CSSStyleSheet vorkommen können. Tatsächlich werden die hier aufgeführten Eigenschaften durch das DOM CSSStyleRule-Interface definiert. Style-Regeln stellen die häufigste und wichtigste Art von Regeln in einem Stylesheet dar. Die hier aufgeführten Eigenschaften sind die einzigen, die über alle Browser hinweg portabel verwendet werden können. IE unterstützt die DOM Level 2Spezifikation nicht sehr gut (zumindest nicht über IE 7), implementiert aber ein CSSRuleObjekt, das die beiden hier aufgeführten Eigenschaften unterstützt.
Siehe auch CSS2Properties, CSSStyleSheet
818 | Referenz für clientseitiges JavaScript
491-0.book Seite 819 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CSSStyleSheet
CSSStyleSheet
DOM Level 2 CSS, IE 4
Ein CSS-Stylesheet
Object ➝ CSSStyleSheet
Eigenschaften readonly CSSRule[] cssRules
Ein schreibgeschütztes, Array-ähnliches Objekt, das die CSSRule-Objekte enthält, die das Stylesheet bilden. In IE verwenden Sie stattdessen die rules-Eigenschaft. In DOMkonformen Implementierungen enthält dieses Array Objekte, die alle Regeln eines Stylesheets repräsentieren, und zwar einschließlich @-Regeln wie z.B. @import-Anweisungen. Regeln dieser Art implementieren ein anderes Interface als das für CSSRule beschriebene. Diese anderen Typen von Regel-Objekten werden nur schlecht über Browsergrenzen hinweg unterstützt und sind in diesem Buch nicht dokumentiert. Achten Sie also darauf, dass Sie alle Einträge in diesem Array daraufhin testen, ob sie CSSRule-Eigenschaften repräsentieren, bevor Sie versuchen, diese Eigenschaften zu verwenden. boolean disabled
readonly String href
Die URL eines Stylesheet, das mit dem Dokument verknüpft ist, oder null bei InlineStylesheets. readonly StyleSheet parentStyleSheet
Das Stylesheet, in dem dieses hier enthalten war, oder null, wenn dieses Stylesheet unmittelbar in das Dokument eingebunden war. readonly CSSRule[] rules
Das IE-Äquivalent des DOM-Standard-cssRules[]-Arrays. readonly String title
Der Titel des Stylesheets, sofern einer festgelegt ist. Ein Titel kann über das title-Attribut eines - oder -Elements festgelegt werden, das sich auf dieses Stylesheet bezieht. readonly String type
Der Typ dieses Stylesheets als MIME-Typ. CSS-Stylesheets haben den Typ »text/css«.
Methoden addRule( )
IE-spezifische Methode, um einem Stylesheet eine CSS-Regel hinzuzufügen. deleteRule( )
DOM-Standardmethode zum Löschen der Regel an der angegebenen Position. insertRule( )
DOM-Standardmethode zum Einfügen einer neuen Regel in das Stylesheet. removeRule( )
IE-spezifische Methode zum Entfernen einer Regel.
Referenz für clientseitiges JavaScript |
819
Referenz für clientseitiges JavaScript
Ist diese Eigenschaft true, so ist das Stylesheets deaktiviert und wird nicht auf das Dokument angewendet. Ist diese Eigenschaft false, so ist das Stylesheet aktiviert und wird auf das Dokument angewendet.
491-0.book Seite 820 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CSSStyleSheet.addRule( )
Beschreibung Dieses Interface repräsentiert ein CSS-Stylesheet. Es hat Eigenschaften und Methoden zur Deaktivierung des Stylesheets sowie zum Abfragen, Einfügen und Entfernen von Style-Regeln. IE implementiert eine API, die etwas vom DOM-Standard abweicht. In IE verwenden Sie statt des cssRules[]-Arrays das rules[]-Array, und statt den DOM-Standard-Methoden insertRule( ) und deleteRule( ) verwenden Sie addRule( ) und removeRule( ). Die zu einem Dokument gehörenden CSSStyleSheet-Objekte sind Teil des styleSheets[]Arrays des Document-Objekts. Im DOM-Standard wird außerdem verlangt (obwohl das zu der Zeit, als dieses Buch geschrieben wurde, nicht weitverbreitet implementiert war), dass jedes - oder -Element bzw. jeder -ProcessingInstruction-Knoten, das bzw. die ein Stylesheet definiert oder mit ihm verknüpft ist, das CSSStyleSheet-Objekt über eine sheetEigenschaft verfügbar machen soll.
Siehe auch CSSRule, die styleSheets[]-Eigenschaft des Document-Objekts; Kapitel 16
CSSStyleSheet.addRule( )
IE 4
IE-spezifische Methode, um eine Regel in ein Stylesheet einzufügen.
Die Styles, die auf Elemente angewendet werden, die mit dem selector übereinstimmen. Der Style-String ist eine Abfolge von mit einem Semikolon getrennten Attribut:WertPaaren. Er beginnt und endet nicht mit geschwungenen Klammern. index
Die Position im rules-Array, an der die Regel ein- oder angefügt werden soll. Wird dieses optionale Argument weggelassen, wird die neue Regel an das Regel-Array angefügt.
Beschreibung Diese Methode fügt eine neue CSS-Style-Regel an der angegebenen index-Position des rulesArrays dieses Stylesheets ein oder an. Sie ist eine IE-spezifische Alternative zur normalen insertRule( )-Methode. Beachten Sie, dass sich die Argumente zu dieser Methode von denen für insertRule( ) unterscheiden.
820 | Referenz für clientseitiges JavaScript
491-0.book Seite 821 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CSSStyleSheet.deleteRule( )
CSSStyleSheet.deleteRule( )
DOM Level 2 CSS
Löscht eine Regel aus einem Stylesheet
Überblick void deleteRule(unsigned long index) throws DOMException;
Argumente index
Der Index der zu löschenden Regel im cssRules-Array. Exceptions Diese Methode löst eine DOMException mit dem code INDEX_SIZE_ERR aus, wenn index negativ oder größer oder gleich cssRules.length ist. Sie löst eine DOMException mit dem code NO_MODIFICATION_ALLOWED_ERR aus, wenn dieses Stylesheet schreibgeschützt ist.
Diese Methode löscht die Regel an der angegebenen index-Position aus dem cssRules-Array. Dabei handelt es sich um eine DOM-Standard-Methode; eine IE-spezifische Alternative finden Sie unter CSSStyleSheet.removeRule( ).
CSSStyleSheet.insertRule( )
DOM Level 2 CSS
Fügt eine Regel in ein Stylesheet ein
Überblick unsigned long insertRule(String regel, unsigned long index) throws DOMException;
Argumente regel
Die vollständige, parser-fertige Textdarstellung der Regel, die dem Stylesheet hinzugefügt werden soll. Bei Stilregeln gehören dazu auch der Elementselektor und die Stilinformationen. index
Die Position im cssRules-Array, an der die Regel ein- oder angefügt werden soll. Rückgabewert Der Wert des index-Arguments. Exceptions Diese Methode löst unter folgenden Umständen eine DOMException mit einem der folgenden code-Werte aus:
Referenz für clientseitiges JavaScript |
821
Referenz für clientseitiges JavaScript
Beschreibung
491-0.book Seite 822 Mittwoch, 4. April 2007 9:55 09
e-bol.net
CSSStyleSheet.removeRule( ) HIERARCHY_REQUEST_ERR
Die CSS-Syntax gestattet an der angegebenen Stelle diese Regel nicht. INDEX_SIZE_ERR index ist negativ oder größer als cssRules.length. NO_MODIFICATION_ALLOWED_ERR
Die Regel ist schreibgeschützt. SYNTAX_ERR
In dem angegebenen regel-Text ist ein Syntaxfehler.
Beschreibung Diese Methode fügt eine neue CSS-regel an der angegebenen index-Position des cssRulesArrays dieses Stylesheets ein oder an. Dabei handelt es sich um eine DOM-Standard-Methode; eine IE-spezifische Alternative finden Sie unter CSSStyleSheet.addRule( ).
CSSStyleSheet.removeRule( )
IE 4
IE-spezifische Methode zum Entfernen einer CSS-Regel aus einem Stylesheet.
Überblick void removeRule(integer index)
Argumente index
Der Index der zu löschenden Regel im rules[]-Array. Wird dieses optionale Argument weggelassen, wird die erste Regel im Array entfernt.
Beschreibung Diese Methode entfernt die CSS-Style-Regel am angegebenen index des rules-Arrays dieses Stylesheets. Sie ist eine IE-spezifische Alternative zur normalen deleteRule( )-Methode.
Document Ein HTML- oder XML-Dokument
DOM Level 1 Core Node ➝ Document
Subinterfaces HTMLDocument
Eigenschaften readonly Window defaultView
Das Webbrowser-Window-Objekt (der »view« in der DOM-Sprache), in dem das Dokument angezeigt wird.
822 | Referenz für clientseitiges JavaScript
491-0.book Seite 823 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Document readonly DocumentType doctype
Gibt für XML-Dokumente mit einer -Deklaration einen DocumentType-Knoten an, der die DTD dieses Dokuments repräsentiert. Für HTML-Dokumente und für XMLDokumente ohne ist diese Eigenschaft null. readonly Element documentElement
Eine Referenz auf das Wurzelelement des Dokuments. Bei HTML-Dokumenten ist diese Eigenschaft immer das Element-Objekt, das das -Tag darstellt. Dieses Wurzelelement kann auch über das aus Node geerbte childNodes[]-Array abgerufen werden. Vergleichen Sie dazu die body-Eigenschaft von HTMLDocument. readonly DOMImplementation implementation
Das DOMImplementation-Objekt, das die Implementierung darstellt, mit der dieses Dokument erzeugt wurde. readonly CSSStyleSheet[] styleSheets
Eine Sammlung von Objekten, die alle Stylesheets darstellt, die in ein Dokument eingebettet oder damit verknüpft sind. In HTML-Dokumenten gehören dazu auch Stylesheets, die mit den Tags und definiert sind.
addEventListener( )
Fügt dem Set von Event-Handlern für dieses Dokument eine Event-Handler-Funktion hinzu. Dies ist eine DOM-Standard-Methode, die von allen modernen Browsern außer IE unterstützt wird. attachEvent( )
Fügt dem Set von Event-Handlern für dieses Dokument eine Event-Handler-Funktion hinzu. Sie ist die IE-spezifische Alternative zu addEventListener( ). createAttribute( )
Erzeugt einen neuen Attr-Knoten mit dem angegebenen Namen. createAttributeNS( )
Erzeugt einen neuen Attr-Knoten mit dem angegebenen Namen und Namensraum. createCDATASection( )
Erzeugt einen neuen CDATASection-Knoten mit dem angegebenen Text. createComment( )
Erzeugt einen neuen Kommentarknoten mit dem angegebenen String. createDocumentFragment( )
Erzeugt einen neuen, leeren DocumentFragment-Knoten. createElement( )
Erzeugt einen neuen Element-Knoten mit dem angegebenen Tag-Namen. createElementNS( )
Erzeugt einen neuen Element-Knoten mit dem angegebenen Tag-Namen und Namensraum. createEvent( )
Erzeugt ein neues, synthetisches Event-Objekt des angegebenen Typs.
Referenz für clientseitiges JavaScript |
823
Referenz für clientseitiges JavaScript
Methoden
491-0.book Seite 824 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Document createExpression( )
Erzeugt ein neues XPathExpression-Objekt, das eine kompilierte XPath-Abfrage repräsentiert. Eine IE-spezifische Alternative finden Sie unter Node.selectNodes( ). createProcessingInstruction( )
Erzeugt einen neuen ProcessingInstruction-Knoten mit dem angegebenen Ziel und Datenstring. createRange( )
Erzeugt ein neues Range-Objekt. Diese Methode gehört technisch gesehen zum DocumentRange-Interface und wird nur in solchen Implementierungen vom Document-Objekt implementiert, die auch das Range-Modul unterstützen. createTextNode( )
Erzeugt einen neuen Text-Knoten, der den angegebenen Text darstellt. detachEvent( )
Löscht eine Event-Handler-Funktion aus diesem Dokument. Sie ist die IE-spezifische Alternative zur normalen removeEventListener( )-Methode. dispatchEvent( )
Übermittelt ein synthetisches Event an dieses Dokument. evaluate( )
Wertet eine XPath-Abfrage anhand dieses Dokuments aus. Eine IE-spezifische Alternative finden Sie unter Node.selectNodes( ). getElementById( )
Gibt ein Nachfahren-Element dieses Dokuments zurück. Das Element hat für sein idAttribut den angegebenen Wert oder null, wenn im Dokument kein solches Element existiert. getElementsByTagName( )
Gibt ein Array (technisch gesehen eine NodeList) aller Element-Knoten in diesem Dokument zurück, die den angegebenen Tag-Namen haben. Die Element-Knoten erscheinen im Rückgabe-Array in der Reihenfolge, in der sie auch im Dokumentquelltext stehen. getElementsByTagNameNS( )
Gibt ein Array aller Element-Knoten zurück, die den angegebenen Tag-Namen und Namensraum haben. importNode( )
Kopiert einen Knoten aus einem anderen Dokument, der sich dazu eignet, in dieses Dokument eingefügt zu werden. loadXML( ) [IE only]
Parst einen String mit XML-Markup und speichert das Ergebnis in diesem DocumentObjekt. removeEventListener( )
Entfernt eine Event-Handler-Funktion aus dem Satz der Handler dieses Dokuments. Dies ist eine DOM-Standard-Methode, die von allen modernen Browsern außer IE unterstützt wird.
824 | Referenz für clientseitiges JavaScript
491-0.book Seite 825 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Document
Beschreibung Das Document-Interface ist der Wurzelknoten eines Dokumentbaums. Ein Document-Knoten kann mehrere Kinder haben, doch kann nur eines der Kinder ein Element-Knoten sein: Dies ist das Wurzelelement des Dokuments. Am einfachsten greifen Sie auf das Wurzelelement mit der Eigenschaft documentElement zu. Die Eigenschaften doctype und implementation geben Zugriff auf das DocumentType-Objekt (falls vorhanden) und das DOMImplementation-Objekt für dieses Dokument. Die meisten vom Document-Interface definierten Methoden sind »Factory-Methoden«, die verschiedene Arten von Knoten erzeugen, die in dieses Dokument eingefügt werden können. Erwähnenswerte Ausnahmen davon sind die Methoden getElementById() und getElementsByTagName(), die ganz nützlich sind, wenn Sie ein spezielles Element oder eine Menge zusammenhängender Element-Knoten in einem Dokumentbaum finden möchten. Weitere Ausnahmen sind Event-Handler-Registrierungsmethoden, wie z.B. addEventHandler( ). Diese Event-bezogenen Methoden werden auch vom Element-Interface implementiert und sind dort im Einzelnen dokumentiert.
Beim Arbeiten mit XML (einschließlich XHTML) lassen sich neue Document-Objekte über die createDocument( )-Methode der DOMImplementation erzeugen: document.implementation.createDocument(namespaceURL, rootTagName, null);
In IE verwenden Sie stattdessen folgenden Code: new ActiveXObject("MSXML2.DOMDocument");
In Beispiel 21-1 finden Sie eine plattformübergreifende Hilfsfunktion, die ein neues DocumentObjekt erzeugt. Es ist auch möglich, eine XML-Datei aus dem Netz zu laden und sie in ein Document-Objekt zu parsen. Vergleichen Sie dazu die responseXML-Eigenschaft des XMLHttpRequest-Objekts. Sie können auch einen String mit XML-Markup in ein Document-Objekt parsen: Vergleichen Sie dazu DOMParser.parseFromString( ) und das IE-spezifische Document.loadXML( ). (Beispiel 21-4 ist eine plattformübergreifende Hilfsfunktion, die diese Methoden zum Parsen von XML-Markup verwendet). Weitere Eigenschaften und Methoden speziell für HTML-Dokumente finden Sie unter HTMLDocument.
Siehe auch DOMImplementation, DOMParser, HTMLDocument, Window, XMLHttpRequest; Kapitel 15
Referenz für clientseitiges JavaScript |
825
Referenz für clientseitiges JavaScript
Meist erhalten Sie ein Document-Objekt über die document-Eigenschaft eines Window-Objekts. Sie können aber Document-Objekte auch über die contentDocument-Eigenschaft von Frame und IFrame erhalten oder über die ownerDocument-Eigenschaft eines beliebigen Knotens, der in ein Dokument aufgenommen wurde.
491-0.book Seite 826 Mittwoch, 4. April 2007 9:55 09
Der Name des neu erzeugten Attributs. Rückgabewert Ein neu erzeugter Attr-Knoten, dessen nodeName-Eigenschaft auf name gesetzt ist. Exceptions Diese Methode löst eine DOMException mit dem code INVALID_CHARACTER_ERR aus, wenn name ein unzulässiges Zeichen enthält.
Siehe auch Attr, Element.setAttribute( ), Element.setAttributeNode( )
Der eindeutige Bezeichner des Namensraums für das Attr oder null, wenn kein Namensraum vorhanden ist. qualifizierterName
Der qualifizierte Attributname; er sollte ein Namensraumpräfix, einen Doppelpunkt und einen lokalen Namen enthalten.
826 | Referenz für clientseitiges JavaScript
491-0.book Seite 827 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Document.createCDATASection( )
Rückgabewert Ein neu erzeugter Attr-Knoten mit dem angegebenen Namen und Namensraum. Exceptions Diese Methode kann unter den folgenden Umständen eine DOMException mit einem der folgenden code-Werte auslösen: INVALID_CHARACTER_ERR qualifizierterName enthält ein unzulässiges Zeichen. NAMESPACE_ERR qualifizierterName ist nicht wohlgeformt, oder qualifizierterName und namensraumURI
passen nicht zueinander. NOT_SUPPORTED_ERR
Die Implementierung unterstützt keine XML-Dokumente und implementiert daher auch nicht diese Methode.
Beschreibung nur einen Namen, sondern zusätzlich auch einen Namensraum hat. Diese Methode kann nur für XML-Dokumente eingesetzt werden, die Namensräume verwenden.
Der Text der zu erzeugenden CDATASection. Rückgabewert Ein neu erzeugter CDATASection-Knoten, der die angegebenen daten enthält. Exceptions Wenn das Dokument ein HTML-Dokument ist, löst diese Methode eine DOMException mit dem code NOT_SUPPORTED_ERR aus, da HTML-Dokumente keine CDATASection-Knoten gestatten.
Referenz für clientseitiges JavaScript |
827
Referenz für clientseitiges JavaScript
createAttributeNS() ist genau wie createAttribute(), nur dass der erzeugte Attr-Knoten nicht
491-0.book Seite 828 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Document.createComment( )
Document.createComment( )
DOM Level 1 Core
Erzeugt einen neuen Kommentarknoten
Überblick Comment createComment(String daten);
Argumente daten
Der Text des zu erzeugenden Kommentarknotens. Rückgabewert Ein neu erzeugter Kommentarknoten, der als Text die angegebenen daten enthält.
Document.createDocumentFragment( )
DOM Level 1 Core
Erzeugt einen neuen, leeren DocumentFragment-Knoten
Rückgabewert Ein neu erzeugter DocumentFragment-Knoten ohne Kinder.
Document.createElement( )
DOM Level 1 Core
Erzeugt einen neuen Element-Knoten
Überblick Element createElement(String tagName) throws DOMException;
Argumente tagName
Der Tag-Name des zu erzeugenden Elements. Da HTML-Tags nicht zwischen Groß- und Kleinschreibung unterscheiden, können Sie für HTML-Tag-Namen nach Belieben zwischen Groß- und Kleinschreibung wählen. XML-Tag-Namen unterscheiden zwischen Groß- und Kleinschreibung. Rückgabewert Ein neu erzeugter Element-Knoten mit dem angegebenen Tag-Namen. Exceptions Diese Methode löst eine DOMException mit dem code INVALID_CHARACTER_ERR aus, wenn tagName ein unzulässiges Zeichen enthält.
828 | Referenz für clientseitiges JavaScript
491-0.book Seite 829 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Document.createElementNS( )
Document.createElementNS( )
DOM Level 2 Core
Erzeugt einen neuen Element-Knoten mit Namensraum
Überblick Element createElementNS(String namensraumURI, String qualifizierterName) throws DOMException;
Argumente namensraumURI
Der eindeutige Bezeichner für den Namensraum des neuen Elements oder null, wenn kein Namensraum vorhanden ist. qualifizierterName
Der qualifizierte Name des neuen Elements. Er sollte ein Namensraumpräfix, einen Doppelpunkt und einen lokalen Namen enthalten.
Exceptions Diese Methode kann unter den folgenden Umständen eine DOMException mit einem der folgenden code-Werte auslösen: INVALID_CHARACTER_ERR qualifizierterName enthält ein unzulässiges Zeichen. NAMESPACE_ERR qualifizierterName ist nicht wohlgeformt, oder qualifizierterName und namensraumURI
passen nicht zueinander. NOT_SUPPORTED_ERR
Die Implementierung unterstützt keine XML-Dokumente und implementiert daher auch nicht diese Methode.
Beschreibung createAttributeNS() ist genau wie createAttribute(), nur dass der erzeugte Attr-Knoten nicht
nur einen Namen, sondern zusätzlich auch einen Namensraum hat. Diese Methode eignet sich nur für XML-Dokumente, die Namensräume verwenden.
Rückgabewert Ein neu erzeugter Element-Knoten mit dem angegebenen Tag-Namen und Namensraum.
491-0.book Seite 830 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Document.createEvent( )
Argumente eventTyp
Der Name des Event-Moduls, für das ein Event-Objekt gewünscht wird. Gültige EventTypen werden in der Beschreibung aufgeführt. Rückgabewert Ein neu erzeugtes Event-Objekt des angegebenen Typs. Exceptions Diese Methode löst eine DOMException mit dem code NOT_SUPPORTED_ERR aus, wenn die Implementierung keine Events des angeforderten Typs unterstützt.
Beschreibung Diese Methode erzeugt ein neues Event-Objekt des Typs, der im eventTyp-Argument angegeben ist. Beachten Sie, dass der Wert dieses Arguments nicht der Name des zu erzeugenden Event-Interfaces (im Singular), sondern der Name des DOM-Moduls (im Plural) sein soll, das dieses Interface definiert. Die folgende Tabelle zeigt, welche Werte für eventTyp zulässig sind und welches Event-Interface jeder Wert erzeugt. eventType-Argument
Event-Interface
Initialisierungsmethode
HTMLEvents
Event
initEvent( )
MouseEvents
MouseEvent
initMouseEvent( )
UIEvents
UIEvent
initUIEvent( )
Nachdem Sie ein Event-Objekt mit dieser Methode erzeugt haben, müssen Sie es mit der in der Tabelle angegebenen Initialisierungsmethode initialisieren. Einzelheiten zur Initialisierungsmethode entnehmen Sie bitte der Referenz zu dem jeweiligen Event-Interface. Diese Methode wird eigentlich nicht im Document-Interface, sondern im DOM-DocumentEvent-Interface definiert. Wenn eine Implementierung das Events-Modul unterstützt, implementiert das Document-Objekt immer das DocumentEvent-Interface und unterstützt somit diese Methode. Beachten Sie, dass Internet Explorer das DOM Events-Modul nicht unterstützt.
Siehe auch Event, MouseEvent, UIEvent
830 | Referenz für clientseitiges JavaScript
491-0.book Seite 831 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Document.createExpression( )
Document.createExpression( )
Firefox 1.0, Safari 2.01, Opera 9
Erzeugt einen XPath-Ausdruck zur späteren Auswertung
Überblick XPathExpression createExpression(String xpathText, Function namensraumURLMapper) throws XPathException
Argumente xpathText
Der String, der den zu kompilierenden XPath-Ausdruck darstellt. namensraumURLMapper
Eine Funktion, die ein Namensraumpräfix auf eine vollständige Namensraum-URL abbildet oder null zurückgibt, wenn keine solche Zuordnung erforderlich ist.
Exceptions Diese Methode löst eine Exception aus, wenn der xpathText einen Syntaxfehler enthält oder wenn er ein Namensraumpräfix verwendet, das nicht mit namensraumURLMapper aufgelöst werden kann.
Beschreibung Diese Methode konvertiert eine Stringrepräsentation eines XPath-Ausdrucks in eine kompilierte Form, eine XPathExpression. Zusätzlich zum Ausdruck nimmt diese Methode eine Funktion im Format function(praefix), die einen Namensraumpräfix-String interpretiert und ihn als vollständigen Namensraum-URL-String zurückgibt. Internet Explorer unterstützt diese API nicht. Eine IE-spezifische Alternative finden Sie unter Node.selectNodes( ).
Siehe auch Document.evaluate( ), Node.selectNodes( ), XPathExpression, XPathResult
491-0.book Seite 832 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Document.createRange( )
Argumente ziel
Das Ziel der Verarbeitungsanweisung. daten
Der Textinhalt der Verarbeitungsanweisung. Rückgabewert Ein neu erzeugter ProcessingInstruction-Knoten. Exceptions Diese Methode kann unter den folgenden Umständen eine DOMException mit einem der folgenden code-Werte auslösen: INVALID_CHARACTER_ERR Das angegebene ziel enthält ein unzulässiges Zeichen. NOT_SUPPORTED_ERR
Dies ist ein HTML-Dokument und unterstützt keine Verarbeitungsanweisungen.
Document.createRange( )
DOM Level 2 Range
Erzeugt ein Range-Objekt
Überblick Range createRange( );
Rückgabewert Ein neu erzeugtes Range-Objekt. Beide Begrenzungspunkte sind auf den Dokumentenanfang gesetzt.
Beschreibung Diese Methode erzeugt ein Range-Objekt, mit dem Sie einen Bereich dieses Dokuments oder eines DocumentFragment aus ihm darstellen können. Diese Methode wird eigentlich nicht im Document-Interface, sondern im DocumentRangeInterface definiert. Wenn eine Implementierung das Range-Modul unterstützt, implementiert das Document-Objekt immer das DocumentRange-Interface und unterstützt somit diese Methode. Internet Explorer 6 unterstützt dieses Modul nicht.
Siehe auch Range
832 | Referenz für clientseitiges JavaScript
491-0.book Seite 833 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Document.createTextNode( )
Document.createTextNode( )
DOM Level 1 Core
Erzeugt einen neuen Text-Knoten
Überblick Text createTextNode(String daten);
Argumente daten
Der Inhalt des Text-Knotens. Rückgabewert Ein neu erzeugter Text-Knoten, der den angegebenen daten-String repräsentiert.
Document.detachEvent( ) siehe Element.detachEvent( ) Referenz für clientseitiges JavaScript
Überblick XPathResult evaluate(String xpathText, Node kontextKnoten, Function namensraumURLMapper, short ergebnisTyp, XPathResult ergebnis) throws DOMException, XPathException
Argumente xpathText
Der String, der den auszuwertenden XPath-Ausdruck darstellt. kontextKnoten
Der Knoten in diesem Dokument, auf dem der Ausdruck ausgewertet wird. namensraumURLMapper
Eine Funktion, die ein Namensraumpräfix auf eine vollständige Namensraum-URL abbildet oder null zurückgibt, wenn keine solche Zuordnung erforderlich ist. ergebnisTyp
Gibt den als Ergebnis erwarteten Objekttyp an und verwendet XPath-Konvertierungen, um das gewünschte Ergebnis zu erzwingen. Gültige Werte für ergebnisTyp sind die durch das XPathResult-Objekt definierten Konstanten.
Referenz für clientseitiges JavaScript |
833
491-0.book Seite 834 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Document.getElementById( ) ergebnis
Ein wiederzuverwendendes XPathResult-Objekt oder null, wenn ein neues XPathResultObjekt erzeugt werden soll. Rückgabewert Ein XPathResult-Objekt, das die Auswertung des Ausdrucks auf dem gegebenen Kontextknoten repräsentiert. Exceptions Diese Methode kann eine Exception auslösen, wenn der xpathText einen Syntaxfehler enthält, wenn das Ergebnis des Ausdrucks nicht in den gewünschten ergebnisTyp konvertiert werden kann, wenn der Ausdruck Namensräume enthält, die namensraumURLMapper nicht auflösen kann, oder wenn kontextKnoten vom falschen Typ oder nicht mit diesem Dokument verknüpft ist.
Beschreibung Diese Methode wertet den angegebenen XPath-Ausdruck für den angegebenen KontextKnoten aus. Sie gibt ein XPathResult-Objekt zurück, wobei sie mit ergebnisTyp bestimmt, welcher Ergebnistyp gewünscht ist. Wenn Sie einen Ausdruck mehrmals auswerten wollen, verwenden Sie Document.createExpression( ), um den Ausdruck in ein XPathExpression-Objekt zu kompilieren, und verwenden dann die evaluate( )-Methode von XPathExpression. Internet Explorer unterstützt diese API nicht. IE-spezifische Alternativen finden Sie unter Node.selectNodes( ) und Node.selectSingleNode( ).
Siehe auch Document.createExpression( ) Node.selectNodes( ) Node.selectSingleNode( ) XPathExpression XPathResult
Document.getElementById( )
DOM Level 2 Core
Sucht ein Element mit der angegebenen eindeutigen ID
Überblick Element getElementById(String elementId);
Argumente elementId
Der Wert des id-Attributs des gewünschten Elements. Rückgabewert Der Element-Knoten, der das Dokumentelement mit dem angegebenen id-Attribut darstellt, oder null, wenn kein solches Element gefunden wird.
834 | Referenz für clientseitiges JavaScript
491-0.book Seite 835 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Document.getElementsByTagName( )
Beschreibung Diese Methode sucht im Dokument einen Element-Knoten mit einem id-Attribut, dessen Wert elementId ist, und gibt dieses Element zurück. Wenn kein solches Element zu finden ist, wird null zurückgegeben. Der Wert des id-Attributs soll innerhalb eines Dokuments eindeutig sein, und wenn diese Methode mehr als ein Element mit der angegebenen elementId findet, kann sie entweder ein beliebiges von diesen oder null zurückgeben. Diese Methode ist wichtig und wird oft benutzt, da sie eine einfache Möglichkeit bietet, das Element-Objekt zu erhalten, das ein spezifisches Dokumentelement darstellt. Beachten Sie, dass der Methodenname auf »Id« und nicht auf »ID« endet; schreiben Sie ihn also richtig. In HTML-Dokumenten sucht diese Methode nach einem Element mit dem angegebenen idAttribut. Verwenden Sie HTMLDocument.getElementsByName( ), um nach HTML-Elementen aufgrund ihrer name-Attribute zu suchen.
Siehe auch Document.getElementsByTagName( ) Element.getElementsByTagName( ) HTMLDocument.getElementsByName( )
Document.getElementsByTagName( )
DOM Level 1 Core
Gibt alle Element-Knoten mit dem angegebenen Namen zurück
Der Tag-Name des zurückzugebenden Element-Knotens oder der Wildcard-String »*«, mit dem ohne Berücksichtigung des Tag-Namens alle Element-Knoten im Dokument zurückgegeben werden. Bei HTML-Dokumenten werden Tag-Namen ohne Beachtung der Großund Kleinschreibung verglichen. (In Versionen vor Version 6 unterstützt IE diese Wildcard-Syntax nicht). Rückgabewert Ein schreibgeschütztes Array (technisch gesehen eine NodeList) aller Element-Knoten im Dokumentbaum mit dem angegebenen Tag-Namen. Die zurückgegebenen Element-Knoten stehen in derselben Reihenfolge, in der sie auch im Dokumentquelltext auftauchen.
Referenz für clientseitiges JavaScript |
835
Referenz für clientseitiges JavaScript
In XML-Dokumenten verwendet diese Methode zur Suche alle Attribute vom Typ id, unabhängig vom eigentlichen Namen dieses Attributs. Wenn XML-Attributtypen unbekannt sind (z.B. weil der XML-Parser die DTD des Dokuments ignoriert oder nicht finden konnte), gibt diese Methode immer null zurück. Für clientseitiges JavaScript ist diese Methode bei XMLDokumenten normalerweise nicht sehr nützlich. Tatsächlich wurde getElementById( ) ursprünglich als Bestandteil des HTMLDocument-Interfaces definiert, wurde aber dann zum Document-Interface in DOM Level 2 verschoben.
491-0.book Seite 836 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Document.getElementsByTagNameNS( )
Beschreibung Diese Methode gibt eine NodeList zurück (die Sie auch als schreibgeschütztes Array behandeln können). Sie enthält alle Element-Knoten im Dokument, die den angegebenen TagNamen haben, und zwar in derselben Reihenfolge, in der sie im Dokumentquelltext auftauchen. Die NodeList ist »live«, d.h., ihr Inhalt wird automatisch nach Bedarf aktualisiert, wenn Elemente mit dem angegebenen Tag-Namen dem Dokument hinzugefügt oder aus ihm entfernt werden. HTML-Dokumente beachten die Groß- und Kleinschreibung nicht, sodass Sie tagName großoder kleinschreiben können; alle Tags mit dem gleichen Namen im Dokument werden erfasst, unabhängig davon, ob diese Tags im Dokumentquelltext groß- oder kleingeschrieben sind. XML-Dokumente achten hingegen sehr wohl auf die Groß- und Kleinschreibung. Hier stimmt der tagName nur mit Tags im Dokumentquelltext überein, die denselben Namen und genau dieselbe Groß- und Kleinschreibung verwenden. Beachten Sie, dass das Element-Interface eine gleichnamige Methode definiert, die nur einen Teilbaum des Dokuments durchsucht. Außerdem definiert das Interface HTMLDocument auch die Methode getElementsByName(), die Elemente anhand des Werts ihrer name-Attribute und nicht nach Tag-Namen sucht.
Beispiel Mit Code wie diesem können Sie alle -Tags in einem Dokument finden und durchlaufen: var headings = document.getElementsByTagName("h1"); for(var i = 0; i < headings.length; i++) { // Durchlaufe die zurückgegebenen Tags var h = headings[i]; // Tue nun etwas mit dem -Element in der Variablen h }
Siehe auch Document.getElementById( ) Element.getElementsByTagName( ) HTMLDocument.getElementsByName( )
Document.getElementsByTagNameNS( )
DOM Level 2 Core
Gibt alle Element-Knoten mit einem angegebenen Namen und Namensraum zurück
Der eindeutige Bezeichner des Namensraums der gewünschten Elemente oder »*«, wenn alle Namensräume erfasst werden sollen.
836 | Referenz für clientseitiges JavaScript
491-0.book Seite 837 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Document.importNode( ) lokalerName
Der lokale Name der gewünschten Elemente oder »*«, wenn alle lokalen Namen erfasst werden sollen. Rückgabewert Ein schreibgeschütztes Array (technisch gesehen eine NodeList) aller Element-Knoten im Dokumentbaum mit dem angegebenen Namensraum und lokalen Namen.
Beschreibung Diese Methode funktioniert wie getElementsByTagName(), sucht jedoch Elemente nach Namensraum und Namen. Sie ist nur in XML-Dokumenten nützlich, die Namensräume verwenden.
Document.importNode( )
DOM Level 2 Core
Kopiert einen Knoten eines anderen Dokuments zur Nutzung in diesem Dokument Referenz für clientseitiges JavaScript
Wenn true: Kopiere rekursiv auch alle Nachfahren von importierterKnoten. Rückgabewert Eine Kopie von importierterKnoten (und eventuell all seiner Nachfahren), in der ownerDocument auf dieses Dokument gesetzt ist. Exceptions Diese Methode löst eine DOMException mit dem code NOT_SUPPORTED_ERR aus, wenn importierterKnoten ein Document oder DocumentType-Knoten ist, da diese Knotentypen nicht importiert werden können.
Beschreibung Dieser Methode wird ein in einem anderen Dokument definierter Knoten übergeben. Sie liefert eine Kopie dieses Knotens, die in das vorliegende Dokument eingefügt werden kann. Wenn tief den Wert true hat, werden auch alle Nachfahren des Knotens kopiert. Der Originalknoten und seine Nachfahren werden nicht modifiziert. In der zurückgegebenen Kopie ist die Eigenschaft ownerDocument auf das vorliegende Dokument gesetzt, aber der parentNode auf null, da sie noch nicht in das Dokument eingefügt wurde. EventListener-Funktionen, die auf dem Originalknoten oder -baum registriert waren, werden nicht mitkopiert.
Referenz für clientseitiges JavaScript |
837
491-0.book Seite 838 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Document.loadXML( )
Wird ein Element-Knoten importiert, so werden nur die Attribute mitimportiert, die im Quelldokument explizit angegeben sind. Wenn ein Attr-Knoten importiert wird, wird seine specified-Eigenschaft automatisch auf true gesetzt.
Siehe auch Node.cloneNode( )
Document.loadXML( )
Internet Explorer
Füllt dieses Dokument durch Parsen eines Strings mit XML-Markup
Überblick void loadXML(String text)
Argumente text
Das zu parsende XML-Markup.
Beschreibung Diese IE-spezifische Methode parst den spezifischen String mit XML-Text und baut einen Baum aus DOM-Knoten im gegebenen Document-Objekt. Dabei werden alle vorher bereits im Dokument vorhanden Knoten gelöscht. Diese Methode fehlt bei Document-Objekten, die HTML-Dokumente darstellen. Vor dem Aufruf von loadXML( ) wird normalerweise ein neues, leeres Dokument erzeugt, das den geparsten Inhalt aufnimmt: var doc = new ActiveXObject("MSXML2.DOMDocument"); doc.loadXML(markup);
Unter DOMParser.parseFromString( ) finden Sie eine Alternative für andere Browser als IE.
491-0.book Seite 839 Mittwoch, 4. April 2007 9:55 09
e-bol.net
DocumentFragment
DocumentFragment Benachbarte Knoten und ihre Teilbäume
DOM Level 1 Core Node ➝ DocumentFragment
Beschreibung Das Interface DocumentFragment stellt einen Teil oder ein Fragment eines Dokuments dar. Genauer gesagt, ist es eine Liste von nebeneinanderliegenden Knoten und allen Nachfahren dieser Knoten, aber ohne einen gemeinsamen übergeordneten Knoten. DocumentFragmentKnoten sind nie Teil eines Dokumentbaums, und die geerbte Eigenschaft parentNode ist immer null. Durch ihr Spezialverhalten sind DocumentFragment-Nodes recht hilfreich. Erfolgt ein Aufruf mit dem Ziel, ein DocumentFragment in einen Dokumentbaum einzufügen, wird allerdings jedes Kind von DocumentFragment eingefügt, nicht aber der DocumentFragmentKnoten selbst. Das macht DocumentFragment zu einem vorübergehenden Platzhalter für Knoten, die Sie später alle zugleich in ein Dokument einfügen möchten. Besonders nützlich ist DocumentFragment überdies zum Implementieren der Funktionen Ausschneiden, Kopieren und Einfügen, insbesondere in Kombination mit dem Range-Interface.
Der nicht gepaste Text einer internen Teilmenge der DTD (d.h. der Teil der DTD, der nicht in einer externen Datei, sondern in dem Dokument selbst erscheint). Die eckigen Begrenzungsklammern der internen Teilmenge gehören nicht zum Rückgabewert. Wenn es keine interne Teilmenge gibt, ist diese Eigenschaft null. readonly String name
Der Name des Dokumenttyps. Dies ist der Bezeichner, der am Anfang eines XML-Dokuments unmittelbar hinter steht; er ist derselbe wie der Tag-Name des Wurzelelements des Dokuments. readonly String publicId [DOM Level 2]
Der öffentliche Bezeichner der externen Teilmenge der DTD oder null, wenn keiner angegeben wurde. readonly String systemId [DOM Level 2]
Der Systembezeichner der externen Teilmenge der DTD oder null, wenn keiner angegeben wurde.
Referenz für clientseitiges JavaScript |
839
Referenz für clientseitiges JavaScript
Sie können ein neues, leeres DocumentFragment mit Document.createDocumentFragment() erzeugen oder mit Range.extractContents() oder Range.cloneContents() ein DocumentFragment erhalten, das ein Fragment eines vorhandenen Dokuments enthält.
491-0.book Seite 840 Mittwoch, 4. April 2007 9:55 09
e-bol.net
DOMException
Beschreibung Dieses nur selten benutzte Interface repräsentiert die DTD eines XML-Dokuments. Programmierer, die ausschließlich mit HTML-Dokumenten arbeiten, müssen dieses Interface nie benutzen. Da eine DTD nicht zum Inhalt eines Dokuments gehört, erscheinen DocumentType-Knoten nie im Dokumentenbaum. Wenn ein XML-Dokument eine DTD hat, so kann auf den DocumentType-Knoten für diese DTD über die doctype-Eigenschaft des Document-Knotens zugegriffen werden. Obwohl das W3C DOM eine API für den Zugriff auf die XML-Entities und -Notationen enthält, die in einer DTD definiert sind, wird diese API hier nicht dokumentiert. Die üblichen Webbrowser parsen die DTDs für die von ihnen geladenen Dokumente nicht, und JavaScript kann auf der Clientseite nicht auf diese Entities und Notationen zugreifen. Für das Programmieren von clientseitigem JavaScript repräsentiert dieses Interface lediglich den Inhalt des -Tags und nicht den Inhalt der DTD-Datei, die es referenziert. DocumentType-Knoten sind unveränderlich.
Siehe auch Document, DOMImplementation.createDocument( ), DOMImplementation.createDocumentType( )
DOMException Signalisiert Exceptions oder Fehler für Core DOM-Objekte
DOM Level 1 Core Object ➝ DOMException
Konstanten Die folgenden Konstanten definieren die zulässigen Werte der code-Eigenschaft eines DOMException-Objekts. Beachten Sie, dass diese Konstanten statische Eigenschaften von DOMException sind und keine Eigenschaften individueller Exception-Objekte: unsigned short INDEX_SIZE_ERR = 1
Out-of-Bounds-Fehler für einen Array- oder String-Index. unsigned short DOMSTRING_SIZE_ERR = 2
Ein angeforderter Text ist zu groß, um noch in einen String der aktuellen JavaScriptImplementierung zu passen. unsigned short HIERARCHY_REQUEST_ERR = 3
Es wurde versucht, einen Knoten an eine unzulässige Stelle in der Dokumentenbaumhierarchie zu setzen. unsigned short WRONG_DOCUMENT_ERR = 4
Es wurde versucht, einen Knoten mit einem anderen Dokument als dem zu benutzen, das den Knoten erzeugte. unsigned short INVALID_CHARACTER_ERR = 5
Ein unzulässiges Zeichen wurde verwendet (z.B. in einem Elementnamen).
840 | Referenz für clientseitiges JavaScript
491-0.book Seite 841 Mittwoch, 4. April 2007 9:55 09
e-bol.net
DOMException unsigned short NO_DATA_ALLOWED_ERR = 6
Gegenwärtig nicht benutzt. unsigned short NO_MODIFICATION_ALLOWED_ERR = 7
Es wurde versucht, einen schreibgeschützten Knoten zu ändern. unsigned short NOT_FOUND_ERR = 8
Ein Knoten wurde nicht an der erwarteten Stelle gefunden. unsigned short NOT_SUPPORTED_ERR = 9
Eine Methode oder Eigenschaft wird von der aktuellen DOM-Implementierung nicht unterstützt. unsigned short INUSE_ATTRIBUTE_ERR = 10
Es wurde versucht, ein Attr mit einem Element zu assoziieren, obwohl dieser Attr-Knoten bereits mit einem anderen Element-Knoten assoziiert war. unsigned short INVALID_STATE_ERR = 11 [DOM Level 2]
Es wurde versucht, ein Objekt zu benutzen, das noch nicht oder nicht mehr in einem benutzbaren Zustand ist. Ein angegebener String enthält einen Syntaxfehler. Wird oft bei CSS-Eigenschaftsspezifikationen benutzt. unsigned short INVALID_MODIFICATION_ERR = 13 [DOM Level 2]
Es wurde versucht, den Typ eines CSSRule- oder CSSValue-Objekts zu ändern. unsigned short NAMESPACE_ERR = 14 [DOM Level 2]
Ein Fehler im Zusammenhang mit Element- oder Attribut-Namensräumen ist aufgetreten. unsigned short INVALID_ACCESS_ERR = 15 [DOM Level 2]
Es wurde versucht, auf eine Weise auf ein Objekt zuzugreifen, die von der Implementierung nicht unterstützt wird.
Eigenschaften unsigned short code
Ein Fehlercode, der Einzelheiten über die Ursache der Exception verrät. Die oben aufgeführten Konstanten zeigen die zulässigen Werte (und ihre Bedeutungen).
Beschreibung Ein DOMException-Objekt wird ausgelöst, wenn eine DOM-Methode oder -Eigenschaft falsch oder im falschen Kontext angewendet wird. Der Wert der code-Eigenschaft zeigt an, um welchen Exception-Typ es sich handelt. Beachten Sie, dass eine DOMException beim Lesen oder Schreiben einer Objekteigenschaft und beim Aufruf einer Objektmethode ausgelöst werden kann. Die Beschreibungen der Objekteigenschaften und -methoden in dieser Referenz umfassen auch eine Liste der möglichen Exception-Typen. Beachten Sie jedoch, dass bestimmte, oft ausgelöste Exceptions in dieser Liste weggelassen wurden. Wenn versucht wird, den schreibgeschützten Knoten zu ändern, wird jedes Mal eine DOMException mit einem code von NO_MODIFICATION_ALLOWED_ERR ausgelöst. Es können also die meisten Methoden und les- und schreibbare Eigenschaften des Node-Interfaces (und seiner Subinterfaces) diese Exception
Referenz für clientseitiges JavaScript |
841
Referenz für clientseitiges JavaScript
unsigned short SYNTAX_ERR = 12 [DOM Level 2]
491-0.book Seite 842 Mittwoch, 4. April 2007 9:55 09
e-bol.net
DOMImplementation
auslösen. Da schreibgeschützte Knoten nur in XML- und nicht in HTML-Dokumenten auftauchen und da sie ganz allgemein auf die Methoden und Writable-Eigenschaften von NodeObjekten anwendbar ist, wurde auch die NO_MODIFICATION_ALLOWED_ERR-Exception bei den Beschreibungen dieser Methoden und Eigenschaften weggelassen. In ähnlicher Weise können auch viele DOM-Methoden und -Eigenschaften, die Strings zurückgeben, eine DOMException mit dem code DOMSTRING_SIZE_ERR auslösen. Sie weist darauf hin, dass der zurückzugebende Text zu lang ist, um in der darunterliegenden JavaScript-Implementierung als Stringwert dargestellt zu werden. Diese Art Exception kann zwar theoretisch von vielen Eigenschaften und Methoden ausgelöst werden, ist aber in der Praxis selten und wurde bei den Beschreibungen der relevanten Methoden und Eigenschaften ebenfalls weggelassen. Beachten Sie, dass nicht alle Exceptions im DOM durch eine DOMException signalisiert werden: Exceptions, an denen das DOM Range-Modul beteiligt ist, veranlassen das Auslösen einer RangeException.
Siehe auch RangeException
DOMImplementation Methoden, die nicht von einem bestimmten Dokument abhängig sind
DOM Level 1 Core Object ➝ DOMImplementation
Methoden createDocument( )
Erzeugt ein neues Document-Objekt mit einem Wurzelelement (die documentElementEigenschaft des zurückgegebenen Document-Objekts) des angegebenen Typs. createDocumentType( )
Erzeugt einen neuen DocumentType-Knoten. hasFeature( )
Prüft, ob die aktuelle Implementierung eine spezifizierte Version eines angegebenen Features unterstützt.
Beschreibung Das DOMImplementation-Interface ist ein Platzhalter für Methoden, die sich nicht speziell auf ein bestimmtes Document-Objekt beziehen, sondern für die Implementierung des DOM »global« sind. Eine Referenz auf das DOMImplementation-Objekt beschaffen Sie sich mit der implementation-Eigenschaft eines beliebigen Document-Objekts.
842 | Referenz für clientseitiges JavaScript
491-0.book Seite 843 Mittwoch, 4. April 2007 9:55 09
e-bol.net
DOMImplementation.createDocument( )
DOMImplementation.createDocument( )
DOM Level 2 Core
Erzeugt ein neues Document und das angegebene Wurzelelement
Der eindeutige Bezeichner des Namensraums des Wurzelelements, das für das Dokument erzeugt wird, oder null, wenn kein Namensraum vorhanden ist. qualifizierterName
doctyp
Das DocumentType-Objekt für das neu erzeugte Document, oder null, wenn keines gewünscht wird. Rückgabewert Ein Document-Objekt, dessen documentElement-Eigenschaft auf einen Wurzelelement-Knoten des angegebenen Typs gesetzt ist. Exceptions Diese Methode kann unter folgenden Umständen eine DOMException mit den folgenden codeWerten auslösen: INVALID_CHARACTER_ERR qualifizierterName enthält ein unzulässiges Zeichen. NAMESPACE_ERR qualifizierterName ist nicht wohlgeformt, oder qualifizierterName und namensraumURI
passen nicht zueinander. NOT_SUPPORTED_ERR
Die aktuelle Implementierung unterstützt keine XML-Dokumente und implementiert diese Methode nicht. WRONG_DOCUMENT_ERR doctyp wird bereits für ein anderes Dokument genutzt oder wurde von einem anderen
DOMImplementation-Objekt erzeugt.
Beschreibung Diese Methode erzeugt ein neues XML Document-Objekt und das dafür angegebene documentElement-Wurzelobjekt. Wenn das Argument doctyp nicht null ist, wird die ownerDocumentEigenschaft dieses DocumentType-Objekts auf das neu erzeugte Dokument gesetzt.
Referenz für clientseitiges JavaScript |
843
Referenz für clientseitiges JavaScript
Der Name des Wurzelelements, das für dieses Dokument angelegt werden soll. Wenn namensraumURI nicht null ist, sollte dieser Name ein Namensraumpräfix und einen Doppelpunkt enthalten.
491-0.book Seite 844 Mittwoch, 4. April 2007 9:55 09
e-bol.net
DOMImplementation.createDocumentType( )
Diese Methode wird zum Erzeugen von XML-Dokumenten gebraucht und kann von NurHTML-Implementierungen nicht unterstützt werden.
Siehe auch DOMImplementation.createDocumentType( )
Der Name des Dokumenttyps. Wenn Sie XML-Namensräume verwenden, kann dies ein qualifizierter Name sein, zu dem ein Namensraumpräfix und ein lokaler Name gehören, der durch einen Doppelpunkt von dem Namensraumpräfix getrennt wird. publicId
Der öffentliche Bezeichner des Dokumenttyps oder null. systemId
Der Systembezeichner des Dokumenttyps oder null. Dieses Argument gibt in der Regel den lokalen Dateinamen einer DTD-Datei an. Rückgabewert Ein neues DocumentType-Objekt mit der ownerDocument-Eigenschaft null. Exceptions Diese Methode kann eine DOMException mit einem der folgenden code-Werte auslösen: INVALID_CHARACTER_ERR qualifizierterName enthält ein unzulässiges Zeichen. NAMESPACE_ERR qualifizierterName ist nicht wohlgeformt. NOT_SUPPORTED_ERR
Die aktuelle Implementierung unterstützt keine XML-Dokumente und implementiert diese Methode nicht.
Beschreibung Diese Methode erzeugt einen neuen DocumentType-Knoten. Sie spezifiziert nur eine externe Teilmenge des Dokumenttyps. Bis zum Level 2 bietet der DOM-Standard noch keine Möglichkeit, eine interne Teilmenge anzugeben, und der zurückgegebene DocumentType definiert keine Entity- oder Notation-Knoten. Diese Methode ist nur bei XML-Dokumenten von Nutzen.
844 | Referenz für clientseitiges JavaScript
491-0.book Seite 845 Mittwoch, 4. April 2007 9:55 09
e-bol.net
DOMImplementation.hasFeature( )
DOMImplementation.hasFeature( )
DOM Level 1 Core
Stellt fest, ob die Implementierung ein bestimmtes Feature unterstützt
Der Name des Features, dessen Unterstützung getestet werden soll. Die gültigen FeatureNamen für den DOM Level 2-Standard werden in der Tabelle in der Beschreibung aufgeführt. Die Feature-Namen unterscheiden nicht zwischen Groß- und Kleinschreibung. version
Rückgabewert true, wenn die Implementierung die angegebene Version des angegebenen Features vollständig unterstützt, andernfalls false. Wenn keine Versionsnummer angegeben wurde, gibt die Methode true zurück, falls die Implementierung jede beliebige Version des angegebenen Features voll und ganz unterstützt.
Beschreibung Der W3C DOM-Standard ist modular, und die Implementierungen brauchen nicht unbedingt alle Module oder Features des Standards zu unterstützen. Mit dieser Methode testet man, ob eine DOM-Implementierung ein angegebenes Modul der DOM-Spezifikation unterstützt. In den Verfügbarkeitsinformationen zu den einzelnen Einträgen in dieser DOM-Referenz steht der Name des Moduls. Beachten Sie, dass Internet Explorer 5 und 5.5 die DOM Level 1-Spezifikation zwar teilweise unterstützen, aber eine Unterstützung für diese wichtige Methode erst mit dem IE 6 hinzugefügt wurde. Die folgende Tabelle zeigt alle Modulnamen, auf die das feature-Argument gesetzt werden kann. Feature
Beschreibung
Core
Node, Element, Document, Text und andere Basis-Interfaces, die für alle DOM-Implementierungen erforderlich sind, werden implementiert. Alle dazu konformen Implementierungen müssen dieses Modul unterstützen.
HTML
HTMLElement, HTMLDocument und die anderen HTML-spezifischen Interfaces werden implementiert.
XML
Entity, EntityReference, ProcessingInstruction, Notation und die anderen Knotentypen, die nur für XMLDokumente nützlich sind, werden implementiert.
StyleSheets
Einfache Interfaces zur Beschreibung generischer Stylesheets werden implementiert.
Referenz für clientseitiges JavaScript |
845
Referenz für clientseitiges JavaScript
Die Feature-Versionsnummer, deren Unterstützung getestet werden soll, bzw. null oder der leere String "", wenn die Unterstützung einer beliebigen Version des betreffenden Features ausreicht. In der Level 2-DOM-Spezifikation werden die Versionsnummern 1.0 und 2.0 unterstützt.
491-0.book Seite 846 Mittwoch, 4. April 2007 9:55 09
e-bol.net
DOMParser Feature
Beschreibung
CSS
Interfaces für CSS-Stylesheets werden implementiert.
CSS2
Das CSS2Properties-Interface wird implementiert.
Events
Die wichtigsten Interfaces für das Event-Handling werden implementiert.
UIEvents
Die Interfaces für Benutzeroberflächen-Events werden implementiert.
MouseEvents
Die Interfaces für Maus-Events werden implementiert.
HTMLEvents
Die Interfaces für HTML-Events werden implementiert.
MutationEvents
Die Interfaces für Document-Mutation-Events werden implementiert.
Range
Die Interfaces zur Bearbeitung von Dokumentbereichen werden implementiert.
Traversal
Die Interfaces für den fortgeschrittenen Dokument-Durchlauf werden implementiert
Views
Die Interfaces für Dokument-Views werden implementiert.
Beispiel Diese Methode können Sie z.B. in folgendem Code verwenden: // Prüfe, ob der Browser die DOM Level 2-Range-API unterstützt if (document.implementation && document.implementation.hasFeature && document.implementation.hasFeature("Range", "2.0")) { // Wenn ja, verwende sie hier... } else { // Wenn nicht, greife auf Code zurück, der keine Range-Objekte benötigt }
Siehe auch Node.isSupported( )
DOMParser Parst XML-Markup, um ein Document zu erzeugen
Konstruktor new DOMParser( )
Methoden parseFromString( )
Parst XML-Markup und gibt ein Document zurück.
846 | Referenz für clientseitiges JavaScript
Firefox 1.0, Safari 2.01, Opera 7.60 Object ➝ DOMParser
491-0.book Seite 847 Mittwoch, 4. April 2007 9:55 09
e-bol.net
DOMParser.parseFromString( )
Beschreibung Ein DOMParser-Objekt parst XML-Text und gibt ein XML-Document-Objekt zurück. Um einen DOMParser zu verwenden, instanziieren Sie ihn mit dem Konstruktor ohne Argumente und rufen dann seine parseFromString( )-Methode auf: var doc = (new DOMParser( )).parseFromString(text);
Internet Explorer unterstützt das DOMParser-Objekt nicht. Stattdessen unterstützt er das Parsen von XML mit Document.loadXML( ). Beachten Sie, dass das XMLHttpRequest-Objekt auch XML-Dokumente parsen kann. Vergleichen Sie dazu die responseXML-Eigenschaft des XMLHttpRequest.
Siehe auch Document.loadXML( ), XMLHttpRequest; Kapitel 21
DOMParser.parseFromString( ) Referenz für clientseitiges JavaScript
Der Content Type des Texts. Dieser kann »text/xml«, »application/xml« oder »application/xhtml+xml« sein. Beachten Sie, dass »text/html« nicht unterstützt wird. Rückgabewert Ein Document-Objekt, das die geparste Repräsentation von text enthält. Eine IE-spezifische Alternative für diese Methode finden Sie unter Document.loadXML( ).
Element
DOM Level 1 Core
Ein HTML- oder XML-Element
Node ➝ Element
Subinterfaces HTMLElement
Eigenschaften readonly String tagName
Der Tag-Name des Elements. Für ein
-Element von HTML wäre das z.B. der String »P«. Bei HTML-Dokumenten wird der Tag-Name – unabhängig von seiner Schreibweise
Referenz für clientseitiges JavaScript |
847
491-0.book Seite 848 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Element
im Dokumentquelltext – in Großbuchstaben konvertiert. XML-Dokumente unterscheiden zwischen Groß- und Kleinschreibung, sodass hier der Name in exakt derselben Schreibweise wie im Dokumentquelltext wiedergegeben wird. Diese Eigenschaft hat denselben Wert wie die geerbte nodeName-Eigenschaft des Node-Interfaces.
Methoden addEventListener( )
Fügt dem Satz der Event-Handler für dieses Element eine Event-Handler-Funktion hinzu. Dies ist eine DOM-Standard-Methode, die von allen modernen Browsern außer IE unterstützt wird. attachEvent( )
Fügt dem Satz der Event-Handler für dieses Element eine Event-Handler-Funktion hinzu. Diese Methode ist die IE-spezifische Alternative zu addEventListener( ). detachEvent( )
Entfernt eine Event-Handler-Funktion von diesem Element. Diese Methode ist die IEspezifische Alternative zur normalen removeEventListener( )-Methode. dispatchEvent( )
Übermittelt ein synthetisches Event an diesen Knoten. getAttribute( )
Gibt den Wert eines angegebenen Attributs als String zurück. getAttributeNS( )
Gibt den Stringwert eines Attributs zurück, das durch den lokalen Namen und die Namensraum-URI näher spezifiziert ist. Diese Methode eignet sich nur für XML-Dokumente, die Namensräume verwenden. getAttributeNode( )
Gibt den Namen eines angegebenen Attributs als Attr-Knoten zurück. getAttributeNodeNS( )
Gibt den Attr-Wert eines Attributs zurück, das durch den lokalen Namen und die Namensraum-URI näher spezifiziert ist. Diese Methode eignet sich nur für XML-Dokumente, die Namensräume verwenden. getElementsByTagName( )
Gibt ein Array (technisch gesehen eine NodeList) zurück, das alle NachfahrenelementKnoten dieses Elements enthält, die den angegebenen Tag-Namen haben. Sie erscheinen in derselben Reihenfolge wie im Dokument. getElementsByTagNameNS( ) Wie getElementsByTagName(), nur dass der Element-Tag-Name durch einen lokalen Namen
und eine Namensraum-URI spezifiziert ist. Diese Methode eignet sich nur für XML-Dokumente, die Namensräume verwenden. hasAttribute( ) Gibt true zurück, wenn dieses Element ein Attribut des angegebenen Namens hat, andernfalls false. Beachten Sie, dass diese Methode true zurückgibt, wenn das angegebene
Attribut im Dokumentquelltext explizit spezifiziert wird oder wenn die DTD des Dokuments einen Standardnamen für dieses Attribut angibt.
848 | Referenz für clientseitiges JavaScript
491-0.book Seite 849 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Element hasAttributeNS( ) Wie hasAttribute(), nur dass das Attribut durch eine Kombination von lokalem Namen
und Namensraum-URI spezifiziert ist. Diese Methode kann nur für XML-Dokumente eingesetzt werden, die Namensräume verwenden. removeAttribute( )
Löscht das angegebene Attribut aus diesem Element. Denken Sie aber daran, dass diese Methode nur solche Attribute löscht, die im Dokumentquelltext für dieses Element explizit angegeben sind. Wenn die DTD einen Standardwert für dieses Attribut spezifiziert, dann wird dieser der neue Wert des Attributs. removeAttributeNode( )
Löscht den angegebenen Attr-Knoten aus der Liste der Attribute für dieses Element. Beachten Sie, dass sich so nur Attribute löschen lassen, die im Dokumentquelltext für dieses Element explizit angegeben sind. Wenn die DTD einen Standardwert für dieses Attribut festlegt, dann wird ein neuer Attr-Knoten erzeugt, der den Standardattributwert repräsentiert.
lokalem Namen und Namensraum-URI näher bezeichnet wird. Diese Methode eignet sich nur für XML-Dokumente, die Namensräume verwenden. removeEventListener( )
Entfernt eine Event-Handler-Funktion aus dem Satz der Handler dieses Elements. Das ist eine DOM-Standard-Methode, die von allen modernen Browsern außer IE unterstützt wird. IE verwendet detachEvent( ). setAttribute( )
Setzt das angegebene Attribut auf den angegebenen Stringwert. Wenn noch kein Attribut dieses Namens vorhanden ist, wird dem Element ein neues Attribut hinzugefügt. setAttributeNode( )
Fügt den angegebenen Attr-Knoten zur Liste der Attribute für dieses Element hinzu. Wenn bereits ein Attribut dieses Namens vorhanden ist, wird sein Wert ersetzt. setAttributeNodeNS( ) Wie setAttributeNode(), nur dass diese Methode sich für Knoten eignet, die von Document. createAttributeNS() zurückgegeben wurden. Diese Methode eignet sich nur für XML-
Dokumente, die Namensräume verwenden. setAttributeNS( ) Wie setAttribute(), nur dass das zu setzende Attribut durch die Kombination von
lokalem Namen und Namensraum-URI näher bezeichnet wird. Diese Methode eignet sich nur für XML-Dokumente, die Namensräume verwenden.
Beschreibung Das Element-Interface stellt HTML- oder XML-Elemente oder -Tags dar. Die Eigenschaft tagName gibt den Elementnamen an. Die documentElement-Eigenschaft eines Dokuments bezieht sich auf das Wurzelelement-Objekt für dieses Dokument. Die body-Eigenschaft des HTMLDocument-Objekts ist ähnlich: Sie bezieht sich auf das -Element des Dokuments. Um ein bestimmtes benanntes Element in einem HTML-Dokument zu finden, verwenden Sie
Referenz für clientseitiges JavaScript |
849
Referenz für clientseitiges JavaScript
removeAttributeNS( ) Wie removeAttribute(), nur dass das zu löschende Attribut durch eine Kombination von
491-0.book Seite 850 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Element.addEventListener( ) Document.getElementById( ) (und geben dem Element mit dem id-Attribut einen eindeutigen Namen). Um Elemente anhand von Tag-Namen zu finden, verwenden Sie getElementsByTagName( ), die sowohl eine Methode von Element als auch von Document ist. In HTMLDokumenten können Sie auch das ähnliche HTMLDocument.getElementsByName( ) verwenden, um Elemente anhand der Werte ihrer name-Attribute zu finden. Schließlich können Sie mit Document.createElement( ) auch neue Element-Objekte zum Einfügen in ein Dokument
erzeugen. Mit der addEventListener( )-Methode (und ihrer IE-spezifischen Alternative attachEvent( )) lassen sich Event-Handler-Funktionen für spezielle Eventtypen bei einem Element registrieren. Eine vollständige Beschreibung finden Sie in Kapitel 17. Technisch gesehen werden addEventListener( ), removeEventListener( ) und dispatchEvent( ) vom EventTarget-Interface der DOM Level 2 Events-Spezifikation definiert. Da alle Element-Objekte EventTarget implementieren, werden hier die Methoden aufgeführt. Die diversen anderen Methoden dieses Interfaces geben Zugriff auf die Elementattribute. In HTML-Dokumenten (und auch vielen XML-Dokumenten) haben alle Attribute einfache Stringwerte. Sie können jede erforderliche Attributbearbeitung mit den einfachen Methoden getAttribute() und setAttribute() durchführen. Wenn Sie mit XML-Dokumenten arbeiten, die Entity-Referenzen als Teile von Attributwerten enthalten können, müssen Sie mit Attr-Objekten und ihren Knoten-Teilbäumen umgehen. Sie können das Attr-Objekt für ein Attribut mit getAttributeNode() holen und mit setAttributeNode() setzen oder die Attr-Knoten des attributes[]-Arrays des Node-Interfaces durchlaufen. Wenn Sie mit einem XML-Dokument arbeiten, das XML-Namensräume verwendet, müssen Sie die Methoden einsetzen, deren Namen auf »NS« enden. In der DOM Level 1-Spezifikation gehörte die Methode normalize() zum Element-Interface. In der Level 2-Spezifikation ist normalize() dagegen Teil des Node-Interface. Alle Element-Knoten erben diese Methode und können sie nach wie vor nutzen.
Siehe auch HTMLElement, Node; Kapitel 15, Kapitel 17
Element.addEventListener( )
DOM Level 2 Events
Registriert einen Event-Handler
Überblick void addEventListener(String typ, Function listener, boolean useCapture);
Argumente typ
Der Typ von Event, für den der Event-Listener aufgerufen werden soll, z.B. »load«, »click« oder »mousedown«.
850 | Referenz für clientseitiges JavaScript
491-0.book Seite 851 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Element.attachEvent( ) listener
Die Event-Listener-Funktion, die aufgerufen wird, wenn ein Event des angegebenen Typs an dieses Element übermittelt wird. Beim Aufruf wird ein Event-Objekt an diese ListenerFunktion übergeben; sie wird als Methode des Elements aufgerufen, für das sie registriert ist. useCapture
Ist diese Eigenschaft true, so wird der angegebene listener nur beim Abfangen der EventAusbreitung aufgerufen. Häufiger ist der Wert false. Er bedeutet, dass listener nicht in der Phase des Einfangens aufgerufen wird, sondern dann, wenn dieser Knoten das tatsächliche Event-Ziel ist oder wenn das Event von seinem ursprünglichen Ziel zu diesem Knoten hochsteigt.
Beschreibung
addEventListener( ) kann mehrmals aufgerufen werden, um mehrere Event-Handler für
denselben Event-Typ auf demselben Knoten zu registrieren. Das DOM garantiert jedoch keine bestimmte Reihenfolge, in der mehrere Event-Handler aufgerufen werden. Wenn dieselbe Event-Listener-Funktion zweimal auf demselben Knoten mit denselben Argumenten für typ und useCapture registriert wird, so wird die zweite Registrierung einfach ignoriert. Wird ein neuer Event-Listener auf diesem Knoten registriert, wenn gerade ein Event auf diesem Knoten behandelt wird, so wird der neue Event-Listener für dieses Event nicht aufgerufen. Wenn ein Knoten mit Node.cloneNode() oder Document.importNode() dupliziert wird, werden die für den Originalknoten registrierten Event-Listener nicht kopiert. Diese Methode wird auch durch die Document- und Window-Objekte definiert, auf denen sie auf die gleiche Art arbeitet.
Siehe auch Event; Kapitel 17
Element.attachEvent( )
IE 4
Registriert einen Event-Handler
Überblick void attachEvent(String typ, Function listener);
Referenz für clientseitiges JavaScript |
851
Referenz für clientseitiges JavaScript
Diese Methode fügt der Menge der Listener, die auf diesem Knoten zur Behandlung von Events des angegebenen typs registriert sind, die angegebene Event Listener-Funktion hinzu. Wenn useCapture den Wert true hat, wird der Listener als Event-Listener für das Capturing hinzugefügt. Hat useCapture den Wert false, so wird er als normaler Event-Listener registriert.
491-0.book Seite 852 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Element.detachEvent( )
Argumente typ
Der Event-Typ, für den der Event-Listener aufgerufen werden soll, mit einem voranstehenden »on«-Präfix. z.B. »onload«, »onclick« oder »onmousedown«. listener
Die Event-Listener-Funktion, die aufgerufen wird, wenn ein Event des angegebenen Typs an dieses Element übergeben wird. Dieser Funktion werden keine Argumente übergeben, aber sie kann auf das Event-Objekt über die event-Eigenschaft des Window-Objekts zugreifen.
Beschreibung Diese Methode ist eine IE-spezifische Event-Registrationsmethode. Sie dient dem gleichen Zweck wie die normale addEventListener( )-Methode (die nicht von IE unterstützt wird), unterscheidet sich von dieser Funktion aber in mehreren wichtigen Punkten: • Da das IE-Event-Modell das Abfangen von Events nicht unterstützt, erwarten attachEvent( ) und detachEvent( ) lediglich zwei Argumente: den Event-Typ und die Handler-Funktion. • Die an die IE-Methoden übergebenen Event-Handler-Namen sollten das »on«-Präfix enthalten. Verwenden Sie beispielsweise nicht »click« für addEventListener( ), sondern »onclick« mit attachEvent( ). • Funktionen, die mit attachEvent( ) registriert sind, werden ohne Event-Objekt-Argument aufgerufen. Stattdessen müssen sie die event-Eigenschaft des Window-Objekts lesen. • Funktionen, die mit attachEvent( ) registriert sind, werden als globale Funktionen aufgerufen und nicht als Methoden des Dokument-Elements, in dem das Event aufgetreten ist. Wenn also ein mit attachEvent( ) registrierter Event-Handler ausgeführt wird, bezieht sich das this-Schlüsselwort nicht auf das Target-Element des Events, sondern auf das Window-Objekt. • Mit attachEvent( ) kann die gleiche Event-Handler-Funktion mehrmals registriert werden. Findet ein Event vom angegebenen Typ statt, wird die registrierte Funktion so oft aufgerufen, wie sie registriert ist. Diese Methode wird auch durch die Document- und Window-Objekte definiert, auf denen sie auf die gleiche Art arbeitet.
Siehe auch Element.addEventListener( ), Event; Kapitel 17
Element.detachEvent( ) Löscht einen Event-Listener
Überblick void detachEvent(String typ, Function listener)
852 | Referenz für clientseitiges JavaScript
IE 4
491-0.book Seite 853 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Element.dispatchEvent( )
Argumente typ
Der Event-Typ, für den der Listener gelöscht werden soll, mit einem »on«-Präfix, zum Beispiel: »onclick«. listener
Die zu entfernende Event-Listener-Funktion.
Beschreibung Diese Methode hebt die von der attachEvent( )-Methode durchgeführte Event-Handler-Funktionsregistrierung wieder auf. Es ist die IE-spezifische Alternative zu removeEventListener( ). Um eine Event-Handler-Funktion für ein Element zu löschen, rufen Sie einfach detachEvent auf und übergeben die gleichen Argumente, die Sie ursprünglich an attachEvent( ) übergeben haben. Diese Methode wird auch durch die Document- und Window-Objekte definiert, auf denen sie auf die gleiche Art arbeitet.
DOM Level 2 Events
Übermittelt ein synthetisches Event an diesen Knoten
Das zu übermittelnde Event-Objekt. Rückgabewert false, wenn die preventDefault()-Methode von evt während der Event-Ausbreitung aufgerufen wurde, andernfalls true. Exceptions Diese Methode löst eine Exception aus, wenn das Event-Objekt evt nicht initialisiert ist oder wenn seine type-Eigenschaft null oder ein leerer String ist.
Beschreibung Diese Methode übermittelt ein synthetisches Event, das mit Document.createEvent() erzeugt und mit der vom Event-Interface oder einem seiner Subinterfaces definierten Initialisierungsmethode initialisiert wurde. Der Knoten, auf dem die Methode aufgerufen wird, wird das Event-Ziel, aber das Event breitet sich zunächst während der Capturing-Phase im Dokumentenbaum nach unten aus und steigt dann, falls seine bubbles-Eigenschaft true ist, wieder im Dokumentenbaum nach oben, nachdem es am eigentlichen Event-Ziel behandelt wurde.
Referenz für clientseitiges JavaScript |
853
Referenz für clientseitiges JavaScript
Element.dispatchEvent( )
491-0.book Seite 854 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Element.getAttribute( )
Siehe auch Document.createEvent( ), Event.initEvent( ), MouseEvent.initMouseEvent( )
Element.getAttribute( )
DOM Level 1 Core
Gibt den Stringwert eines angegebenen Attributs zurück
Überblick String getAttribute(String name);
Argumente name
Der Name des Attributs, dessen Wert zurückgegeben werden soll. Rückgabewert Der neue Wert des Attributs als String. Wenn das Attribut nicht definiert ist, sollte diese Methode einen leeren String zurückgeben. Allerdings geben manche Implementierungen in diesem Fall null zurück.
Beschreibung getAttribute( ) gibt den Wert eines angegebenen Elementattributs zurück. Das HTMLElement-Objekt definiert JavaScript-Eigenschaften, die allen standardisierten HTML-Attributen entsprechen. Sie müssen diese Methode mit HTML-Dokumenten also nur verwenden, wenn Sie den Wert von Attributen abfragen, die nicht dem Standard entsprechen.
In XML-Dokumenten kann man auf Attributwerte nicht unmittelbar als Eigenschaften des Elements zugreifen, sondern sie müssen mit diesem Methodenaufruf nachgeschlagen werden. Bei XML-Dokumenten, die Namensräume verwenden, nehmen Sie getAttributeNS( ).
Beispiel Der folgende Code zeigt zwei verschiedene Möglichkeiten, einen Attributwert eines HTML-Elements zu beschaffen: // Hole alle Bilder im Dokument var images = document.body.getElementsByTagName("img"); // Hole das SRC-Attribut des ersten Bilds var src0 = images[0].getAttribute("src"); // Hole das SRC-Attribut des zweiten Bilds, indem du einfach die Eigenschaft liest var src1 = images[1].src;
Siehe auch Element.getAttributeNode( ), Element.getAttributeNS( ), Node
854 | Referenz für clientseitiges JavaScript
491-0.book Seite 855 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Element.getAttributeNode( )
Element.getAttributeNode( )
DOM Level 1 Core
Gibt den Attr-Knoten für das angegebene Attribut zurück
Überblick Attr getAttributeNode(String name);
Argumente name
Der Name des gewünschten Attributs. Rückgabewert Ein Attr-Knoten, der den Wert des angegebenen Attributs darstellt, oder null, wenn das Element dieses Attribut nicht hat.
Beschreibung
erhalten, die aus dem Node-Interface geerbt wurde.
Siehe auch Element.getAttribute( ), Element.getAttributeNodeNS( )
Element.getAttributeNodeNS( )
DOM Level 2 Core
Gibt den Attr-Knoten für ein Attribut mit einem Namensraum zurück
Die URI, die den Namensraum dieses Attributs eindeutig bezeichnet, oder null, wenn kein Namensraum vorhanden ist. lokalerName
Der Bezeichner, der den Namen des Attributs innerhalb seines Namensraums angibt. Rückgabewert Der Attr-Knoten, der den Wert des angegebenen Attributs darstellt, oder null, wenn das Element dieses Attribut nicht hat.
Referenz für clientseitiges JavaScript |
855
Referenz für clientseitiges JavaScript
getAttributeNode( ) gibt einen Attr-Knoten zurück, der den Wert eines angegebenen Attributs repräsentiert. Beachten Sie, dass Sie diesen Attr-Knoten auch über die attributes-Eigenschaft
491-0.book Seite 856 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Element.getAttributeNS( )
Beschreibung Diese Methode arbeitet wie getAttributeNode(), nur dass das Attribut durch die Kombination von Namensraum-URI und einem innerhalb dieses Namensraums definierten lokalen Namen näher bezeichnet ist. Diese Methode kann nur für XML-Dokumente eingesetzt werden, die Namensräume verwenden.
Siehe auch Element.getAttributeNode( ), Element.getAttributeNS( )
Element.getAttributeNS( )
DOM Level 2 Core
Holt den Wert eines Attributs, das Namensräume verwendet
Die URI, die den Namensraum dieses Attributs eindeutig bezeichnet, oder null, wenn kein Namensraum vorhanden ist. lokalerName
Der Bezeichner, der den Namen des Attributs innerhalb seines Namensraums angibt. Rückgabewert Der neue Wert des Attributs als String. Wurde das Attribut nicht definiert, sollte diese Methode einen leeren String zurückgeben. Manche Implementierungen geben jedoch null zurück.
Beschreibung Diese Methode funktioniert genau wie die getAttribute( )-Methode, nur dass das Attribut durch die Kombination von Namensraum-URI und einem innerhalb dieses Namensraums definierten lokalen Namen näher bezeichnet ist. Diese Methode kann nur für XML-Dokumente eingesetzt werden, die Namensräume verwenden.
Siehe auch Element.getAttribute( ), Element.getAttributeNodeNS( )
Element.getElementsByTagName( ) Sucht Nachfahren-Elemente mit einem angegebenen Tag-Namen
491-0.book Seite 857 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Element.getElementsByTagNameNS( )
Argumente name
Der Tag-Name der angegebenen Elemente oder »*«, um anzugeben, dass alle NachfahrenElemente unabhängig von ihren Tag-Namen zurückgegeben werden sollen. Rückgabewert Ein schreibgeschütztes Array (technisch gesehen eine NodeList) von Element-Objekten, die Nachfahren dieses Elements sind und den angegebenen Tag-Namen haben.
Beschreibung Diese Methode durchläuft alle Nachfahren dieses Elements und gibt ein Array (eigentlich ein NodeList-Objekt) mit Element-Knoten zurück, die alle Dokumentelemente des angegebenen Tagnamens darstellen. Die Elemente erscheinen im Rückgabe-Array in derselben Reihenfolge wie im Dokumentquelltext.
Beispiel Mit folgendem Code können Sie alle -Tags in einem Dokument finden: var divisions = document.body.getElementsByTagName("div");
Und dieser Code liefert Ihnen alle
-Tags innerhalb des ersten -Tags: var paragraphs = divisions[0].getElementsByTagname("p");
Siehe auch Document.getElementById( ) Document.getElementsByTagName( ) HTMLDocument.getElementsByName( )
Element.getElementsByTagNameNS( )
DOM Level 2 Core
Gibt Nachfahren-Elemente mit dem angegebenen Namen und Namensraum zurück
Die URI, die den Namensraum des Elements eindeutig bezeichnet. lokalerName
Der Bezeichner, der den Namen des Elements innerhalb seines Namensraums angibt.
Referenz für clientseitiges JavaScript |
857
Referenz für clientseitiges JavaScript
Das Document-Interface hat auch eine getElementsByTagName()-Methode, die genauso wie diese funktioniert, aber das gesamte Dokument und nicht nur die Nachfahren eines einzigen Elements durchläuft. Bitte verwechseln Sie diese Methode nicht mit der Methode HTMLDocument.getElementsByName(), die Elemente anhand des Werts ihrer name-Attribute und nicht anhand ihrer Tag-Namen sucht.
491-0.book Seite 858 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Element.hasAttribute( )
Rückgabewert Ein schreibgeschütztes Array (technisch gesehen eine NodeList) von Element-Objekten, die Nachfahren dieses Elements sind und den angegebenen Tag-Namen und Namensraum haben.
Beschreibung Diese Methode funktioniert wie getElementsByTagName(), nur dass der Tag-Name des gewünschten Elements durch die Kombination von Namensraum-URI und einem innerhalb dieses Namensraums definierten lokalen Namen näher bezeichnet ist. Diese Methode eignet sich nur für XML-Dokumente, die Namensräume verwenden.
Siehe auch Document.getElementsByTagNameNS( ), Element.getElementsByTagName( )
Element.hasAttribute( )
DOM Level 2 Core
Stellt fest, ob dieses Element ein angegebenes Attribut hat
Überblick boolean hasAttribute(String name);
Argumente name
Der Name des gewünschten Attributs. Rückgabewert true, wenn dieses Element einen angegebenen Wert oder Defaultwert für das bezeichnete Attribut hat, andernfalls false.
Beschreibung Diese Methode stellt fest, ob ein Element ein Attribut mit dem bezeichneten Namen hat, gibt aber den Wert dieses Attributs nicht zurück. Die Methode hasAttribute() gibt true zurück, wenn das angegebene Attribut explizit im Dokument spezifiziert ist, aber auch, wenn die interne Teilmenge des Dokumenttyps einen Standardwert dafür angibt.
Siehe auch Element.getAttribute( ), Element.setAttribute( )
Element.hasAttributeNS( ) Stellt fest, ob dieses Element ein angegebenes Attribut hat
491-0.book Seite 859 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Element.removeAttribute( )
Argumente namensraumURI
Der eindeutige Namensraumbezeichner für das Attribut oder null, wenn kein Namensraum vorhanden ist. lokalerName
Der Name des Attributs im angegebenen Namensraum. Rückgabewert true, wenn für dieses Element entweder explizit ein Wert angegeben oder ein Standardwert für das bezeichnete Attribut festgelegt wurde, andernfalls false.
Beschreibung Diese Methode funktioniert wie hasAttribute(), nur dass das zu prüfende Attribut durch seinen Namensraum und seinen Namen spezifiziert ist. Diese Methode eignet sich nur für XML-Dokumente, die Namensräume verwenden. Referenz für clientseitiges JavaScript
Siehe auch Element.getAttributeNS( ), Element.hasAttribute( ), Element.setAttributeNS( )
Element.removeAttribute( )
DOM Level 1 Core
Löscht ein angegebenes Elementattribut
Überblick void removeAttribute(String name);
Argumente name
Der Name des zu löschenden Attributs. Exceptions Diese Methode kann eine DOMException mit dem code NO_MODIFICATION_ALLOWED_ERR auslösen, wenn dieses Element schreibgeschützt ist und seine Attribute nicht gelöscht werden können.
Beschreibung removeAttribute( ) löscht ein angegebenes Attribut aus diesem Element. Wenn das angegebene Attribut einen durch den Dokumenttyp spezifizierten Standardwert hat, geben nachfolgende Aufrufe der Methode getAttribute() diesen Standardwert zurück. Wenn Sie versuchen, nicht vorhandene Attribute oder solche Attribute zu löschen, die nicht angegeben werden, sondern einen Standardwert haben, so wird dieser Versuch stillschweigend ignoriert.
Siehe auch Element.getAttribute( ), Element.setAttribute( ), Node
Referenz für clientseitiges JavaScript |
859
491-0.book Seite 860 Mittwoch, 4. April 2007 9:55 09
Der Attr-Knoten, der aus dem Element gelöscht werden soll. Rückgabewert Der gelöschte Attr-Knoten. Exceptions Diese Methode kann eine DOMException mit den folgenden code-Werten auslösen: NO_MODIFICATION_ALLOWED_ERR
Das Element ist schreibgeschützt und verbietet das Löschen von Attributen. NOT_FOUND_ERR altesAttr ist kein Attribut dieses Elements.
Beschreibung Diese Methode löscht einen Attr-Knoten aus der Attributmenge eines Elements und gibt ihn zurück. Wenn das gelöschte Attribut einen durch eine DTD spezifizierten Standardwert hat, wird ein neues Attr mit diesem Standardwert hinzugefügt. Oft ist es einfacher, removeAttribute() statt dieser Methode zu benutzen.
Siehe auch Attr, Element.removeAttribute( )
Element.removeAttributeNS( )
DOM Level 2 Core
Löscht ein durch Name und Namensraum spezifiziertes Attribut
Der eindeutige Bezeichner des Namensraums dieses Attributs oder null, wenn kein Namensraum vorhanden ist. lokalerName
Der Name des Attributs im angegebenen Namensraum.
860 | Referenz für clientseitiges JavaScript
491-0.book Seite 861 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Element.removeEventListener( )
Exceptions Diese Methode kann eine DOMException mit dem code NO_MODIFICATION_ALLOWED_ERR auslösen, wenn dieses Element schreibgeschützt ist und seine Attribute nicht gelöscht werden können.
Beschreibung removeAttributeNS() funktioniert wie removeAttribute(), nur dass das zu löschende Attribut durch seinen Namen und Namensraum statt nur durch seinen Namen angegeben wird. Diese Methode ist nur für XML-Dokumente sinnvoll, die Namensräume verwenden.
Siehe auch Element.getAttributeNS( ), Element.removeAttribute( ), Element.setAttributeNS( )
Element.removeEventListener( )
DOM Level 2 Events
Löscht einen Event-Listener Referenz für clientseitiges JavaScript
Überblick void removeEventListener(String type, Function listener, boolean useCapture);
Argumente type
Der Event-Typ, für den der Event-Listener gelöscht werden soll. listener
Die zu entfernende Event-Listener-Funktion. useCapture true, wenn ein abfangender Event-Listener entfernt werden soll; false, wenn ein normaler
Event-Listener entfernt werden soll.
Beschreibung Diese Methode entfernt die angegebene Event-Listener-Funktion. Die Argumente typ und useCapture müssen dieselben wie in dem zugehörigen Aufruf von addEventListener() sein. Wird kein Event-Listener gefunden, der zu den angegebenen Argumenten passt, tut diese Methode gar nichts. Wenn eine Event-Listener-Funktion von dieser Methode entfernt wurde, wird sie für den angegebenen Event-Typ auf diesem Knoten nicht mehr aufgerufen. Das gilt auch dann, wenn der Event-Listener von einem anderen Listener entfernt wird, der für denselben Event-Typ auf demselben Knoten registriert ist. Diese Methode wird auch durch die Document- und Window-Objekte definiert, auf denen sie auf die gleiche Art arbeitet.
Referenz für clientseitiges JavaScript |
861
491-0.book Seite 862 Mittwoch, 4. April 2007 9:55 09
Der Name des zu erzeugenden oder zu ändernden Attributs. wert
Der Stringwert des Attributs. Exceptions Diese Methode kann eine DOMException mit den folgenden code-Werten auslösen: INVALID_CHARACTER_ERR Das name-Argument enthält ein Zeichen, das in HTML- oder XML-Attributnamen unzu-
lässig ist. NO_MODIFICATION_ALLOWED_ERR
Dieses Element ist schreibgeschützt und verbietet Attributänderungen.
Beschreibung Diese Methode setzt das angegebene Attribut auf den angegebenen Wert. Ist noch kein Attribut dieses Namens vorhanden, so wird ein neues angelegt. Die HTMLElement-Objekte eines HTML-Dokuments definieren JavaScript-Eigenschaften, die allen standardisierten HTML-Attributen entsprechen. Sie müssen diese Methode also nur verwenden, wenn Sie ein Attribut setzen wollen, das dem Standard nicht folgt.
Beispiel // Setze das TARGET-Attribut für alle Links in einem Dokument var links = document.body.getElementsByTagName("a"); for(var i = 0; i < links.length; i++) { links[i].setAttribute("target", "newwindow"); // oder einfacher: links[i].target = "newwindow" }
Siehe auch Element.getAttribute( ), Element.removeAttribute( ), Element.setAttributeNode( )
862 | Referenz für clientseitiges JavaScript
491-0.book Seite 863 Mittwoch, 4. April 2007 9:55 09
Der Attr-Knoten, der das Attribut darstellt, das hinzugefügt oder dessen Wert geändert werden soll. Rückgabewert Der Attr-Knoten, der durch neuesAttr ersetzt wurde, oder null, wenn kein Attribut ersetzt wurde. Referenz für clientseitiges JavaScript
Exceptions Diese Methode kann eine DOMException mit einem der folgenden code-Werte auslösen: INUSE_ATTRIBUTE_ERR neuesAttr ist bereits ein Element der Attributmenge eines anderen Element-Knotens. NO_MODIFICATION_ALLOWED_ERR
Der Element-Knoten ist schreibgeschützt und verbietet Attributänderungen. WRONG_DOCUMENT_ERR neuesAttr hat eine andere ownerDocument-Eigenschaft als das Element, für das es gesetzt
wird.
Beschreibung Diese Methode fügt der Attributmenge eines Element-Knotens einen neuen Attr-Knoten hinzu. Wenn für das Element bereits ein Attribut dieses Namens existiert, wird es durch neuesAttr ersetzt, und der ersetzte Attr-Knoten wird zurückgegeben. Wenn noch kein solches Attribut existiert, definiert diese Methode ein neues Attribut für das Element. Normalerweise ist es einfacher, setAttribute() anstelle von setAttributeNode() zu verwenden.
Siehe auch Attr, Document.createAttribute( ), Element.setAttribute( )
Element.setAttributeNodeNS( )
DOM Level 2 Core
Fügt einem Element einen Namensraum-Attr-Knoten hinzu
491-0.book Seite 864 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Element.setAttributeNS( )
Argumente neuesAttr
Der Attr-Knoten, der das Attribut darstellt, das hinzugefügt oder dessen Wert geändert werden soll. Rückgabewert Der Attr-Knoten, der durch neuesAttr ersetzt wurde, oder null, wenn kein Attribut ersetzt wurde. Exceptions Diese Methode löst aus denselben Gründen wie setAttributeNode() Exceptions aus. Sie kann auch eine DOM-Exception mit dem code NOT_SUPPORTED_ERR auslösen, um anzuzeigen, dass die Methode deswegen nicht implementiert wird, weil die aktuelle Implementierung keine XMLDokumente und -Namensräume unterstützt.
Beschreibung Diese Methode funktioniert wie setAttributeNode(), nur dass sie für Attr-Knoten entwickelt wurde, die Attribute repräsentieren, die durch ihren Namensraum und Namen spezifiziert werden. Diese Methode eignet sich nur für XML-Dokumente, die Namensräume verwenden. Eventuell ist sie auf Browsern, die keine XML-Dokumente unterstützen, auch gar nicht implementiert (d.h., sie löst einen NOT_SUPPORTED_ERR aus).
Siehe auch Attr, Document.createAttributeNS( ), Element.setAttributeNS( ), Element.setAttributeNode( )
Element.setAttributeNS( )
DOM Level 2 Core
Erzeugt oder ändert ein Attribut mit einem Namensraum
Die URI, die den Namensraum des zu setzenden oder zu erzeugenden Attributs eindeutig identifiziert, oder null, wenn kein Namensraum vorhanden ist. qualifizierterName
Der Attributname, angegeben durch ein optionales Namensraumpräfix und einen Doppelpunkt, gefolgt von einem innerhalb des Namensraums definierten lokalen Namen. wert
Der neue Wert des Attributs.
864 | Referenz für clientseitiges JavaScript
491-0.book Seite 865 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Event
Exceptions Diese Methode kann eine DOMException mit den folgenden code-Werten auslösen: INVALID_CHARACTER_ERR Das Argument qualifizierterName enthält ein Zeichen, das in HTML- oder XML-Attribut-
namen unzulässig ist. NAMESPACE_ERR qualifizierterName ist nicht wohlgeformt, oder qualifizierterName und namensraumURI
passen nicht zueinander. NO_MODIFICATION_ALLOWED_ERR
Dieses Element ist schreibgeschützt und verbietet Attributänderungen. NOT_SUPPORTED_ERR
Die DOM-Implementierung unterstützt keine XML-Dokumente.
Beschreibung
Diese Methode eignet sich nur für XML-Dokumente, die Namensräume verwenden. Eventuell ist sie auf Browsern, die keine XML-Dokumente unterstützen, auch gar nicht implementiert (d.h., sie löst einen NOT_SUPPORTED_ERR aus).
Siehe auch Element.setAttribute( ), Element.setAttributeNode( )
Event Informationen über ein Event
DOM Level 2 Events, IE Object ➝ Event
Subinterfaces UIEvent
Standardeigenschaften Die folgenden Eigenschaften werden vom DOM Level 2 Events-Standard definiert. Zusätzliche, typenspezifische Event-Eigenschaften finden Sie unter KeyEvent, MouseEvent und UIEvent: readonly boolean bubbles true, wenn das Element aufgrund seines Typs aufsteigt (solange nicht stopPropagation( ) aufgerufen wird), andernfalls false. readonly boolean cancelable true, wenn die Standardaktion zu diesem Event mit preventDefault( ) gestrichen werden kann, andernfalls false.
Referenz für clientseitiges JavaScript |
865
Referenz für clientseitiges JavaScript
Diese Methode ähnelt setAttribute(), nur dass das zu erzeugende oder zu setzende Attribut durch eine Namensraum-URI und einen qualifizierten Namen spezifiziert ist, der aus einem Namensraumpräfix, einem Doppelpunkt und einem innerhalb des Namensraums gültigen lokalen Namen besteht.
491-0.book Seite 866 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Event readonly Object currentTarget
Das Element, Document oder Window-Objekt, das dieses Event momentan verarbeitet. Beim Abfangen und Aufsteigen unterscheidet sich das von target. readonly unsigned short eventPhase
Die aktuelle Phase der Event-Ausbreitung. Der Wert ist einer der drei nachfolgend aufgeführten Konstanten, die die Phase des Abfangens, die normale Event-Übermittlung und die Aufsteigephase repräsentieren: eventPhase Constant
Wert
Event.CAPTURING_PHASE
1
Event.AT_TARGET
2
Event.BUBBLING_PHASE
3
readonly Object target
Der Zielknoten für dieses Event, d.h. das Element, Document oder Window-Objekt, das das Event erzeugte. readonly Date timeStamp
Das Datum und die Uhrzeit, zu der das Event eintrat (oder, technisch gesprochen, zu der das Event-Objekt erzeugt wurde). Implementierungen brauchen in diesem Feld keine gültige Zeitdaten bereitzustellen. Falls keine solchen vorhanden sind, sollte die getTime( )Methode dieses Datums-Objekts 0 zurückgeben. Vergleichen Sie dazu Date in Teil III in diesem Buch. readonly String type
Der Name des Events, das dieses Event-Objekt darstellt. Das ist der Name, unter dem der Event-Handler registriert wurde, oder auch der Name der Event-Handler-Eigenschaft, bei dem das vorangestellte »on« entfernt wurde, z.B. »click«, »load« oder »submit«.
IE-Eigenschaften Internet Explorer unterstützt (zumindest bis IE 7) das standardisierte DOM-Event-Modell nicht. Das Event-Objekt von IE definiert eine vollständig andere Gruppe von Eigenschaften. Das IE-Event-Modell definiert keine Vererbungshierarchie für unterschiedliche Event-Typen. Folglich sind alle Eigenschaften, die für einen beliebigen Event-Typ relevant sind, hier aufgeführt: boolean altKey
Gibt an, ob beim Eintreten des Events die Alt-Taste gedrückt war. integer button
Bei Maus-Events gibt button an, welche Maustaste(n) gedrückt war(en). Dieser Wert ist eine Bitmaske: Beim Drücken der linken Maustaste wird das 1er-Bit gesetzt, beim Drücken der rechten Maustaste das 2er-Bit, und beim Drücken der mittleren Maustaste (einer Maus mit drei Tasten) wird das 4er-Bit gesetzt. boolean cancelBubble
Wenn ein Event-Handler die Weitergabe eines Events an umgebende Objekte verhindern soll, muss er diese Eigenschaft auf true setzen.
866 | Referenz für clientseitiges JavaScript
491-0.book Seite 867 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Event integer clientX, clientY
Die Koordinaten relativ zur Webbrowser-Seite, bei der das Event auftrat. boolean ctrlKey
Gibt an, ob beim Eintreten des Events die Strg-Taste gedrückt war. Element fromElement Bei mouseover- und mouseout-Events bezieht sich fromElement auf das Objekt, von dem sich
der Mauszeiger wegbewegt. integer keyCode
Für Tastendruck-Events gibt diese Eigenschaft den Unicode-Zeichencode an, den die gedrückte Taste generiert. Für keydown- und keyup-Events gibt sie den virtuellen Tastencode der gedrückten Taste an. Virtuelle Tastencodes können vom benutzten Tastaturlayout abhängen. integer offsetX, offsetY
Die Koordinaten, bei denen das Event im Koordinatensystem seines Quellelements auftrat (siehe srcElement). boolean returnValue
integer screenX, screenY
Diese Eigenschaften geben relativ zum Bildschirm die Koordinaten an, bei denen das Event auftrat. boolean shiftKey
Gibt an, ob beim Eintreten des Events die Umschalt-Taste gedrückt war. Object srcElement
Eine Referenz auf das Window-, Document- oder Element-Objekt, das das Event generierte. Element toElement Bei mouseover- und mouseout-Events bezieht sich toElement auf das Objekt, zu dem sich der
Mauszeiger bewegt. String type
Der Typ des Events. Ihr Wert ist der Name des Event-Handlers ohne das Präfix »on«. Wenn also der Event-Handler onclick() aufgerufen wird, dann ist die type-Eigenschaft des Event-Objekts »click«. integer x, y
Gibt die X- und Y-Koordinaten an, an denen das Event relativ zum Dokument stattfand, oder relativ zum innersten umgebenden Element, das mit CSS dynamisch positioniert wurde.
Referenz für clientseitiges JavaScript |
867
Referenz für clientseitiges JavaScript
Wenn diese Eigenschaft gesetzt ist, hat ihr Wert Vorrang vor dem tatsächlich von einem Event-Handler zurückgegebenen Wert. Wenn Sie diese Eigenschaft auf false setzen, wird die Standardaktion des Quellelements, auf dem das Event auftrat, aufgehoben.
491-0.book Seite 868 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Event.initEvent( )
Standard-Methoden Die nachfolgenden Methoden werden von der DOM Level 2 Events-Spezifikation definiert. Im IE-Event-Modell hat das Event-Objekt keine Methoden: initEvent( )
Initialisiert die Eigenschaften eines neu erzeugten Event-Objekts. preventDefault( )
Teilt dem Webbrowser mit, dass er die mit diesem Event zusammenhängende Standardaktion (falls vorhanden) nicht ausführen soll. Wenn das Event von einer Art ist, die nicht aufgehoben werden kann, bleibt diese Methode wirkungslos. stopPropagation( )
Verhindert die weitere Ausbreitung des Events während der Capturing-, Ziel- und Bubbling-Phase der Event-Weitergabe. Nach dem Aufruf dieser Methode werden zwar, falls vorhanden, weitere Event-Handler für dasselbe Event auf demselben Knoten aufgerufen, aber an andere Knoten wird das Event nicht mehr weitergereicht.
Beschreibung Die Eigenschaften eines Event-Objekts liefern Einzelheiten über ein Event, wie z.B. das Element, auf dem das Event stattfand. Die Methoden eines Event-Objekts können die Ausbreitung des Events überwachen. Der DOM Level 2 Event-Standard definiert ein standardisiertes Event-Modell, das von allen modernen Browsern außer Internet Explorer implementiert wird. IE definiert sein eigenes, inkompatibles Modell. Dieser Referenzeintrag führt die Eigenschaften des standardisierten Event-Objekts und des IE-Event-Objekts auf. Weitere Einzelheiten bezüglich der beiden Event-Modelle finden Sie in Kapitel 17. Achten Sie besonders darauf, dass ein Event-Objekt im standardmäßigen Event-Modell an die Event-Handler-Funktion übergeben wird, ein Event-Objekt im IE-Event-Modell aber in der event-Eigenschaft des Window-Objekts gespeichert wird. Im standardisierten Event-Modell definieren verschiedene Subinterfaces von Event zusätzliche Eigenschaften, die Einzelheiten zu speziellen Event-Typen enthalten. Im IE-Event-Modell gibt es nur einen Typ von Event-Objekt. Er wird für alle Event-Typen verwendet.
Siehe auch KeyEvent, MouseEvent, UIEvent; Kapitel 17
Event.initEvent( ) Initialisiert die Eigenschaften eines neuen Events
491-0.book Seite 869 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Event.preventDefault( )
Argumente eventTypArg
Der Typ des Events. Er kann einer der vordefinierten Typen wie z.B. »load« oder »submit« oder auch ein selbstdefinierter Typ Ihrer Wahl sein. Mit »DOM« beginnende Namen sind allerdings reserviert. kannAufsteigenArg
Gibt an, ob das Event aufsteigen wird. abbrechbarArg
Gibt an, ob das Event mit preventDefault() aufgehoben werden kann.
Beschreibung Diese Methode initialisiert jeweils die Eigenschaften type, bubbles und cancelable bei einem synthetischen, mit Document.createEvent() erzeugten Event-Objekt. Bei neu erstellten EventObjekten muss diese Methode aufgerufen werden, bevor sie mit der dispatchEvent( )-Methode des Document- oder Element-Objekts übermittelt werden. Referenz für clientseitiges JavaScript
Siehe auch Document.createEvent( ), MouseEvent.initMouseEvent( ), UIEvent.initUIEvent( )
Event.preventDefault( )
DOM Level 2 Events
Hebt die Standardaktion eines Events auf
Überblick void preventDefault( );
Beschreibung Diese Methode teilt dem Webbrowser mit, dass er eine eventuell vorhandene Standardaktion für dieses Event nicht ausführen darf. Wenn z.B. die type-Eigenschaft »submit« ist, kann jeder Event-Handler, der während einer Event-Ausbreitungsphase aufgerufen wird, das Abschicken des Formulars verhindern, indem er diese Methode aufruft. Wenn die cancelable-Eigenschaft eines Event-Objekts false ist, ist entweder gar keine Standardaktion vorhanden, oder es gibt eine Standardaktion, die sich nicht verhindern lässt. In beiden Fällen hat der Aufruf der Methode keinen Effekt.
Event.stopPropagation( )
DOM Level 2 Events
Reicht ein Event nicht mehr weiter
Überblick void stopPropagation( );
Referenz für clientseitiges JavaScript |
869
491-0.book Seite 870 Mittwoch, 4. April 2007 9:55 09
e-bol.net
ExternalInterface
Beschreibung Diese Methode unterbindet die Weiterverbreitung eines Events und verhindert, dass es an andere Document-Knoten übermittelt wird. Sie kann in jeder Ausbreitungsphase aufgerufen werden. Sie verhindert zwar nicht den Aufruf anderer Event-Handler auf demselben Document-Knoten, aber sie unterbindet, dass das Event an andere Knoten weitergeleitet wird.
ExternalInterface
ActionScript-Objekt in Flash 8
Ein bidirektionales Interface zu Flash
Statische Eigenschaften available
Gibt an, ob Flash mit JavaScript kommunizieren kann. Das Ergebnis ist false, wenn die Sicherheitseinstellungen für den Browser die Kommunikation unterbinden.
Statische Funktionen addCallback( )
Exportiert eine ActionScript-Methode, damit sie von JavaScript aufgerufen werden kann. call( )
Ruft eine JavaScript-Funktion aus ActionScript heraus auf.
Beschreibung ExternalInterface ist ein ActionScript-Objekt, das vom Adobe Flash-Plug-in ab Version 8 definiert wird. Es definiert zwei statische Funktionen, die der ActionScript-Code in Flash-Movies verwenden kann. Diese Funktion ermöglichen die Kommunikation zwischen JavaScript-Code in einem Webbrowser und ActionScript-Code in einem Flash-Movie.
Siehe auch FlashPlayer; Kapitel 23
ExternalInterface.addCallback( ) Exponiert eine ActionScript-Methode zur Ausführung von JavaScript aus
Überblick boolean ExternalInterface.addCallback(String name, Object instanz, Function func)
870 | Referenz für clientseitiges JavaScript
ActionScript-Funktion in Flash 8
491-0.book Seite 871 Mittwoch, 4. April 2007 9:55 09
e-bol.net
ExternalInterface.call( )
Argumente name
Der Name der zu definierenden JavaScript-Funktion. Wird die JavaScript-Funktion mit diesem Namen aufgerufen, ruft der Flash-Player die ActionScript-Funktion func als eine Methode des instance-Objekts auf. instanz
Das ActionScript-Objekt, auf dem func aufgerufen werden soll, oder null. Dieses Argument wird zum Wert des this-Schlüsselworts, wenn func aufgerufen wird. func
Die ActionScript-Funktion, die aufgerufen wird, wenn die JavaScript-Funktion mit dem Namen name aufgerufen wird. Rückgabewert true bei Erfolg, false bei einem Fehlschlag.
Beschreibung
Die Argumente der JavaScript-Funktion werden konvertiert und an func übergeben. Der Rückgabewert von func wird konvertiert und wird zum Rückgabewert der JavaScript-Funktion. Als Argumente und Rückgabewerte sind elementare Zahlen, Strings und Boolesche Werte zulässig sowie Objekte und Arrays, die elementare Werte enthalten. Ein clientseitiges JavaScriptObjekt, wie z.B. ein Window oder Document, kann allerdings nicht an eine ActionScriptFunktion übergeben werden. Außerdem kann kein Flash-spezifisches ActionScript-Objekt, wie z.B. ein MovieClip, an JavaScript zurückgegeben werden.
Siehe auch FlashPlayer; Kapitel 23
ExternalInterface.call( )
ActionScript-Funktion in Flash 8
Ruft eine JavaScript-Funktion aus ActionScript heraus auf
Diese statische Funktion wird vom ActionScript-Code in Flash-Movies verwendet, damit JavaScript-Code in einem Webbrowser ActionScript-Code aufrufen kann. Beim Aufruf von addCallback( ) definiert sie eine Toplevel-JavaScript-Funktion mit dem Namen name. Wird diese Funktion aufgerufen, wird die ActionScript-Funktion func als eine Methode des ActionScriptObjekts instance aufgerufen.
491-0.book Seite 872 Mittwoch, 4. April 2007 9:55 09
e-bol.net
FileUpload
Argumente name
Der Name der aufzurufenden JavaScript-Funktion. args...
Keine, ein oder mehrere Argumente, die konvertiert und an die JavaScript-Funktion übergeben werden sollen. Rückgabewert Der Rückgabewert der JavaScript-Funktion, zu einem ActionScript-Wert konvertiert.
Beschreibung Diese statische Funktion wird von ActionScript-Code in einem Flash-Movie verwendet, um eine JavaScript-Funktion aufzurufen, die in dem Webbrowser definiert ist, in dem das FlashMovie eingebettet ist. Erläuterungen zur Konvertierung von Funktionsargumenten und Rückgabewerten zwischen ActionScript und JavaScript finden Sie unter ExternalInterface. addCallback( ).
FileUpload Siehe Input
FlashPlayer
Flash 2.0
Plug-in für Flash-Movies
Methoden GetVariable( )
Gibt den Wert einer Variablen zurück, die von einem Flash-Movie definiert wird. GotoFrame( )
Springt zur angegebenen Frame-Nummer im Movie. IsPlaying( )
Überprüft, ob das Movie läuft. LoadMovie( )
Lädt ein Hilfs-Flash-Movie und zeigt es an einem angegebenen Layer oder Level des momentanen Movies an. Pan( )
Verschiebt den Viewport des Movies. PercentLoaded( )
Gibt an, wie weit der Movie-Ladevorgang fortgeschritten ist. Play( )
Beginnt mit dem Abspielen des Movies. Rewind( )
Spult das Movie auf sein erstes Frame zurück.
872 | Referenz für clientseitiges JavaScript
491-0.book Seite 873 Mittwoch, 4. April 2007 9:55 09
e-bol.net
FlashPlayer.GetVariable( ) SetVariable( )
Setzt eine von einem Flash-Movie definierte Variable. SetZoomRect( )
Setzt den Bereich des Movies, der vom Flash-Player angezeigt wird. StopPlay( )
Hält das Movie an. TotalFrames( )
Gibt die Länge des Movies als Anzahl der Frames zurück. Zoom( )
Ändert die Größe des Movie-Viewports.
Beschreibung
Steht Ihnen ein FlashPlayer-Objekt zur Verfügung, können Sie die verschiedenen von ihm definierten JavaScript-Methoden verwenden, um die Wiedergabe des Movies zu steuern und um mit ihm durch das Setzen und Abfragen von Variablen in Interaktion zu treten. Beachten Sie, dass alle FlashPlayer-Methoden mit einem Großbuchstaben beginnen, was bei JavaScript auf der Clientseite keine geläufige Namenskonvention ist.
Siehe auch Kapitel 23
FlashPlayer.GetVariable( )
Flash 4
Gibt einen in einem Flash-Movie definierten Wert zurück
Der Name der im Flash-Movie definierten Variablen. Rückgabewert Der Wert der angegebenen Variablen als String, oder null, wenn keine solche Variable vorhanden ist.
Referenz für clientseitiges JavaScript |
873
Referenz für clientseitiges JavaScript
Ein FlashPlayer-Objekt repräsentiert ein in einer Webseite eingebettetes Flash-Movie und die Instanz des Flash-Plug-ins, das diesen Film abspielt. Sie können auf das FlashPlayer-Objekt mit Document.getElementById( ) zugreifen. Damit können Sie beispielsweise das - oder -Tag erhalten, das den Film in die Webseite einbettet.
491-0.book Seite 874 Mittwoch, 4. April 2007 9:55 09
e-bol.net
FlashPlayer.GotoFrame( )
FlashPlayer.GotoFrame( )
Flash 2
Springt zum angegebenen Frame eines Movies
Überblick void GotoFrame(integer frameNummer)
Argumente frameNummer
Die FrameNummer, zu der gesprungen werden soll.
Beschreibung Diese Funktion springt zum angegebenen Frame des Films – oder zum letzten verfügbaren Frame, wenn das angegebene Frame noch nicht geladen wurde. Um dieses unbestimmbare Verhalten zu umgehen, können Sie mit PercentLoaded( ) feststellen, wie weit der Film bereits geladen wurde.
FlashPlayer.IsPlaying( )
Flash 2
Überprüft, ob ein Movie läuft
Überblick boolean IsPlaying( )
Rückgabewert true, wenn der Film abgespielt wird, andernfalls false.
Das horizontale und vertikale Ausmaß, um das verschoben werden soll. Dieses Argument legt fest, wie die Werte dx und dy interpretiert werden sollen. Ist dieses Argument 0, werden die anderen Argumente als Pixel interpretiert. Ist das Argument 1, werden die anderen als Prozentsätze angesehen.
Beschreibung Der Flash-Player definiert einen Viewport, durch den Flash-Movies sichtbar sind. In der Regel stimmt die Größe des Viewports mit der Größe des Movies überein. Das ist jedoch nicht der Fall, wenn SetZoomRect( ) oder Zoom( ) aufgerufen wurden: Diese Methoden können den Viewport so verändern, dass nur ein Teil des Movies bis zum Bildschirm durchkommt. Zeigt der Viewport nur einen Teil des Films, verschiebt die Methode Pan( ) den Viewport, wodurch ein anderer Filmteil sichtbar wird. Das Bild lässt sich mit dieser Methode jedoch nicht über die Filmkanten hinaus verschieben.
Siehe auch FlashPlayer.SetZoomRect( ), FlashPlayer.Zoom( )
FlashPlayer.PercentLoaded( )
Flash 2
Zeigt an, wie viel des Movies bereits geladen wurde
Überblick integer PercentLoaded( )
Rückgabewert Ein ganze Zahl zwischen 0 und 100, die den ungefähren Prozentsatz des Movies angibt, der bereits in den Player geladen wurde.
Referenz für clientseitiges JavaScript |
875
Referenz für clientseitiges JavaScript
mode
491-0.book Seite 876 Mittwoch, 4. April 2007 9:55 09
e-bol.net
FlashPlayer.Play( )
FlashPlayer.Play( )
Flash 2
Spielt ein Movie ab
Überblick void Play( )
Beschreibung Beginnt, das Movie abzuspielen.
FlashPlayer.Rewind( )
Flash 2
Spult das Movie auf sein erstes Frame zurück
Überblick void Rewind( )
Beschreibung Diese Methode spult das Movie auf sein erstes Frame zurück.
FlashPlayer.SetVariable( )
Flash 4
Setzt eine von einem Flash-Movie definierte Variable
Die Koordinaten der linken oberen Ecke des Viewports, angegeben in Twips. rechts, unten
Die Koordinaten der rechten unteren Ecke des Viewports, angegeben in Twips.
Beschreibung
Siehe auch FlashPlayer.Pan( ), FlashPlayer.Zoom( )
FlashPlayer.StopPlay( )
Flash 2
Hält das Movie an
Überblick void StopPlay( )
Beschreibung Hält das Movie an.
FlashPlayer.TotalFrames( )
Flash 2
Gibt die Länge des Movies zurück, gemessen in Frames
Überblick integer TotalFrames( )
Beschreibung Diese Methode gibt die Länge des Movies zurück, gemessen in Frames.
Referenz für clientseitiges JavaScript |
877
Referenz für clientseitiges JavaScript
Diese Methode definiert den Viewport des Movies, d.h., sie legt ein Subrechteck des Movies fest, das im Flash-Player erscheinen soll. Flash-Movies werden in einer als Twip bezeichneten Einheit gemessen. Ein Punkt besteht aus 20 Twips und ein Inch aus 1440 Twips.
491-0.book Seite 878 Mittwoch, 4. April 2007 9:55 09
e-bol.net
FlashPlayer.Zoom( )
FlashPlayer.Zoom( )
Flash 2
Heranzoomen oder wegzoomen
Überblick void Zoom(integer prozent)
Argumente prozent
Der Prozentsatz, um den der Viewport skaliert werden soll, oder 0, um den Viewport auf seine volle Größe zurückzusetzen.
Beschreibung Diese Methode skaliert den Viewport um einen festgelegten Prozentsatz. Argumente zwischen 1 und 99 verkleinern die Größe des Viewports, wodurch Objekte im Movie größer erscheinen. Argumente über 100 vergrößern den Viewport (aber nicht über die Größe des Movies hinaus), wodurch Objekte im Movie kleiner erscheinen. Ein Spezialfall ist ein Argument von 0, das den Viewport auf seine volle Größe zurücksetzt, wodurch das gesamte Movie sichtbar ist.
Form
DOM Level 2 HTML
Ein -Element in einem HTML-Dokument
Node ➝ Element ➝ HTMLElement ➝ Form
Eigenschaften readonly HTMLCollection elements
Ein Array (HTMLCollection) mit allen Formularelementen. Siehe Form.elements[]. readonly long length
Die Anzahl der Formularelemente im Formular. Es ist derselbe Wert wie elements.length. Neben diesen Eigenschaften definiert Form auch die Eigenschaften in der folgenden Tabelle, die direkt HTML-Attributen entsprechen. Eigenschaft
Attribut
Beschreibung
String acceptCharset
acceptcharset
Zeichensätze, die der Server akzeptieren kann
String action
action
URL des Formular-Handlers
String enctype
enctype
Codierung des Formulars
String method
method
HTTP-Methode zum Übermitteln des Formulars
String name
name
Name des Formulars
String target
target
Frame- oder Fenstername für die Ergebnisse der Formularübermittlung
Methoden reset()
Setzt alle Formularelemente auf ihre Standardwerte zurück.
878 | Referenz für clientseitiges JavaScript
491-0.book Seite 879 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Form submit()
Reicht das Formular bei einem Webserver ein.
Event-Handler onreset
Wird unmittelbar vor dem Zurücksetzen der Formularelemente aufgerufen. onsubmit
Wird unmittelbar vor dem Übermitteln des Formulars aufgerufen. Mit diesem EventHandler können Formulareinträge vor der Übermittlung auf ihre Gültigkeit geprüft werden.
HTML-Syntax Ein Form-Objekt wird mit dem Standard-HTML-Tag erzeugt. Das Formular enthält Eingabeelemente, die mit , , und anderen Tags erzeugt wurden: Referenz für clientseitiges JavaScript
// Hier kommen Formulartext und Eingabeelemente hin
Beschreibung Das Form-Objekt stellt ein -Element in einem HTML-Dokument dar. Die Eigenschaft elements ist eine HTMLCollection, mit der Sie auf einfache Art auf alle Elemente im Formular zugreifen können. Mit den Methoden submit( ) und reset( ) kann ein Formular programmgesteuert übertragen oder zurückgesetzt werden. Jedes Formular eines Dokuments erhält einen Eintrag im Array Document.forms[]. Auf Formulare mit Namen kann außerdem über die Eigenschaft formular_name ihres Dokuments zugegriffen werden, wobei formular_name der Name ist, der im -Tag durch das Attribut name angegeben wurde. Die Elemente eines Formulars (Buttons, Eingabefelder, Checkboxen usw.) werden im Array Form.elements[] gesammelt. Benannte Elemente können, wie schon benannte Formulare, außerdem direkt über den Namen angesprochen werden. Der Name des Elements wird einfach als Name einer Eigenschaft des Form-Objekts verwendet. Somit könnte man beispielsweise auf ein Input-Element mit dem Namen telefon_nr in einem Formular namens fragebogen mit folgendem JavaScript-Ausdruck zugreifen: document.fragebogen.telefon_nr
Referenz für clientseitiges JavaScript |
879
491-0.book Seite 880 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Form.elements[]
Siehe auch Input, Select, Textarea; Kapitel 18
Form.elements[]
DOM Level 2 HTML
Die Eingabeelemente eines Formulars
Überblick readonly HTMLCollection elements
Beschreibung elements[] ist eine Array-ähnliche HTMLCollection von Formularelementen (wie z.B. Input-,
Select- und Textarea-Objekten), die in einem HTML-Formular vorkommen. Die Elemente des Arrays sind in der gleichen Reihenfolge angeordnet wie im HTML-Quelltext für das Formular. Jedes Element hat eine Eigenschaft type, deren String-Wert den Typ des Elements angibt.
Verwendung Wenn einem Element im Array elements[] durch das Attribut name="name" in seinem HTML-Tag ein Name gegeben wurde, dann erhält form eine Eigenschaft dieses Namens, die auf das Element verweist. Dadurch ist es möglich, namentlich auf Eingabeelemente zuzugreifen, anstatt sie über ihren Index ansprechen zu müssen: form.name
Siehe auch Input, HTMLCollection, Select, Textarea
Form.onreset
DOM Level 0
Event-Handler, der zum Zurücksetzen des Formulars aufgerufen wird
Überblick Function onreset
Beschreibung Die Eigenschaft onreset eines Formularobjekts gibt die Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer im Formular auf Reset klickt. Dieser Handler wird nicht als Reaktion auf den Aufruf der Methode Form.reset( ) aufgerufen. Wenn der Handler onreset den Wert false zurückgibt, werden die Formularelemente nicht zurückgesetzt. Eine Alternative zur Registrierung eines Event-Handlers finden Sie unter Element.addEventListener( ).
Siehe auch Element.addEventListener( ), Form.onsubmit, Form.reset( ); Kapitel 17
880 | Referenz für clientseitiges JavaScript
491-0.book Seite 881 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Form.onsubmit
Form.onsubmit
DOM Level 0
Der Event-Handler, der beim Zurücksetzen eines Formulars aufgerufen wird
Überblick Function onsubmit
Beschreibung Die Eigenschaft onsubmit eines Form-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer auf den Submit-Button eines Formulars klickt. Beachten Sie, dass dieser Event-Handler bei einem Aufruf von Form.submit() nicht aufgerufen wird. Wenn der Handler onsubmit den Wert false zurückgibt, wird das Formular nicht übermittelt. Gibt der Handler einen anderen Wert oder gar nichts zurück, so wird das Formular normal übermittelt. Da der Handler onsubmit auch die Formularübermittlung unterbinden kann, eignet er sich ideal dazu, die Formulardaten auf ihre Gültigkeit hin zu prüfen.
Siehe auch Element.addEventListener( ), Form.onreset, Form.submit( ); Kapitel 17
Form.reset( )
DOM Level 2 HTML
Setzt die Elemente eines Formulars auf ihre Standardwerte zurück
Überblick void reset( );
Beschreibung Diese Methode setzt jedes Element eines Formulars auf seinen Standardwert zurück. Ein Aufruf dieser Methode wirkt sich ebenso aus wie das Anklicken des Reset-Buttons durch einen Benutzer, nur dass der onreset-Event-Handler des Formulars nicht aufgerufen wird.
Siehe auch Form.onreset, Form.submit( )
Form.submit( )
DOM Level 2 HTML
Überträgt Formulardaten an einen Webserver
Überblick void submit( );
Referenz für clientseitiges JavaScript |
881
Referenz für clientseitiges JavaScript
Eine andere Möglichkeit, den Event-Handler zu registrieren, finden Sie unter Element. addEventListener( ).
491-0.book Seite 882 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Frame
Beschreibung Diese Methode übermittelt die Werte der Formularelemente an den Server, der in der Eigenschaft action des Formulars angegeben ist. Sie übermittelt ein Formular in derselben Weise, wie wenn ein Benutzer auf einen Submit-Button klickt. Nur wird hier nicht der onsubmit-EventHandler des Formulars ausgelöst.
Siehe auch Form.onsubmit, Form.reset( )
Frame
DOM Level 2 HTML
Ein in einem HTML-Dokument
Node ➝ Element ➝ HTMLElement ➝ Frame
Eigenschaften Wie aus der Beschreibung zu entnehmenist, kann auf HTML-Frames als Frame-Objekt oder als Window-Objekt zugegriffen werden. Wird auf sie als Frame-Objekt zugegriffen, erben sie Eigenschaften vom HTMLElement und definieren diese zusätzlichen Eigenschaften: Document contentDocument
Das Dokument, das den Frame-Inhalt enthält. String src
Die URL, von der der Frame-Inhalt geladen wurde. Wird diese Eigenschaft gesetzt, lädt das Frame ein neues Dokument. Diese Eigenschaft bildet einfach das Attribut src des HTML-Tags ab: Im Gegensatz zu Window.location ist diese Eigenschaft kein Location-Objekt. Neben diesen Eigenschaften definiert das Frame-Objekt auch die nachfolgenden Eigenschaften, die direkt HTML-Attributen entsprechen. Eigenschaft
Attribut
Beschreibung
String frameBorder
frameborder
Auf »0« gesetzt für rahmenlose Frames
String longDesc
longdesc
Die URL einer Frame-Beschreibung
String marginHeight
marginheight
Oberer und unterer Frame-Rand in Pixeln
String marginWidth
marginwidth
Linker und rechter Frame-Rand in Pixeln
String name
name
Der Frame-Name, für DOM Level 0-Lookup und Formular- und Linkziele
boolean noResize
noresize
Wenn true, kann der Benutzer die Frame-Größe nicht verändern
String scrolling
scrolling
Frame-Scrolleinstellungen: »auto«, »yes« oder »no«
Beschreibung Frames haben zwei »Persönlichkeiten« und können in clientseitigem JavaScript sowohl als Window- als auch als Frame-Objekte dargestellt werden. Im herkömmlichen Level 0 DOM
882 | Referenz für clientseitiges JavaScript
491-0.book Seite 883 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Hidden
wird jedes als unabhängiges Fenster behandelt und von einem durch Namen referenzierten Window-Objekt dargestellt – oder als Element des Arrays frames[] des Fensters, das das Frame enthält: // Hole das Frame als Window-Objekt var win1 = top.frames[0]; // Das Array frames[] nach Nummer indiziert var win2 = top.frames['f1']; // Das Array frames[] nach Namen indiziert var win3 = top.f1; // Hole die Frames als Eigenschaft ihres übergeordneten Fra mes
Wenn Frames auf diese Weise nachgeschlagen werden, ist das zurückgegebene Objekt ein Window und die im vorherigen Abschnitt aufgeführten Eigenschaften stehen nicht zur Verfügung. Verwenden Sie stattdessen Window-Eigenschaften, wie z.B. document, um auf das Dokument des Frames zuzugreifen, und location, um auf die URL dieses Dokuments zuzugreifen. Im Level 2 DOM kann auf die Elemente von über die ID oder den Tag-Namen genauso zugegriffen werden wie auf jedes andere Dokumentelement: // über ID // über Tag-Name
Wird auf Frames über DOM-Methoden wie diese zugegriffen, ist das Ergebnis kein WindowObjekt, sondern ein Frame-Objekt, und die oben aufgeführten Eigenschaften können verwendet werden. Verwenden Sie contentDocument, um auf das Dokument des Frames zuzugreifen, und die Eigenschaft src, um die URL dieses Dokuments abzufragen oder um das Frame zum Laden eines neuen Dokuments zu veranlassen. Um das Window-Objekt eines Frame-Objekts f zu erhalten, verwenden Sie f.contentDocument.defaultView. Die Elemente von sind denen von sehr ähnlich. Vergleichen Sie dazu den Referenzeintrag IFrame. Beachten Sie, dass sich die Same Origin Policy (siehe Abschnitt 13.8.2) auf Dokumente mit mehreren Frames bezieht. Browser lassen den Zugriff auf Frame-Inhalte nicht zu, die aus einer anderen Quelle stammen als aus der, aus der das Skript stammt. Das ist unabhängig davon, ob das Frame von einem Window- oder einem Frame-Objekt dargestellt wird.
Siehe auch IFrame, Window; Kapitel 14
Hidden Siehe Input
Referenz für clientseitiges JavaScript |
883
Referenz für clientseitiges JavaScript
// Hole das Frame als Frame-Objekt var frame1 = top.document.getElementById('f1'); var frame2 = top.document.getElementsByTagName('frame')[1];
491-0.book Seite 884 Mittwoch, 4. April 2007 9:55 09
e-bol.net
History
History Die URL-History des Browsers
JavaScript 1.0 Object ➝ History
Überblick window.history history
Eigenschaften length
Diese numerische Eigenschaft gibt an, wie viele URLs in der History-Liste des Browsers stehen. Da es keine Möglichkeit gibt, den Index zu ermitteln, den das gerade angezeigte Dokument in dieser Liste hat, ist es auch nicht sonderlich hilfreich, die Länge dieser Liste zu kennen.
Methoden back( )
Geht zu einer zuvor besuchten URL zurück. forward( )
Geht zu einer zuvor besuchten URL weiter. go( )
Geht zu einer zuvor besuchten URL.
Beschreibung Das History-Objekt wurde ursprünglich entwickelt, um die Browsing-History eines Fensters darzustellen. Aus Datenschutzgründen erlaubt das History-Objekt jedoch keinen Skript-Zugriff auf die tatsächlich besuchten URLs mehr. Die einzigen noch bestehenden Funktionalitäten sind die Methoden back( ), forward( ) und go( ).
Beispiel Die folgende Codezeile führt dieselbe Aktion aus, wie wenn ein Benutzer auf den ZurückButton des Browsers klickt: history.back( );
Die folgende Codezeile führt dieselbe Aktion aus, als wenn ein Benutzer zweimal auf den Zurück-Button des Browsers klickt: history.go(-2);
Siehe auch Die Eigenschaft history des Window-Objekts, Location
884 | Referenz für clientseitiges JavaScript
491-0.book Seite 885 Mittwoch, 4. April 2007 9:55 09
e-bol.net
History.back( )
History.back( )
JavaScript 1.0
Geht zur vorigen URL zurück
Überblick history.back( )
Beschreibung back() lässt das Fenster oder den Frame, zu dem die History-Objekte gehören, diejenige URL
erneut besuchen (falls es eine gibt), die unmittelbar vor der jetzigen aufgesucht wurde. Ein Aufruf dieser Methode hat dieselbe Wirkung, wie wenn ein Benutzer auf den Zurück-Button des Browsers klickt. Sie ist auch äquivalent zu dem folgenden Ausdruck: history.go(-1);
History.forward( )
JavaScript 1.0 Referenz für clientseitiges JavaScript
Besucht die nächste URL
Überblick history.forward( )
Beschreibung forward() lässt das Fenster oder den Frame, zu dem die History-Objekte gehören, diejenige
URL erneut besuchen (falls es eine gibt), die unmittelbar nach der jetzigen aufgesucht wurde. Ein Aufruf dieser Methode hat dieselbe Wirkung, wie wenn ein Benutzer auf den VorwärtsButton des Browsers klickt. Sie ist auch äquivalent zu dem folgenden Ausdruck: history.go(1);
Wenn der Benutzer sich nicht mit dem Zurück-Button oder dem Gehe-Menü in der History rückwärts bewegt hat und JavaScript nicht die Methode History.back() oder History.go() aufgerufen hat, hat forward() keine Auswirkung, da der Browser bereits am Ende seiner URLListe steht und es keine URL gibt, zu der er noch weitergehen könnte.
Die relative Position der zu besuchenden URL in der History-Liste.
Referenz für clientseitiges JavaScript |
885
491-0.book Seite 886 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLCollection ziel_string
Die URL (oder das URL-Fragment), die besucht werden soll, wenn in der History-Liste eine passende URL vorhanden ist.
Beschreibung Die erste Form der Methode History.go() nimmt ein Integer-Argument entgegen und lässt den Browser diejenige URL erneut aufsuchen, die in der History-Liste des History-Objekts um die angegebene Anzahl Stellen weit entfernt ist. Positive Argumente lassen den Browser in der Liste vorwärts gehen, und negative Argumente lassen ihn rückwärts gehen. Also ist ein Aufruf von history.go(-1) äquivalent zu history.back() und hat dieselbe Wirkung wie das Anklicken eines Zurück-Buttons. history.go(3) besucht dieselbe URL, die auch nach dreimaligem Aufruf von history.forward() aufgesucht würde. Die zweite Arbeitsweise von History.go( ) nimmt ein String-Argument und veranlasst den Browser, die erste (d.h. die zuletzt besuchte) URL noch einmal zu besuchen, die den angegebenen String enthält. Diese Form der Methode ist nur schlecht definiert und kann unter verschiedenen Browsern unterschiedlich funktionieren. Zum Beispiel gibt die Dokumentation von Microsoft an, dass das das Argument genau mit der URL einer vorher angegebenen Seite übereinstimmen muss. Dagegen sagt die alte Dokumentation von Netscape (Netscape erfand das History-Objekt), dass das Argument ein Substring einer vorher besuchten URL sein kann.
HTMLCollection Array von HTML-Elementen, auf die nach Position oder Namen zugegriffen wird
DOM Level 2 HTML Object ➝ HTMLCollection
Eigenschaften readonly unsigned long length
Die Anzahl der Elemente in der Sammlung.
Methoden item( )
Gibt das Element an der angegebenen Position in der Sammlung zurück. Sie können die Position auch einfach in Array-Klammern angeben, anstatt diese Methode explizit aufzurufen. namedItem( )
Gibt das Element der Sammlung zurück, dessen id- oder name-Attribut den angegebenen Wert hat, oder null, wenn kein solches Element vorhanden ist. Sie können den Elementnamen auch in Array-Klammern angeben, anstatt diese Methode explizit aufzurufen.
Beschreibung Eine HTMLCollection ist eine Sammlung von HTML-Elementen mit Methoden, mit denen Sie auf ein Element über seine Position im Dokument oder seine Attribute id oder name zugreifen können. In JavaScript verhalten sich HTMLCollection-Objekte wie schreibgeschützte Arrays, und Sie können auch die JavaScript-Notation mit den eckigen Klammern einsetzen, um eine
886 | Referenz für clientseitiges JavaScript
491-0.book Seite 887 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLCollection.item( )
HTMLCollection nach Zahl oder Namen zu indizieren, anstatt die Methode item() oder namedItem() aufzurufen. Einige Eigenschaften des HTMLDocument-Objekts sind HTMLCollection-Objekte, mit denen Sie bequem auf Elemente wie z.B. Formulare, Bilder oder Links im Dokument zugreifen können. Die Eigenschaften Form.elements und Select.options sind HTMLCollection-Objekte. Das HTMLCollection-Objekt macht es außerdem leicht, die Zeilen einer Tabelle und die Zellen einer TableRow zu durchlaufen. HTMLCollection-Objekte sind schreibgeschützt: Sie können ihnen keine neuen Elemente zuweisen, auch nicht, wenn Sie die JavaScript-Array-Notation verwenden. Sie sind »live«: Wenn sich das zugrunde liegende Dokument ändert, werden diese Änderungen quer durch sämtliche HTMLCollection-Objekte sofort sichtbar. HTMLCollection-Objekte ähneln den NodeList-Objekten sehr, können jedoch sowohl anhand des Namens als auch anhand einer Nummer indiziert werden.
Beispiel c = document.forms; firstform = c[0]; lastform = c[c.length-1]; address = c["address"]; address = c.address;
// // // // //
Das ist eine HTMLCollection von Formularelementen Kann wie ein numerisches Array verwendet werden Die Eigenschaft length gibt die Anzahl der Elemente an Kann wie ein assoziatives Array verwendet werden JavaScript erlaubt auch diese Notation
Siehe auch HTMLDocument, NodeList
HTMLCollection.item( )
DOM Level 2 HTML
Holt ein Element anhand seiner Position
Überblick Node item(unsigned long index);
Argumente index
Die Position des Rückgabeelements. Die Elemente erscheinen in einer HTMLCollection in derselben Reihenfolge wie im Dokumentquelltext. Rückgabewert Das Element am angegebenen Index oder null, wenn index kleiner als null oder größer oder gleich der length-Eigenschaft ist.
Beschreibung Die Methode item() gibt ein nummeriertes Element einer HTMLCollection zurück. In JavaScript ist es einfacher, die HTMLCollection als Array zu behandeln und mit der ArrayNotation zu indizieren.
Referenz für clientseitiges JavaScript |
887
Referenz für clientseitiges JavaScript
var var var var var
491-0.book Seite 888 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLCollection.namedItem( )
Beispiel var c = document.images; var img0 = c.item(0); var img1 = c[1];
// Das ist eine HTMLCollection // Die Methode item( ) können Sie so verwenden // aber diese Notation ist einfacher und gebräuchlicher
Siehe auch NodeList.item( )
HTMLCollection.namedItem( )
DOM Level 2 HTML
Holt ein Element anhand seines Namens
Überblick Node namedItem(String name);
Argumente name
Der Name des zurückzugebenden Elements. Rückgabewert Das Element in der Sammlung, das den angegebenen Wert für sein id- oder name-Attribut hat, oder null, wenn in der HTMLCollection kein Element mit diesem Namen vorhanden ist.
Beschreibung Diese Methode sucht und liefert ein Element aus der HTMLCollection, das den angegebenen Namen hat. Wenn ein Element ein id-Attribut hat, dessen Wert der angegebene Name ist, so wird dieses Element zurückgegeben. Wenn kein solches Element gefunden wird, so wird ein Element zurückgegeben, dessen name-Attribut den angegebenen Wert hat. Existiert überhaupt kein derartiges Element, so gibt namedItem() den Wert null zurück. Beachten Sie, dass jedem HTML-Element ein id-Attribut zugewiesen werden kann, aber nur wenige – wie beispielsweise Formulare, Formularelemente, Bilder und Anker – auch ein Attribut name besitzen können. In JavaScript ist es einfacher, die HTMLCollection als assoziatives Array zu behandeln und name nach der Array-Notation in eckigen Klammern anzugeben.
Beispiel var forms = document.forms;
// Eine HTMLCollection, die aus Formularen // besteht var address = forms.namedItem("address"); // Sucht nach var payment = forms["payment"] // Einfachere Syntax: findet var login = forms.login; // Funktioniert auch: findet
888 | Referenz für clientseitiges JavaScript
491-0.book Seite 889 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLDocument
HTMLDocument Die Wurzel eines HTML-Dokumentbaums
DOM Level 0 Node ➝ Document ➝ HTMLDocument
Eigenschaften Element[] all [IE4]
Diese nicht im Standard enthaltene Eigenschaft ist ein Array-ähnliches Objekt, das auf alle HTMLElemente im Dokument Zugriff gibt. Das Array all[] wurde zum ersten Mal in IE4 verwendet. Obwohl es durch Methoden wie z.B. Document.getElementById( ) und Document.getElementsByTagName( ) abgelöst wurde, wird es immer noch in Code-Anwendungen verwendet. Eine genaue Beschreibung finden Sie in HTMLDocument.all[]. readonly HTMLCollection anchors
Ein Array (HTMLCollection) aller Anchor-Objekte im Dokument. readonly HTMLCollection applets
Ein Array (HTMLCollection) aller Applet-Objekte in einem Dokument. HTMLElement body
String cookie
Hiermit können Cookies für dieses Dokument abgefragt und gesetzt werden. Einzelheiten entnehmen Sie bitte dem Kapitel HTMLDocument.cookie. String domain
Der Domain-Name des Servers, von dem das Dokument geladen wurde, oder null, wenn keiner vorhanden ist. Diese Eigenschaft kann auch verwendet werden, um unter bestimmten Umständen das Sicherheitsprinzip zu lockern, dass Inhalte von derselben Quelle stammen müssen (Same Origin Policy). Einzelheiten entnehmen Sie bitte dem Eintrag HTMLDocument.domain. readonly HTMLCollection forms
Ein Array (HTMLCollection) aller Form-Objekte im Dokument. readonly HTMLCollection images
Ein Array (HTMLCollection) von Image-Objekten im Dokument. Aus Gründen der Kompatibilität mit Level 0 DOM sind Bilder, die statt mit einem -Tag mit einem -Tag definiert werden, nicht in dieser Sammlung enthalten. readonly String lastModified
Gibt das Datum und die Uhrzeit der letzten Änderung im Dokument an. Dieser Wert stammt aus dem Last-Modified-HTTP-Header, der optional vom Webserver übermittelt wird. readonly HTMLCollection links
Ein Array (HTMLCollection) aller Link-Objekte im Dokument. readonly String referrer
Die URL des Dokuments, dessen Link auf dieses Dokument verwies, oder null, wenn nicht über einen Hyperlink auf dieses Dokument zugegriffen wurde. Mit dieser Eigenschaft kann JavaScript auf der Clientseite auf den HTTP-Header referer zugreifen. Achten
Referenz für clientseitiges JavaScript |
889
Referenz für clientseitiges JavaScript
Eine Eigenschaft. Sie bezieht sich auf das HTMLElement, das das -Tag dieses Elements darstellt. Bei Dokumenten, die Framesets definieren, bezieht sich diese Eigenschaft auf das am weitesten außen liegende -Tag.
491-0.book Seite 890 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLDocument
Sie dabei auf die unterschiedliche Schreibweise: Der HTTP-Header enthält den Buchstaben r dreimal, die JavaScript-Eigenschaft aber viermal. String title
Der Inhalt des -Tags für dieses Dokument. readonly String URL
Die URL des Dokuments. Dieser Wert ist oft der gleiche wie der der Eigenschaft location. href des Fensters, das das Dokument enthält. Wenn jedoch ein URL-Redirect stattfindet, enthält die Eigenschaft URL die tatsächliche URL des Dokuments und location.href enthält die angeforderte URL.
Methoden close( )
Schließt einen Dokument-Stream, der mit der open()-Methode geöffnet worden war, und veranlasst, dass jede gepufferte Ausgabe angezeigt wird. getElementsByName( )
Gibt ein Knoten-Array (eine NodeList) aller Dokumentelemente zurück, deren nameAttribut einen spezifizierten Wert hat. open( )
Öffnet einen Stream, in den neuer Dokumentinhalt geschrieben werden kann. Beachten Sie, dass diese Methode einen eventuell vorhandenen, aktuellen Dokumentinhalt löscht. write( )
Hängt einen HTML-Text-String an ein offenes Dokument an. writeln( )
Hängt einen HTML-Text-String, gefolgt von einem Newline-Zeichen, an ein offenes Dokument an.
Beschreibung Dieses Interface erweitert Document und definiert HTML-spezifische Eigenschaften und Methoden. Einige der Eigenschaften sind HTMLCollection-Objekte (im Grunde genommen schreibgeschützte Arrays, die über Nummern oder Namen indiziert werden), die Referenzen auf Anker, Formate, Links und andere wichtige über Skripten steuerbare Elemente des Dokuments enthalten. Diese Collection-Eigenschaften entstanden im Level 0 DOM. Sie wurden von Document.getElementsByTagName( ) abgelöst, werden aber allgemein weiterverwendet, da sie so praktisch sind. Die Methode write( ) ist erwähnenswert: Mit ihr kann ein Skript in ein dynamisch erstelltes Dokument eingefügt werden, während das Dokument geladen und geparst wird. Abschließend sollten Sie sich noch merken, dass HTMLDocument im Level 1 DOM eine sehr nützliche Methode namens getElementById() definierte. Im Level 2 DOM wurde diese Methode in das Document-Interface verlagert und wird nun von HTMLDocument nicht mehr definiert, sondern geerbt. Einzelheiten entnehmen Sie bitte dem Eintrag Document. getElementById( ).
Siehe auch Document, Document.getElementById( ), Document.getElementsByTagName( )
890 | Referenz für clientseitiges JavaScript
491-0.book Seite 891 Mittwoch, 4. April 2007 9:55 09
Beschreibung all[] ist ein vielseitiges Array-ähnliches Objekt, mit dem auf alle HTML-Elemente in einem Dokument zugegriffen werden kann. Das Array all[] wurde zum ersten Mal in IE 4 verwendet
und wurde von einigen anderen Browsern aufgegriffen. Es wurde von den standardisierten Methoden getElementById( ) und getElementsByTagName( ) des Document-Interfaces abgelöst und von der standardisierten Methode getElementsByName( ) des HTMLDocument-Interface. Trotzdem wird das Array all[] in existierendem Code weiterverwendet.
Wenn Sie der Methode all.tags( ) einen Tag-Namen übergeben, gibt sie ein Array von HTMLElementen des angegebenen Typs zurück.
Siehe auch Document.getElementById( ), Document.getElementsByTagName( ), HTMLElement
HTMLDocument.close( )
DOM Level 0
Schließt ein offenes Dokument und zeigt es an
Überblick void close( );
Beschreibung Diese Methode schließt einen Dokument-Stream, der mit der open()-Methode geöffnet worden ist, und veranlasst, dass die gepufferte Ausgabe angezeigt wird. Wenn Sie die Methode write( ) verwenden, um ein Dokument dynamisch auszugeben, müssen Sie daran denken, diese Methode zum Schluss aufzurufen, damit Ihr gesamter Dokumentinhalt angezeigt wird. Nach dem Aufruf von close( ) sollten Sie es vermeiden, write( ) noch einmal aufzurufen, da dadurch automatisch open( ) aufgerufen, das vorhandene Dokument gelöscht und ein neues angefangen wird.
Referenz für clientseitiges JavaScript |
891
Referenz für clientseitiges JavaScript
all[] enthält die Elemente in der Quelltextreihenfolge. Sie können sie direkt aus dem Array extrahieren, wenn Sie deren genaue numerische Position innerhalb des Arrays kennen. Üblicher ist es allerdings, Elemente aus dem Array all[] nach dem Wert ihres HTML-Attributs name oder id abzurufen. Wenn unter dem angegebenen Namen mehr als ein Element vorhanden ist und Sie diesen Namen als Index für das Array all[] verwenden, erhalten Sie ein Array der Elemente, die den betreffenden Namen gemeinsam haben.
491-0.book Seite 892 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLDocument.cookie
Siehe auch HTMLDocument.open( ), HTMLDocument.write( )
HTMLDocument.cookie
DOM Level 0
Die Cookies des Dokuments
Überblick String cookie
Beschreibung cookie ist eine String-Eigenschaft, die es ermöglicht, den oder die zu dem aktuellen Dokument
gehörenden Cookie(s) zu lesen, zu verändern, zu erzeugen oder zu löschen. Ein Cookie ist eine kleine, benannte Datenmenge, die vom Webbrowser gespeichert wird. Er dient dazu, Webbrowsern eine Art Gedächtnis zu geben, sodass sie die auf einer Seite gemachten Eingaben in einer anderen verwenden können. Cookies dienen auch dazu, Browser-Einstellungen bis zur nächsten Sitzung zu speichern. Cookie-Daten werden bei Bedarf automatisch zwischen Webbrowser und -server übertragen, sodass Skripten auf der Serverseite Cookie-Werte lesen und schreiben können. Clientseitiger JavaScript-Code kann durch die Eigenschaft cookie ebenfalls lesend und schreibend auf Cookies zugreifen. Die Eigenschaft HTMLDocument.cookie verhält sich nicht wie eine normale les- und schreibbare Eigenschaft. Sie können den Inhalt von HTMLDocument.cookie zwar lesen und schreiben, allerdings wird der ausgelesene Wert in der Regel nicht der gleiche wie der zuvor geschriebene sein. Einzelheiten über die Verwendung dieser besonders komplizierten Eigenschaft können Sie in Kapitel 19 nachlesen.
Verwendung Cookies sind für das gelegentliche Ablegen kleinerer Datenmengen gedacht. Sie sind nicht als Allzweck-Kommunikations- oder -Programmiermechanismus gedacht; setzen Sie Cookies daher sparsam ein. Beachten Sie, dass Webbrowser nicht mehr als 20 Cookie-Werte pro Webserver aufbewahren müssen, und sie brauchen auch keine Cookies mit name/wert-Paaren aufzubewahren, die länger als vier Kilobyte sind.
Siehe auch Kapitel 19
HTMLDocument.domain Die Sicherheits-Domain eines Dokuments
Überblick String domain
892 | Referenz für clientseitiges JavaScript
DOM Level 0
491-0.book Seite 893 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLDocument.getElementsByName( )
Beschreibung In Übereinstimmung mit dem HTML-Standard von DOM Level 2 ist die Eigenschaft domain lediglich ein schreibgeschützter String, der den Hostnamen des Webservers enthält, aus dem das Dokument geladen wurde. Diese Eigenschaft hat eine weitere wichtige Verwendung (obwohl diese Verwendung nicht standardisiert ist). Das Sicherheitsprinzip des »Same Origin«, also der gleichen Herkunft von Inhalten (im Abschnitt 13.8.2 beschrieben) hält ein Skript in einem Dokument davon ab, den Inhalt eines anderen Dokuments zu lesen (z.B. ein in einem angezeigtes Dokument), es sei denn, die beiden Dokumente haben den gleichen Ursprung (d.h., sie wurden vom gleichen Webserver abgerufen). Bei großen Websites, die mehrere Server verwenden, kann das zu Problemen führen. So kann vielleicht ein Skript, das auf dem Host www.oreilly.com läuft, den Inhalt von Dokumenten lesen, der auf search.oreilly.com läuft.
Siehe auch Abschnitt 13.8.2, »Die Same Origin Policy«
Der gewünschte Wert für das name-Attribut. Rückgabewert Ein schreibgeschütztes Array (technisch gesehen eine NodeList) von Element-Objekten, die ein Attribut name mit dem angegebenen Wert haben. Wenn keine solchen Elemente vorhanden sind, ist das zurückgegebene Array leer und hat die length 0.
Referenz für clientseitiges JavaScript |
893
Referenz für clientseitiges JavaScript
Die domain-Eigenschaft hilft, mit diesem Problem fertigzuwerden. Sie können diese Eigenschaft neu setzen, allerdings mit einer großen Einschränkung: Sie kann nur auf eine Domain gesetzt werden, deren Name ein Suffix von ihr ist. So könnte beispielsweise ein von search.oreilly.com geladenes Skript seine domain-Eigenschaft auf »oreilly.com« setzen. Wenn nun ein Skript von www.oreilly.com in einem anderen Fenster läuft und seine domain-Eigenschaft ebenfalls auf »oreilly.com« setzt, dann können diese beiden Skripte den Dokumentinhalt des jeweils anderen Skripts lesen, obwohl die beiden Skripte nicht von demselben Server stammen. Beachten Sie allerdings, dass ein Skript von search.oreilly.com seine domain nicht auf »search.oreilly« oder ».com« setzen kann.
491-0.book Seite 894 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLDocument.open( )
Beschreibung Diese Methode sucht in einem HTML-Dokumentenbaum Element-Knoten, deren nameAttribut den angegebenen Wert hat, und gibt eine NodeList (die Sie auch als schreibgeschütztes Array behandeln können) mit allen passenden Elementen zurück. Wenn keine passenden Elemente vorhanden sind, wird eine NodeList mit der length 0 zurückgegeben. Verwechseln Sie diese Methode nicht mit der Methode Document.getElementById(), die ein einzelnes Element anhand des eindeutigen Werts eines id-Attributs sucht, oder mit der Methode Document.getElementsByTagName(), die eine NodeList mit Elementen zurückgibt, die den angegebenen Tag-Namen haben.
Siehe auch Document.getElementById( ), Document.getElementsByTagName( )
HTMLDocument.open( )
DOM Level 0
Beginnt ein neues Dokument und löscht das aktuelle
Überblick void open( );
Beschreibung Diese Methode löscht das aktuelle HTML-Dokument und fängt ein neues an, in das mit den Methoden write() und writeln() geschrieben werden kann. Nachdem Sie mit open() ein neues Dokument begonnen und mit write() seinen Inhalt angegeben haben, dürfen Sie nicht vergessen, am Ende des Dokuments auch close() aufzurufen und zu veranlassen, dass der Inhalt angezeigt wird. Diese Methode sollte nicht von einem Skript oder Event-Handler aufgerufen werden, das oder der zu dem überschriebenen Dokument gehört, denn auch das Skript oder der Handler werden überschrieben.
Beispiel var w = window.open(""); // Öffne ein neues Fenster var d = w.document; // Hole sein HTMLDocument-Objekt d.open( ); // Öffne das Dokument zum Schreiben d.write("Hello world"); // Gib HTML an das Dokument aus d.close( ); // Beende das Dokument, und zeige es an
Siehe auch HTMLDocument.close( ), HTMLDocument.write( )
894 | Referenz für clientseitiges JavaScript
491-0.book Seite 895 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLDocument.write( )
HTMLDocument.write( )
DOM Level 0
Hängt HTML-Text an ein geöffnetes Dokument an
Überblick void write(String text);
Argumente text
Der HTML-Text, der an das Dokument angehängt werden soll.
Beschreibung
Die Methode Document.write() wird normalerweise auf zwei verschiedene Arten verwendet. Erstens, indem das aktuelle Dokument sie für sich selbst aufruft, nämlich innerhalb eines -Tags oder innerhalb einer Funktion, die während der Analyse des Dokuments noch ausgeführt wird. In diesem Fall schreibt write() seine HTML-Ausgabe so, als stünde sie wörtlich in der Datei, und zwar anstelle des Codes, der diese Methode aufgerufen hat. Zweitens können Sie Document.write( ) verwenden, um dynamisch neue Dokumente in anderen Fenstern, Frames oder IFrames als denen zu erzeugen, in denen das aufrufende Skript läuft. Ist das Zieldokument offen, fügt write( ) sie an dieses Dokument an. Ist das Dokument nicht offen, löscht write( ) das bestehende Dokument und öffnet ein neues (leeres) Dokument, an das sie ihre Argumente anhängt. Sobald ein Dokument geöffnet worden ist, kann Document.write() jede beliebig lange Ausgabe an das Ende des Dokuments anhängen. Wenn ein neues Dokument vollständig auf diese Weise erzeugt worden ist, muss das Dokument durch den Aufruf von Document.close() geschlossen werden. Beachten Sie, dass der Aufruf von close() immer erfolgen muss, der Aufruf von open() aber optional ist.1 Das Ergebnis des Aufrufs von Document.write( ) ist im Zieldokument unter Umständen nicht sofort sichtbar. Dies liegt daran, dass ein Webbrowser Text zwischenspeichern kann, um ihn später in größeren Blöcken zu parsen und anzuzeigen. Ein Aufruf von Document.close( ) ist die einzige Möglichkeit, um die Darstellung der gepufferten Ausgabe zu erzwingen und sie im Browserfenster anzuzeigen.
Siehe auch HTMLDocument.close( ), HTMLDocument.open( ) 1 Sie müssen Document.open() eigentlich nur dann verwenden, wenn Sie ein Dokument mit einem anderen MIMETyp als »text/html« öffnen möchten.
Referenz für clientseitiges JavaScript |
895
Referenz für clientseitiges JavaScript
Diese Methode fügt den angegebenen HTML-Text an das Dokument an. Entsprechend dem DOM-Standard nimmt diese Methode ein einzelnes String-Argument entgegen. In der Praxis wird der Methode write( ) allerdings oft eine beliebige Anzahl an Argumenten übergeben. Diese Argumente werden in Strings konvertiert und in der gleichen Reihenfolge an das Dokument angefügt.
491-0.book Seite 896 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLDocument.writeln( )
HTMLDocument.writeln( )
DOM Level 0
Hängt HTML-Text und ein Newline-Zeichen an ein offenes Dokument an
Überblick void writeln(String text);
Argumente text
Der HTML-Text, der an das Dokument angehängt werden soll.
Beschreibung Diese Methode ähnelt HTMLDocument.write(), nur dass sie hinter den anzufügenden Text noch ein Newline-Zeichen setzt. Das kann nützlich sein, wenn Sie z.B. den Inhalt eines -Tags schreiben.
Siehe auch HTMLDocument.write( )
HTMLElement Ein Element in einem HTML-Dokument
DOM Level 2 HTML Node ➝ Element ➝ HTMLElement
Eigenschaften Jedes Element eines HTML-Dokuments hat Eigenschaften, die den HTML-Attributen des Elements entsprechen. Nachfolgend sind die Eigenschaften aufgeführt, die von allen HTMLTags unterstützt werden. Weitere Eigenschaften, die sich lediglich auf bestimmte HTML-Tags beziehen, stehen in der ausführlichen Tabelle im nächsten Beschreibungsabschnitt. HTMLElement-Objekte erben einige nützliche standardisierte Eigenschaften von Node und Element und implementieren außerdem einige nicht standardisierte Eigenschaften, die hier beschrieben sind: String className
Der Wert des class-Attributs des Elements, das keinen, einen oder mehrere durch Leerzeichen getrennte CSS-Klassennamen angibt. Beachten Sie, dass diese Eigenschaft nicht »class« heißt, weil dieser Name in JavaScript ein reserviertes Wort ist. CSS2Properties currentStyle
Diese IE-spezifische Eigenschaft repräsentiert den kaskadierten Satz aller CSS-Eigenschaften, die auf das Element angewandt werden. Sie ist eine IE-spezifische Alternative zu Window.getComputedStyle( ). String dir
Der Wert des dir-Attributs des Elements; er gibt die Textrichtung für dieses Dokument an. String id
Der Wert des id-Attributs. Keine zwei Elemente in demselben Dokument dürfen als id denselben Wert haben.
896 | Referenz für clientseitiges JavaScript
491-0.book Seite 897 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLElement String innerHTML
Ein les- und schreibbarer String, der den in diesem Element enthaltenen HTML-Text angibt, allerdings ohne die öffnenden und schließenden Tags des Elements. Die Abfrage dieser Eigenschaft gibt den Inhalt des Elements als einen aus HTML-Text bestehenden String zurück. Wird diese Eigenschaft auf einen aus HTML-Text bestehenden String gesetzt, wird der Inhalt des Elements durch die Darstellung des geparsten HTML ersetzt. Während des Ladevorgangs lässt sich diese Eigenschaft nicht setzen (für diese Funktionalität siehe HTMLDocument.write( )). Die Eigenschaft ist eine nicht standardisierte Eigenschaft, die ihren Ursprung in IE 4 hat. Sie wird von allen modernen Browsern implementiert. String lang
Der Wert des lang-Attributs, das den Sprachcode für den Inhalt des Elements angibt. int offsetHeight, offsetWidth
Die Höhe und Breite des Elements und seines gesamten Inhalts in Pixeln, einschließlich CSS-Padding und der Grenzlinie (border) des Elements, aber ohne den Rand (margin). Diese Eigenschaften sind nicht standardisiert, werden aber gut unterstützt. Die X- und Y-Koordinaten der linken oberen Ecke der CSS-Grenzlinie des Elements, relativ zum umgebenden Element offsetParent. Diese Eigenschaften sind nicht standardisiert, werden aber gut unterstützt. Element offsetParent
Gibt das Container-Element an, das das Koordinatensystem definiert, in dem offsetLeft und offsetTop gemessen werden. Für die meisten Elemente ist offsetParent das sie enthaltende Document-Objekt. Hat jedoch ein Element einen dynamisch positionierten Container, so ist das dynamisch positionierte Element der offsetParent. In manchen Browsern werden Tabellenzellen nicht relativ zum Dokument positioniert, in dem sie enthalten sind, sondern relativ zu der Zeile, in der sie stehen. Ein Beispiel, das diese Eigenschaft browserübergreifend verwendet, finden Sie in Kapitel 16. Diese Eigenschaft ist nicht standardisiert, wird aber gut unterstützt. int scrollHeight, scrollWidth
Die gesamte Höhe und Breite eines Elements. Wenn ein Element Bildlaufleisten hat (beispielweise aufgrund des CSS-Attributs overflow), so unterscheiden sich diese Eigenschaften von offsetHeight und offsetWidth, die lediglich die Größe des sichtbaren Teils des Elements angeben. Diese Eigenschaften sind nicht standardisiert, werden aber gut unterstützt. int scrollLeft, scrollTop
Die Anzahl der Pixel des Elements, die durch Scrollen außerhalb der linken bzw. oberen Kante des Fensters liegen. Diese Eigenschaften eignen sich nur für Elemente mit Bildlaufleisten, wie z.B. Elemente, bei denen das CSS-Attribut overflow auf auto gesetzt ist. Diese Eigenschaften sind ebenfalls durch die Tags oder definiert (abhängig vom Browsertyp) und geben an, um wie viele Pixel das Gesamtdokument gescrollt worden ist. Allerdings geben diese Eigenschaften den Scrollumfang in einem -Tag nicht an. Diese Eigenschaften sind nicht standardisiert, werden aber gut unterstützt.
Referenz für clientseitiges JavaScript |
897
Referenz für clientseitiges JavaScript
int offsetLeft, offsetTop
491-0.book Seite 898 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLElement CSS2Properties style Der Wert des style-Attributs, das Inline-CSS-Stile für dieses Element festlegt. Beachten
Sie, dass der Wert dieser Eigenschaft kein String ist. Einzelheiten entnehmen Sie bitte CSS2Properties. String title
Der Wert des title-Attributs des Elements. Viele Browser zeigen den Wert dieses Attributs in einem Tooltip an, wenn sich die Maus über dem Element befindet.
Methoden HTMLElement-Objekte erben die standardisierten Methoden von Node und Element. Bestimmte Elementtypen implementieren tag-spezifische Methoden, die in der ausführlichen Tabelle im Abschnitt »Beschreibung« aufgeführt und in anderen Referenzeinträgen, wie z.B. Form, Input und Table, dokumentiert sind. Die meisten modernen Browser implementieren zusätzlich die folgende, nicht standardkonforme Methode: scrollIntoView( )
Scrollt das Dokument derart, dass das Element oben oder unten im Fenster zu sehen ist.
Event-Handler Alle HTML-Elemente reagieren auf rohe Maus- und Tasten-Events und können die im Folgenden aufgeführten Event-Handler auslösen. Manche Elemente, beispielsweise Links und Buttons, führen Defaultaktionen aus, wenn diese Events auftreten. Weitere Einzelheiten zu solchen Elementen finden Sie unter dem elementspezifischen Referenzeintrag; z.B. siehe Input und Link: onclick
Wird aufgerufen, wenn der Benutzer auf das Element klickt. ondblclick
Wird aufgerufen, wenn der Benutzer auf das Element doppelklickt. onkeydown
Wird aufgerufen, wenn der Benutzer eine Taste drückt. onkeypress
Wird aufgerufen, wenn der Benutzer eine Taste drückt und loslässt. onkeyup
Wird aufgerufen, wenn der Benutzer eine Taste loslässt. onmousedown
Wird aufgerufen, wenn der Benutzer eine Maustaste drückt. onmousemove
Wird aufgerufen, wenn der Benutzer die Maus bewegt. onmouseout
Wird aufgerufen, wenn der Benutzer die Maus vom Element wegbewegt. onmouseover
Wird aufgerufen, wenn der Benutzer die Maus über ein Element zieht. onmouseup
Wird aufgerufen, wenn der Benutzer eine Maustaste loslässt.
898 | Referenz für clientseitiges JavaScript
491-0.book Seite 899 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLElement
Beschreibung Jedes Tag in einem HTML-Dokument wird von einem HTMLElement-Objekt dargestellt. Ein HTMLElement definiert Eigenschaften, die die Attribute darstellen, die von allen HTMLElementen gemeinsam genutzt werden können. Die folgenden HTML-Tags haben keine Eigenschaften außer den oben aufgeführten und werden vollständig vom Interface HTMLElement beschrieben:
<strong>
Die meisten dieser tag-spezifischen Interfaces definieren lediglich eine JavaScript-Eigenschaft für jedes Attribut des HTML-Tags. Die JavaScript-Eigenschaften heißen genauso wie die Attribute und werden kleingeschrieben (z.B. id) oder auch mit Groß- und Kleinbuchstaben, wenn der Attributname aus mehreren Wörtern besteht (z.B. longDesc). Wenn ein HTML-Attributname in Java oder JavaScript ein reserviertes Wort ist, wird der Eigenschaftsname leicht abgewandelt. Beispielsweise wird das for-Attribut der Tags und zur htmlForEigenschaft der Interfaces HTMLLabelElement und HTMLScriptElement, da auch for ein reserviertes Wort ist. Die Bedeutungen dieser Eigenschaften, die den HTML-Attributen direkt entsprechen, werden in der HTML-Spezifikation definiert. Sie alle hier zu dokumentieren würde den Rahmen dieses Buches sprengen. Die folgende Tabelle führt alle HTML-Tags auf, die ein entsprechendes Subinterface von HTMLElement haben. Für jedes Tag gibt die Tabelle den DOM-Interface-Namen und die Namen der darin definierten Eigenschaften und Methoden an. Alle Eigenschaften sind les- und schreibbare Strings, soweit nichts anderes angegeben ist. Bei Eigenschaften, die keine les- und schreibbaren Strings sind, wird der Eigenschaftstyp vor dem Eigenschaftsnamen in eckigen Klammern angegeben. Einige Tags und Attribute sind in HTML 4 veraltet. Sie werden in dieser Tabelle mit * gekennzeichnet. Da sich diese Interfaces und ihre Eigenschaften so unmittelbar den HTML-Elementen und -Attributen zuordnen lassen, erhalten die meisten keine eigenen Referenzeinträge in diesem
Referenz für clientseitiges JavaScript |
899
Referenz für clientseitiges JavaScript
Die meisten HTML-Tags definieren zusätzliche Eigenschaften außer den oben ausdrücklich aufgeführten. Die DOM Level 2-HTML-Spezifikation definiert tag-spezifische Schnittstellen für diese Tags, sodass alle standardisierten HTML-Attribute eine entsprechende, standardisierte JavaScript-Eigenschaft haben. Ein Tag namens T hat normalerweise ein tag-spezifisches Subinterface namens HTMLTElement. So wird z.B. das -Tag vom HTMLHeadElementInterface dargestellt. In seltenen Fällen teilen sich zwei oder mehr verwandte Tags ein einziges Interface. Das gilt z.B. für die Tags bis , die alle durch das HTMLHeadingElementInterface dargestellt werden.
491-0.book Seite 900 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLElement
Buch. Einzelheiten entnehmen Sie bitte einer HTML-Referenz. Die Ausnahmen sind Schnittstellen, die Tags darstellen, die für clientseitige JavaScript-Programmierer besonders wichtig sind, wie beispielsweise und -Tags. Diese Tags werden in diesem Buch unter Namen dokumentiert, die kein »HTML«-Präfix oder »Element«-Suffix enthalten. Vergleichen Sie dazu z.B. die Einträge für Anchor, Applet, Canvas, Form, Image, Input, Link, Option, Select, Table und Textarea: HTML-Tag
Event-Handler, der aufgerufen wird, wenn der Benutzer auf ein Element klickt
Überblick Function onclick
Beschreibung Die Eigenschaft onclick eines HTMLElement-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer auf das Element klickt. Beachten Sie, dass onclick etwas anderes als onmousedown ist. Ein Klick-Event tritt erst ein, wenn ein mousedown- und ein mouseup-Event nacheinander auf demselben Element aufgetreten sind.
902 | Referenz für clientseitiges JavaScript
491-0.book Seite 903 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLElement.ondblclick
Siehe auch Element.addEventListener( ), Event, MouseEvent; Kapitel 17
HTMLElement.ondblclick
DOM Level 0
Dieser Event-Handler wird aufgerufen, wenn der Benutzer auf ein Element doppelklickt
Überblick Function ondblclick
Beschreibung Die Eigenschaft ondblclick eines HTMLElement-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer auf das Element doppelklickt.
Siehe auch
HTMLElement.onkeydown
DOM Level 0
Dieser Event-Handler wird aufgerufen, wenn der Benutzer eine Taste drückt
Überblick Function onkeydown
Beschreibung Die Eigenschaft onkeydown eines HTMLElement-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer eine Taste drückt während das Element den Tastaturfokus hat. Die Ermittlung, welche Taste oder Tasten gedrückt wurden, hängt etwas vom Browser ab. Einzelheiten entnehmen Sie bitte dem Kapitel 17. Für Funktionstasten wird vorzugsweise der Handler onkeydown verwendet. Um auf normale, alphanumerische Tastendrücke zu reagieren, verwenden Sie onkeypress.
Siehe auch HTMLElement.onkeypress; Kapitel 17
HTMLElement.onkeypress
DOM Level 0
Dieser Event-Handler wird aufgerufen, wenn der Benutzer eine Taste drückt
491-0.book Seite 904 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLElement.onkeyup
Beschreibung Die Eigenschaft onkeypress eines HTMLElement-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer eine Taste drückt, und loslässt, während das Element den Tastaturfokus hat. Ein keypress-Event wird nach dem keydown- und vor dem dazugehörigen keyup-Event generiert. Die Events keypress und keydown sind ähnlich, aber ein keypressEvent ist oft mehr für alphanumerische Tasten von Nutzen, und ein keydown-Handler kann für Funktionstasten vorteilhafter sein. Die Bestimmung, welche Taste gedrückt wurde und welche Modifier-Tasten zu diesem Zeitpunkt aktiv waren, ist recht kompliziert und hängt etwas vom Browsertyp ab. Einzelheiten entnehmen Sie bitte dem Kapitel 17.
Siehe auch HTMLElement.onkeydown; Kapitel 17
HTMLElement.onkeyup
DOM Level 0
Dieser Event-Handler wird aufgerufen, wenn der Benutzer eine Taste loslässt
Überblick Function onkeyup
Beschreibung Die Eigenschaft onkeyup eines HTMLElement-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer eine Taste loslässt, während das Element den Tastaturfokus hat.
Siehe auch HTMLElement.onkeydown; Kapitel 17
HTMLElement.onmousedown
DOM Level 0
Dieser Event-Handler wird aufgerufen, wenn der Benutzer eine Maustaste drückt
Überblick Function onmousedown
Beschreibung Die Eigenschaft onmousedown eines HTMLElement-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer eine Maustaste über dem Element drückt.
Siehe auch Element.addEventListener( ), Event, MouseEvent; Kapitel 17
904 | Referenz für clientseitiges JavaScript
491-0.book Seite 905 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLElement.onmousemove
HTMLElement.onmousemove
DOM Level 0
Dieser Event-Handler wird aufgerufen, wenn sich die Maus innerhalb eines Elements bewegt
Überblick Function onmousemove
Beschreibung Die Eigenschaft onmousemove eines HTMLElement-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer den Mauszeiger innerhalb des Elements bewegt. Wenn Sie einen onmousemove-Event-Handler definieren, werden massenweise MausbewegungsEvents generiert und gemeldet, wenn die Maus innerhalb von element bewegt wird. Bitte denken Sie daran, wenn Sie die Funktion schreiben, die der Event-Handler aufrufen soll. Wenn Sie das Ziehen der Maus verfolgen wollen, registrieren Sie einen Handler dieses Typs als Antwort auf ein mousedown-Event und deregistrieren ihn, wenn das mouseup-Event eintritt. Referenz für clientseitiges JavaScript
Siehe auch Element.addEventListener( ), Event, MouseEvent; Kapitel 17
HTMLElement.onmouseout
DOM Level 0
Dieser Event-Handler wird aufgerufen, wenn sich die Maus von einem Element wegbewegt
Überblick Function onmouseout
Beschreibung Die Eigenschaft onmouseout eines HTMLElement-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer den Mauszeiger aus dem Element herausbewegt.
Siehe auch Element.addEventListener( ), Event, MouseEvent; Kapitel 17
HTMLElement.onmouseover
DOM Level 0
Dieser Event-Handler wird aufgerufen, wenn sich die Maus über ein Element bewegt
Überblick Function onmouseover
Beschreibung Die Eigenschaft onmouseover eines HTMLElement-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer den Mauszeiger über das Element bewegt.
Referenz für clientseitiges JavaScript |
905
491-0.book Seite 906 Mittwoch, 4. April 2007 9:55 09
e-bol.net
HTMLElement.onmouseup
Siehe auch Element.addEventListener( ), Event, MouseEvent; Kapitel 17
HTMLElement.onmouseup
DOM Level 0
Dieser Event-Handler wird aufgerufen, wenn der Benutzer eine Maustaste loslässt
Überblick Function onmouseup
Beschreibung Die Eigenschaft onmouseup eines HTMLElement-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer eine Maustaste über dem Element loslässt.
Siehe auch Element.addEventListener( ), Event, MouseEvent; Kapitel 17
HTMLElement.scrollIntoView( )
Firefox 1.0, IE 4, Safari 2.02, Opera 8.5
Macht ein Element sichtbar
Überblick element.scrollIntoView(oben)
Argumente oben
Ein optionales Boolesches Argument, das angibt, ob das Element an das obere (true) oder untere (false) Ende des Bildschirms gescrollt werden soll. Dieses Argument wird nicht von allen Browsern unterstützt. Elemente, die weit oben oder weit unten im Dokument liegen, können normalerweise nicht zum gegenüberliegenden Festerrand gescrollt werden, sodass dieses Argument lediglich als Hinweis betrachtet werden sollte.
Beschreibung Ist das HTML-Element momentan nicht im Fester sichtbar, scrollt diese Methode das Dokument, sodass das Element sichtbar wird. Das Argument oben ist ein optionaler Hinweis darauf, ob das Element an das obere oder untere Ende des Bildschirms gescrollt werden soll. Für Elemente, die den Tastaturfokus akzeptieren (beispielsweise die Elemente Link und Input), führt die Methode focus( ) die gleiche Scrolle-bis-sichtbar-Operation automatisch durch.
Siehe auch Anchor.focus( ), Input.focus( ), Link.focus( ), Window.scrollTo( )
906 | Referenz für clientseitiges JavaScript
491-0.book Seite 907 Mittwoch, 4. April 2007 9:55 09
e-bol.net
IFrame
IFrame
DOM Level 2 HTML Node ➝ Element ➝ HTMLElement ➝ IFrame
Ein in einem HTML-Dokument
Eigenschaften Wie die folgende Beschreibung erklärt, kann auf IFrame-Elemente als IFrame-Objekt oder als Window-Objekt zugegriffen werden. Wird auf sie als IFrame-Objekt zugegriffen, erbt sie Eigenschaften von HTMLElement und definiert die zusätzlichen, unten aufgeführten Eigenschaften: Document contentDocument
Das Dokument, das den Inhalt von enthält. String src
Die URL, aus der der Inhalt des IFrames geladen wurde. Wenn Sie diese Eigenschaft setzen, lädt das IFrame ein neues Dokument. Diese Eigenschaft spiegelt lediglich das Attribut src des HTML--Tags wieder.
Eigenschaft
Attribut
Beschreibung
deprecated String align
align
Ausrichtung hinsichlich Inline-Inhalt
String frameBorder
frameborder
Für begrenzungslinienlose Frames auf »0« gesetzt
String height
height
Höhe des Viewports in Pixeln oder Prozent
String longDesc
longdesc
Die URL einer Frame-Beschreibung
String marginHeight
marginheight
Oberer und unterer Rand des Frames in Pixeln
String marginWidth
marginwidth
Linker und rechter Rand des Frames in Pixeln
String name
name
Der Name des Frames, zum Zugriff unter DOM Level 0 und für Formular- und Link-Ziele
String scrolling
scrolling
Scrollverhalten des Frames: »auto«, »yes« oder »no«
String width
width
Breite des Viewports in Pixeln oder Prozent
Beschreibung Abgesehen von kleinen Unterschieden in ihren HTML-Attributen verhalten sich Elemente in clientseitigem JavaScript sehr ähnlich wie -Elemente. -Elemente werden Teil des frames[]-Arrays im umgebenden Window-Objekt. Wird über dieses Array auf die Elemente zugegriffen, werden sie durch Window-Objekte dargestellt, und die oben aufgeführten Eigenschaften sind nicht vorhanden. Wird auf ein -Element als Dokumentelement über die ID oder den Tag-Namen zugegriffen, dann wird es durch ein IFrame-Objekt dargestellt; es enthält dann die oben gezeigten Eigenschaften. Verwenden Sie src, um die URL des abzufragen oder zu setzen, und contentDocument, um auf den IFrame-Inhalt zuzugreifen. Denken Sie aber daran, dass die Same Origin Policy (siehe Abschnitt 13.8.2) eventuell den Zugriff auf contentDocument verhindert.
Referenz für clientseitiges JavaScript |
907
Referenz für clientseitiges JavaScript
Neben diesen Eigenschaften definiert das IFrame-Objekt auch die nachfolgenden Eigenschaften, die direkt HTML-Attributen des -Tags entsprechen:
491-0.book Seite 908 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Image
Siehe auch Frame, Window; Kapitel 14
Image
DOM Level 2 HTML
Ein Bild in einem HTML-Dokument
Node ➝ Element ➝ HTMLElement ➝ Input
Konstruktor new Image(integer breite, integer hoehe)
Argumente breite, hoehe
Eine optional für das Bild angegebene Breite und Höhe.
Eigenschaften String name
Diese Eigenschaft legt den Namen für das Image-Objekt fest. Wenn ein -Tag ein name-Attribut hat, können Sie auf das entsprechende Image-Objekt über eine benannte Eigenschaft des Document-Objekts zugreifen. String src
Ein les- und schreibbarer String mit der URL des Bildes, das der Browser anzeigen soll. Der Anfangswert dieser Eigenschaft wird vom src-Attribut des -Tags gesetzt. Wenn Sie diese Eigenschaft auf die URL eines neuen Bildes setzen, lädt der Browser dieses neue Bild und zeigt es an. Das ist nützlich, wenn Sie das grafische Erscheinungsbild Ihrer Webseiten je nach den Benutzeraktionen anpassen, und hiermit sind auch einfache Animationen möglich. Zusätzlich zu diesen Eigenschaften unterstützen Image-Objekte auch die nachfolgenden Eigenschaften, die lediglich die HTML-Attribute widerspiegeln: Eigenschaft
Attribute
Beschreibung
deprecated String align
align
Ausrichtung hinsichtlich Inline-Inhalt
String alt
alt
Alternativer Text, wenn das Bild nicht angezeigt werden kann
deprecated String border
border
Breite der Bildumrandung
long height
height
Bildhöhe in Pixeln
deprecated long hspace
hspace
Linker und rechter Rand in Pixeln
boolean isMap
ismap
Gibt an, ob eine serverseitige Imagemap verwendet werden soll
String longDesc
longdesc
Die URI einer langen Bildbeschreibung
String useMap
usemap
Legt eine clientseitige Imagemap für das Bild fest
deprecated long vspace
vspace
Oberer und unterer Rand in Pixeln
long width
width
Bildbreite in Pixeln
908 | Referenz für clientseitiges JavaScript
491-0.book Seite 909 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Image
Event-Handler Image erbt Event-Handler von HTMLElement und definiert die folgenden Event-Handler: onabort
Wird aufgerufen, wenn der Ladevorgang für die Seite angehalten wird, bevor das Bild vollständig heruntergeladen ist. onerror
Wird aufgerufen, wenn beim Herunterladen des Bildes ein Fehler auftritt. onload
Wird aufgerufen, wenn das Bild erfolgreich geladen wurde.
HTML-Syntax Das Image-Objekt wird mit dem Standard-HTML-Tag erzeugt. Manche -Attribute brauchen die folgende Syntax nicht zu befolgen, weil sie in JavaScript nicht allgemein verwendet werden: // // // // // // //
Das anzuzeigende Bild ... seine Breite ... seine Höhe Kurzbeschreibung des Bildes Wird nach dem vollständigen Laden aufgerufen Wird aufgerufen, wenn beim Laden ein Fehler auftritt Wird aufgerufen, wenn der Benutzer den Ladevorgang abbricht
Beschreibung Ein Image-Objekt stellt ein Bild dar, das mit einem -Tag in ein HTML-Dokument eingebettet wurde. Die in einem Dokument erscheinenden Bilder werden im Array document. images[] gesammelt. Sie können auf Bilder mit name-Attributen auch über benannte Eigenschaften des Document-Objekts zugreifen. Ein Beispiel: document.images[0] document.banner
// Das erste Bild im Dokument // Ein Bild mit name="banner"
Beim Image-Objekt ist die Eigenschaft src die interessanteste. Wenn Sie sie setzen, lädt der Browser das Bild, das durch den neuen Wert angegeben wird, und zeigt es an. Dadurch lassen sich visuelle Effekte erzielen, wie z.B. Bild-Rollover und Animationen. Beispiele finden Sie in Kapitel 22. Sie können in Ihrem JavaScript-Programm Offscreen-Image-Objekte dynamisch mit der Konstruktorfunktion Image() erzeugen. Beachten Sie, dass dieser Konstruktor kein Argument hat, das das zu ladende Bild angibt. Wie bei den in HTML erzeugten Bildern teilen Sie dem Browser mit, dass er ein Bild laden soll, indem Sie die src-Eigenschaft eines explizit von Ihnen erzeugten Bildes setzen. Ein auf diese Art erzeugtes Image-Objekt kann nicht angezeigt werden; Sie können das Image-Objekt lediglich zum Herunterladen eines Bildes zwingen, indem Sie die Eigenschaft src setzen. Das ist allerdings nützlich, da ein Bild in den Browser-Cache geladen wird. Wenn die gleiche Bild-URL später mit einem tatsächlichen -Tag verwendet wird, wird es schnell angezeigt, da es bereits im Cache vorhanden ist.
Referenz für clientseitiges JavaScript |
909
Referenz für clientseitiges JavaScript
491-0.book Seite 910 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Image.onabort
Siehe auch Kapitel 22
Image.onabort
DOM Level 2 Events
Dieser Event-Handler wird aufgerufen, wenn der Benutzer das Laden des Bildes abbricht
Überblick Function onabort
Beschreibung Die Eigenschaft onabort eines Image-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer das Laden einer Seite abbricht (indem er z.B. auf Stop klickt, bevor das Bild vollständig heruntergeladen ist).
Image.onerror
DOM Level 2 Events
Dieser Event-Handler wird aufgerufen, wenn beim Laden eines Bildes ein Fehler auftritt
Überblick Function onerror
Beschreibung Die Eigenschaft onerror eines Image-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn beim Laden eines Bildes ein Fehler auftrat. Siehe auch Window.onerror.
Image.onload
DOM Level 2 Events
Dieser Event-Handler wird aufgerufen, wenn ein Bild fertig geladen wurde
Überblick Function onload
Beschreibung Die Eigenschaft onload eines Image-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn ein Bild erfolgreich geladen wurde. Siehe auch Window.onload.
910 | Referenz für clientseitiges JavaScript
491-0.book Seite 911 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Input
Input Ein Eingabeelement in einem HTML-Formular
DOM Level 2 HTML Node ➝ Element ➝ HTMLElement ➝ Input
Eigenschaften String accept Wenn type auf »file« gesetzt ist, ist diese Eigenschaft eine durch Kommata getrennte Liste
von MIME-Typen, die die hochladbaren Dateitypen angibt. Diese Eigenschaft bildet das accept-Attribut ab. String accessKey
Der Tastatur-Shortcut (darf nur ein einziges Zeichen sein), mit dem ein Browser den Tastaturfokus auf dieses Eingabeelement übertragen kann. Bildet das Attribut accesskey ab. deprecated String align
Die vertikale Ausrichtung dieses Elements hinsichtlich des umgebenden Texts oder der linke oder rechte Einzug für das Element. Diese Eigenschaft bildet das align-Attribut ab. Ein Alternativtext, der von Browsern angezeigt wird, die dieses Eingabeelement nicht wiedergeben können. Ist besonders nützlich, wenn image der type ist. Diese Eigenschaft bildet das alt-Attribut ab. boolean checked Wenn der type auf »radio« oder »checkbox« gesetzt ist, legt diese Eigenschaft fest, ob das
Element auf »checked« steht oder nicht. Wenn Sie sie setzen, ändert sich das Erscheinungsbild des Eingabeelements. Diese Eigenschaft bildet das checked-Attribut ab. boolean defaultChecked Wenn der type »radio« oder »checkbox« ist, enthält diese Eigenschaft den Anfangswert des Attributs checked so, wie er im Dokumentquelltext erscheint. Wenn das Formular zurückgesetzt wird, wird die checked-Eigenschaft auf den Wert dieser Eigenschaft zurückgesetzt. Wenn Sie den Wert dieser Eigenschaft ändern, ändern sich der Wert der checked-
Eigenschaft und der aktuelle Auswahlstatus des Elements. String defaultValue Steht type auf »text«, »password« oder »file«, so enthält diese Eigenschaft den vom
Element angezeigten Anfangswert. Wenn das Formular zurückgesetzt wird, wird das Element mit diesem Wert wiederhergestellt. Eine Änderung des Wertes dieser Eigenschaft ändert auch die value-Eigenschaft und den aktuell angezeigten Wert. boolean disabled
Wenn diese Eigenschaft true ist, ist das Eingabeelement deaktiviert und steht nicht für eine Benutzereingabe zur Verfügung. Bildet das Attribut disabled ab. readonly HTMLFormElement form
Das Form-Objekt, das das -Element darstellt, in dem dieses Eingabeelement enthalten ist, oder null, wenn sich das Eingabeelement gar nicht in einem Formular befindet.
Referenz für clientseitiges JavaScript |
911
Referenz für clientseitiges JavaScript
String alt
491-0.book Seite 912 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Input long maxLength Steht type auf »text« oder »password«, dann gibt diese Eigenschaft die maximale Zeichen-
anzahl an, die der Benutzer eingeben kann. Sie sollten diesen Wert aber niemals als Garantie dafür ansehen, dass Ihr Serverskript unter dem Namen dieses Eingabeelements keine längeren Zeichenketten empfangen wird: Ein Hacker braucht zum Ansprechen Ihres Skripts ja nicht unbedingt das dafür von Ihnen vorgesehene Formular verwenden; er kann sich dafür auch sein eigenes Formular ohne Zeichenbegrenzung schreiben. Beachten Sie, dass diese Eigenschaft nicht mit der size-Eigenschaft identisch ist. Bildet das Attribut maxlength ab. String name
Der Name des Eingabeelements, wie er im name-Attribut angegeben wird. Weitere Einzelheiten über Formularelementnamen finden Sie in der anschließenden Beschreibung. boolean readOnly Steht true und type auf »text« oder »password«, so kann der Benutzer keinen Text in das Element eingeben. Bildet das Attribut readonly ab. unsigned long size Steht type auf »text« oder »password«, dann gibt diese Eigenschaft die Breite des Elements in Zeichen an. Bildet das size-Attribut ab. Siehe auch maxLength. String src
Für Eingabeelemente, die type als »type« haben. Gibt die URL des anzuzeigenden Bilds an. Bildet das src-Attribut ab. long tabIndex
Die Position dieses Eingabeelements in der Tab-Reihenfolge. Bildet das Attribut tabindex ab. String type
Der Typ des Eingabeelements. Bildet das type-Attribut ab. Die Beschreibung enthält weitere Einzelheiten über Formelement-Typen. String useMap
Für Elemente, die »image« als type haben, gibt diese Eigenschaft den Namen einer an, die eine clientseitige Imagemap für das Element liefert. String value
Der Wert, der bei der Übermittlung des Formulars an den Webserver übergeben wird. Für Elemente, die »text«, »password« oder »file« als type haben, stellt diese Eigenschaft den editierbaren Text im Eingabeelement dar. Für Elemente, die »button«, »submit« oder »reset« als type haben, ist das die (nicht editierbare) auf diesem Button erscheinende Beschriftung. Aus Sicherheitsgründen ist die value-Eigenschaft von FileUpload-Elementen meist schreibgeschützt. In gleicher Weise ist der Wert, den diese Eigenschaft bei Password-Elementen zurückgibt, unter Umständen nicht die wirkliche Benutzereingabe.
Methoden blur( )
Entzieht dem Element den Tastaturfokus. click( )
Wenn type »button«, »checkbox«, »radio«, »reset« oder »submit« ist, simuliert diese Methode einen Mausklick auf das Element.
912 | Referenz für clientseitiges JavaScript
491-0.book Seite 913 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Input focus( )
Übergibt den Tastaturfokus an dieses Eingabeelement. select( )
Wenn der type »file«, »password« oder »text« ist, wählt diese Methode den vom Element angezeigten Text aus. In vielen Browsern wird, wenn der Benutzer das nächste Zeichen eingibt, der ausgewählte Text gelöscht und durch das neu eingetippte Zeichen ersetzt.
Event-Handler onblur
Wird aufgerufen, wenn der Benutzer dem Element den Tastaturfokus entzieht. onchange
onclick
Bei Buttons und Schaltelementen wird dieser Event-Handler aufgerufen, wenn der Benutzer den Button durch einen Mausklick oder eine Tastatureingabe aktiviert. onfocus
Wird aufgerufen, wenn der Benutzer dem Element den Tastaturfokus gibt.
Beschreibung Ein Input-Objekt stellt ein HTML-Tag dar, das ein Formular-Eingabeelement beschreibt, das sich per Skript steuern lässt. Die drei wichtigsten Eigenschaften eines InputObjekts sind type, value und name. Diese Eigenschaften werden in den anschließenden Unterabschnitten beschrieben. In Kapitel 18 können Sie weitere Informationen über HTMLFormulare und Formularelemente nachlesen. Typen von Eingabeelementen Das Attribut type des HTML-Tags legt die Art des zu erzeugenden Eingabeelements fest. Das Attribut kann in clientseitigem JavaScript als type-Eigenschaft des Input-Objekts verwendet werden. Es ist nützlich, um den Typ eines unbekannten Formularelements festzustellen, beispielsweise wenn Sie durch das Array elements[] eines Form-Objekts iterieren. Hier werden die zulässigen Werte von type aufgeführt: "button"
Das Eingabeelement ist ein grafischer Button, der den von der Eigenschaft value festgelegten Klartext anzeigt. Der Button hat kein Standardverhalten. Um nützlich zu sein, braucht er einen onclick-Event-Handler. Für Buttons, die ein Formular absenden oder zurücksetzen, verwenden Sie den type »submit« oder »reset«. Beachten Sie, dass das HTML-Tag Buttons erzeugen kann, die statt Klartext beliebiges HTML anzeigen.
Referenz für clientseitiges JavaScript |
913
Referenz für clientseitiges JavaScript
Bei Texteingabe-Elementen wird dieser Event-Handler aufgerufen, wenn der Benutzer den angezeigten Text ändert und diese Änderungen »bestätigt«, indem er den Tastaturfokus durch Tabbing oder Klicken der Maustaste auf ein anderes Element verlagert. Dieser Handler reagiert nicht auf Änderungen nach einzelnen Eingabetastendrücken. Die Schaltelemente vom Typ »checkbox« und »radio« können dieses Event auch auslösen (zusätzlich zum Event onclick), wenn der Benutzer den Schaltzustand ändert.
491-0.book Seite 914 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Input "checkbox"
Ein Eingabeelement dieses Typs zeigt einen Schalter an, den der Benutzer aktivieren und deaktivieren kann (Checkboxen). Die Eigenschaft checked enthält den momentanen Button-Status. Der Event-Handler onclick wird aktiviert, wenn sich dieser Wert ändert. (Browser können auch den Handler onchange aktivieren.) Die Eigenschaft value ist ein interner Wert zur Übermittlung an einen Webserver und wird dem Benutzer nicht angezeigt. Um ein Label mit einer Checkbox zu assoziieren, stellen Sie den Beschriftungstext einfach neben das Tag . Wenn Sie wollen, können Sie das Tag verwenden. Checkboxen kommen oft in Gruppen vor. Den Gruppenmitgliedern werden manchmal die gleiche name-Eigenschaft und unterschiedliche value-Eigenschaften gegeben, was die Arbeit des Webservers erleichtert, an den das Formular übermittelt wird. "file"
Dieser Typ erzeugt ein Fileupload-Element zum Heraufladen von Dateien. Dieses Element besteht aus einem Texteingabefeld zur Angabe eines Dateinamens und aus einem Button, der ein Dialogfeld zur Dateiauswahl öffnet, mit dem eine Datei grafisch ausgewählt wird. Die Eigenschaft value enthält den Namen der vom Benutzer angegebenen Datei. Wenn ein Formular übermittelt wird, das ein Fileupload-Element enthält, sendet der Browser jedoch nicht nur den Dateinamen, sondern den Inhalt der ausgewählten Datei an den Server. (Damit dies funktioniert, muss das Formular die »multipart/formdata«-Codierung und das Übertragungsverfahren POST benutzen.) Aus Sicherheitsgründen erlaubt das Fileupload-Element HTML-Autoren oder JavaScriptProgrammierern nicht, den Default-Dateinamen auszuwählen. Das HTML-Attribut value wird ignoriert, und die Eigenschaft value ist für diesen Elementtyp schreibgeschützt, sodass nur der Benutzer einen Dateinamen eingeben kann. Wählt oder ändert der Benutzer einen Dateinamen, aktiviert ein Fileupload-Element den Event-Handler onchange. "hidden"
Ein Eingabeelement dieses Typs wird verborgen. Die Eigenschaft value dieses unsichtbaren Formularelements enthält einen an den Webserver zu übergebenden beliebigen String.Wenn Sie Daten übermitteln wollen, die der Benutzer nicht selbst eingegeben hat, verwenden Sie Elemente dieses Typs. "image"
Dieser Typ eines Eingabeelements ist ein Formularabsende-Button, der kein Label mit Text anzeigt, sondern ein Bild (festgelegt von der Eigenschaft src). Die value-Eigenschaft wird nicht verwendet. Weitere Informationen finden Sie unter dem Elementtyp »submit«. "password"
Dieses Texteingabefeld dient der Eingabe von vertraulichen Daten, wie z.B. Passwörtern. Beim Drücken der Tasten wird die Eingabe getarnt (beispielsweise durch Sternchen), um zu verhindern, dass Beistehende die Eingabewerte mitlesen können. Allerdings wird die Benutzereingabe nicht verschlüsselt. Bei der Übergabe des Formulars wird sie als Klartext gesendet. Als Vorsichtsmaßnahme halten manche Browser den JavaScript-Code davon ab, die Eigenschaft value zu lesen. In allen anderen Situationen verhält sich ein PasswortEingabeelement genau wie ein Element des Typs »text«. Es aktiviert den Event-Handler onchange, wenn der Benutzer den angezeigten Wert ändert.
914 | Referenz für clientseitiges JavaScript
491-0.book Seite 915 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Input "radio"
Ein Eingabeelement von diesem Typ zeigt einen einzelnen, grafischen Radio-Button an. Ein Radio-Button ist ein einzelner aus einer Gruppe von Buttons, die für sich gegenseitig ausschließende Wahlmöglichkeiten stehen. Wird ein Button gewählt, ist der vorher ausgewählte Button nicht mehr gewählt (wie bei mechanischen, voreingestellten Stationsknöpfen an alten Autoradios). Damit die Gruppe der Radio-Buttons dieses Verhalten der sich gegenseitig ausschließenden Wahlmöglichkeit zeigt, müssen sie im gleichen -Tag stehen und den gleichen name haben. Schalter ohne gegenseitigen Ausschluss verwenden einen type von »checkbox«. Beachten Sie, dass das HTML-Tag auch zur Darstellung von exklusiven oder nicht exklusiven Auswahlmöglichkeiten verwendet werden kann (siehe Select). Die Eigenschaft checked gibt an, ob der Radio-Button ausgewählt ist. Es gibt keine Möglichkeit festzustellen, welcher Button in einer sich gegenseitig ausschließenden Gruppe ausgewählt ist: Sie müssen jeden Button auf die Eigenschaft checked hin überprüfen. Bei Wahl oder Abwahl von Radio-Buttons aktivieren diese den Event-Handler onclick.
"reset"
Ein Eingabeelement dieses Typs gleicht dem mit dem type »button« erzeugten Button, hat jedoch einen spezielleren Zweck. Wird ein Reset-Button-Element angeklickt, werden die Werte aller Eingabeelemente im Formular, die dieses Element enthalten, auf ihre Standardwerte zurückgesetzt (die über das HTML-Attribut value oder die JavaScriptEigenschaft defaultValue festgelegt werden). Die Eigenschaft value gibt den Text an, der auf dem Button erscheinen soll. Ein ResetButton aktiviert den Handler onclick und setzt dann das Formular zurück. Dieser Handler kann das Zurücksetzen unterbinden, indem er false zurückgibt oder indem er andere Methoden zum Löschen des Events verwendet, die in Kapitel 17 beschrieben werden. Vergleichen Sie dazu auch die Methode Form.reset( ) und den Event-Handler Form.onreset. "submit"
Ein Element von diesem Typ ist ein Button, der beim Anklicken die übermittelt, die das Element enthält. Die Eigenschaft value gibt den Text an, der auf dem Button erscheinen soll. Zuerst wird der Event-Handler onclick aktiviert und dann das Formular übermittelt. Ein Handler kann die Übertragung des Formulars abbrechen, indem er false zurückgibt. Vergleichen Sie dazu die Methode Form.submit( ) und den Event-Handler Form.onsubmit. "text"
Das ist der Standardwert der Eigenschaft type; er erzeugt ein einzeiliges Texteingabefeld. Das HTML-Attribut value gibt den im Feld stehenden Standardtext an, und die JavaScript-Eigenschaft value enthält den momentan angezeigten Text. Der Event-Handler onchange wird ausgelöst, wenn der Benutzer den angezeigten Text editiert und den Eingabefokus dann an ein anderes Element übergibt. Verwenden Sie size, um die Breite des
Referenz für clientseitiges JavaScript |
915
Referenz für clientseitiges JavaScript
Die Eigenschaft value gibt einen an den Webserver zu übermittelnden Wert an, der im Formular nicht angezeigt wird. Um eine Beschriftung für einen Radio-Button anzugeben, gehen Sie wie bei einem -Tag vor, also außerhalb des -Tags.
491-0.book Seite 916 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Input
Eingabefelds festzulegen, und maxLength für die maximal eingebbare Zeichenanzahl. Beachten Sie, dass nicht garantiert werden kann, dass sich auch jeder Client an die Vorgabe einer maximalen Eingabelänge hält. Enthält ein Formular lediglich ein Eingabeelement vom Typ »text«, so wird das Formular beim Drücken von Enter übermittelt. Für mehrzeilige Texteingaben verwenden Sie das HTML-Tag (siehe Textarea). Für eine getarnte Texteingabe setzen Sie type auf »password«. Input-Elementwerte Die Eigenschaft value des Input-Objekts ist eine les- und schreibbare String-Eigenschaft, die den an den Webserver gesendeten Text festlegt, wenn das Formular übermittelt wird, das das Eingabeelement enthält. Abhängig vom Wert der Eigenschaft type kann die Eigenschaft value auch vom Benutzer einsehbaren Text enthalten. Bei Eingabeelementen vom Typ »text« und »file« enthält diese Eigenschaft den vom Benutzer eingegebenen Text. Bei Elementen des Typs »button«, »reset« und »submit« gibt die Eigenschaft value an, welcher Text auf dem Button stehen soll. Bei anderen Element-Typen, wie z.B. »checkbox«, »radio« und »image«, wird der Inhalt der Eigenschaft value dem Benutzer nicht angezeigt und nur bei der Übermittlung des Formulars verwendet. Input-Elementnamen Die Eigenschaft name des Input-Objekts ist ein String, der dem Eingabeelement einen Namen zur Verfügung stellt. Ihr Wert stammt aus dem HTML-Attribut name. Der Name eines Formularelements dient zwei Zwecken. Der erste ist die Formularübermittlung. Die Daten für die einzelnen Elemente werden normalerweise im folgenden Format übermittelt: name=wert
Hierbei werden name und wert so codiert, wie es für die Übermittlung erforderlich ist. Wenn für ein Formularelement kein Name angegeben wird, können die Daten dieses Elements nicht an einen Webserver übertragen werden. Zweitens dient die Eigenschaft name dazu, in einem JavaScript-Programm auf ein Formularelement Bezug zu nehmen. Der Name eines Elements wird eine Eigenschaft des Formulars, in dem dieses Element steht. Der Wert dieser Eigenschaft ist eine Referenz auf das betreffende Element. Ist beispielsweise adresse ein Formular, das ein Texteingabeelement namens PLZ enthält, so bezieht sich adresse.PLZ auf eben dieses Element. Für Eingabeelemente vom Typ »radio« und »checkbox« wird in der Regel mehr als ein zugehöriges Objekt definiert. Alle diese Objekte haben dieselbe name-Eigenschaft. In diesem Fall werden die Daten im folgenden Format an den Server übermittelt: name=wert1,wert2,...,wertn
Ebenso wird auch in JavaScript jedes Element, das seinen Namen mit anderen teilt, Element eines Arrays mit demselben Namen. Wenn Sie z.B. im Formular bestellung vier gleichnamige Checkbox-Elemente haben, so stehen diese in JavaScript als Elemente des Arrays bestellung.options[] zur Verfügung.
916 | Referenz für clientseitiges JavaScript
491-0.book Seite 917 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Input.blur( )
Verwandte Formularelemente Mit dem HTML-Tag können Sie verschiedene Formularelemente erzeugen. Die Tags , und erzeugen außerdem ebenfalls Formularelemente.
Siehe auch Form, Form.elements[], Option, Select, Textarea; Kapitel 18
Input.blur( )
DOM Level 2 HTML
Entzieht einem Formularelement den Eingabefokus
Überblick void blur( )
Beschreibung
Input.click( )
DOM Level 2 HTML
Simuliert einen Mausklick auf einem Formularelement
Überblick void click( )
Beschreibung Die click()-Methode eines Formularelements simuliert einen Mausklick auf dieses Element, ruft aber nicht dessen Event-Handler onclick auf. Die click()-Methode ist nicht oft von Nutzen. Da sie den onclick-Handler nicht aufruft, ist ein Aufruf dieser Methode auf Button-Elementen sinnlos, da diese einzig und allein das durch onclick definierte Verhalten haben. Wenn Sie click() auf einem Submit- oder Reset-Element aufrufen, wird ein Formular übermittelt oder zurückgesetzt, aber der direktere Weg dafür wäre ein Aufruf der Methode submit() oder reset() des Form-Objekts selbst.
Referenz für clientseitiges JavaScript |
917
Referenz für clientseitiges JavaScript
Die Methode blur( ) eines Formularelements entfernt den Tastaturfokus von diesem Element, ohne dabei den Event-Handler onblur aufzurufen. Im Grunde ist diese Methode das Gegenteil der Methode focus( ). Da die Methode blur() den Tastaturfokus jedoch nicht an eine andere Stelle verlagert, ist ein Aufruf dieser Methode nur an einem einzigen Punkt wirklich sinnvoll, nämlich unmittelbar, bevor Sie den Tastaturfokus mit der focus()-Methode verlagern, ohne dass der Event-Handler onblur aufgerufen werden soll. Also: Indem Sie einem Element den Fokus explizit entziehen, werden Sie nicht benachrichtigt, wenn er durch den Aufruf von focus() für ein anderes Element implizit verlagert wird.
491-0.book Seite 918 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Input.focus( )
Input.focus( )
DOM Level 2 HTML
Gibt einem Formularelement den Tastaturfokus
Überblick void focus( )
Beschreibung Die focus()-Methode eines Formularelements gibt ihm den Tastaturfokus, ohne den EventHandler onfocus aufzurufen. Sie aktiviert also dieses Element für die Tastaturnavigation und Tastatureingabe. Wenn Sie also für ein Eingabeelement vom Typ »text« focus( ) aufrufen, erscheint der gesamte Text, den der Benutzer anschließend eingibt, in diesem Text-Element. Rufen Sie focus() für ein Button-Element auf, so kann der Benutzer den betreffenden Button von der Tastatur aus drücken.
Input.onblur
DOM Level 0
Dieser Handler wird aufgerufen, wenn ein Element den Fokus verliert
Überblick Function onblur
Beschreibung Die Eigenschaft onblur eines Input-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer diesem Eingabeelement den Tastaturfokus entzieht. Wird blur() aufgerufen, um den Fokus von einem Element zu entfernen, so wird dadurch nicht onblur für dieses Objekt aufgerufen. Wenn Sie hingegen mit der Methode focus() den Fokus auf ein anderes Element verlagern, wird sehr wohl der Event-Handler onblur für das Element aufgerufen, das zurzeit noch den Fokus hat.
Siehe auch Element.addEventListener( ), Window.onblur; Kapitel 17
Input.onchange
DOM Level 2 Events
Dieser Event-Handler wird aufgerufen, wenn sich der Wert eines Formularelements ändert
Überblick Function onchange
Beschreibung Die Eigenschaft onchange eines Input-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer den Wert ändert, den ein Formularelement anzeigt. Die Änderung kann eine Editierung des in Eingabeelementen vom Typ »text«, »password« und
918 | Referenz für clientseitiges JavaScript
491-0.book Seite 919 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Input.onclick
»file« angezeigten Textes sein oder die Auswahl oder Abwahl eines Toggle-Buttons vom Typ »radio« oder »checkbox«. (Radio- und Checkbox-Elemente lösen immer den Handler onclick aus und können zusätzlich den Handler onchange auslösen). Beachten Sie, dass dieser EventHandler nur aufgerufen wird, wenn der Benutzer eine solche Änderung vornimmt, und nicht, wenn ein JavaScript-Programm den Anzeigewert eines Elements ändert. Denken Sie bitte auch daran, dass der Event-Handler onchange nicht jedes Mal aufgerufen wird, wenn der Benutzer ein Zeichen in einem Texteingabeelement eingibt oder löscht. onchange ist nicht für eine derartige zeichenweise Event-Verarbeitung gedacht. Der Aufruf von onchange erfolgt erst dann, wenn der Benutzer die Bearbeitung abgeschlossen hat. Der Browser geht davon aus, dass die Bearbeitung abgeschlossen ist, wenn der Tastaturfokus von einem Element zu einem anderen verlagert wird, also z.B., wenn der Benutzer auf das nächste Element im Formular klickt. S(iehe HTMLElement.onkeypress für Informationen über zeichenweise EventNotifikation.)
Siehe auch Element.addEventListener( ), HTMLElement.onkeypress; Kapitel 17
Input.onclick
DOM Level 2 Events
Dieser Event-Handler wird aufgerufen, wenn ein Formularelement angeklickt wird
Überblick Function onclick
Beschreibung Die Eigenschaft onclick eines Input-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer das Input-Element aktiviert. In der Regel geschieht das mit einem Mausklick auf das Element. Der Event-Handler onclick wird aber auch ausgelöst, wenn der Benutzer das Element über die Tastatur (Tabulatortaste) aktiviert. Der Handler onclick wird nicht aufgerufen, wenn die click( )-Methode auf diesem Element eingesetzt wird. Achten Sie darauf, dass die Eingabeelemente des Typs »reset« und »submit« bei ihrem Anklicken eine Standardaktion durchführen: Sie setzen das Formular, in dem sie enthalten sind, zurück bzw. senden es ab. Den onclick-Event-Handler jedes Elements können Sie dazu nutzen, zusätzlich zu diesen Standardaktionen noch andere Aktionen geschehen zu lassen. Sie können die Standardaktionen unterbinden, indem Sie false zurückgeben oder indem Sie die anderen Techniken zum Abbrechen von Events verwenden, die in Kapitel 17 beschrieben werden. Dasselbe können Sie auch mit den Event-Handlern onsubmit und onreset des Form-Objekts selbst tun.
Referenz für clientseitiges JavaScript |
919
Referenz für clientseitiges JavaScript
Der Event-Handler onchange wird bei Eingabeelementen vom Typ »button«, »hidden«, »image«, »reset« und »submit« nicht verwendet. Elemente dieses Typs verwenden stattdessen den Event-Handler onclick.
491-0.book Seite 920 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Input.onfocus
Siehe auch Element.addEventListener( ); Kapitel 17
Input.onfocus
DOM Level 2 Events
Dieser Event-Handler wird aufgerufen, wenn das Formularelement den Fokus erhält
Überblick Function onfocus
Beschreibung Die Eigenschaft onfocus eines Input-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer den Tastaturfokus auf dieses Element überträgt. Wenn Sie focus() aufrufen, um den Fokus auf ein Element zu lenken, so wird nicht onfocus für dieses Objekt aufgerufen.
Siehe auch Element.addEventListener( ), Window.onfocus; Kapitel 17
Input.select( )
DOM Level 2 HTML
Wählt einen Text in einem Formularelement aus
Überblick void select( )
Beschreibung Die Methode select() markiert den in einem Eingabeelement vom Typ »text«, »password« oder »file« angezeigten Text. Die Auswirkungen der Textauswahl können je nach Plattform unterschiedlich sein. In der Regel wird der Text markiert, kann ausgeschnitten und eingefügt werden, und er wird gelöscht, wenn der Benutzer ein anderes Zeichen eingibt.
JavaArray, JavaClass, JavaObject, JavaPackage Siehe Teil III
JSObject Java-Darstellung eines JavaScript-Objekts
Überblick public final class netscape.javascript.JSObject extends Object
920 | Referenz für clientseitiges JavaScript
Java-Klasse in einem Java-Plug-in
491-0.book Seite 921 Mittwoch, 4. April 2007 9:55 09
e-bol.net
JSObject.call( )
Methoden call( )
Ruft eine Methode des JavaScript-Objekts auf. eval( )
Wertet einen String mit JavaScript-Code im Kontext des JavaScript-Objekts aus. getMember( )
Holt den Wert einer Eigenschaft des JavaScript-Objekts. getSlot( )
Holt den Wert eines Array-Elements des JavaScript-Objekts. getWindow( )
Holt ein »Wurzel«-JSObject, das das JavaScript-Window-Objekt des Webbrowsers repräsentiert. removeMember( )
Löscht eine Eigenschaft aus dem JavaScript-Objekt. setMember( )
Referenz für clientseitiges JavaScript
Setzt den Wert einer Eigenschaft des JavaScript-Objekts. setSlot( )
Setzt den Wert eines Array-Elements des JavaScript-Objekts. toString( )
Ruft die Methode toString() von JavaScript für das JavaScript-Objekt auf und gibt ihre Ergebnisse zurück.
Beschreibung JSObject ist kein JavaScript-Objekt, sondern eine Java-Klasse; in Ihrem JavaScript-Programm kann sie nicht verwendet werden. Stattdessen wird das JSObject von Java-Applets genutzt, die mit JavaScript kommunizieren möchten, indem sie JavaScript-Eigenschaften und ArrayElemente lesen und schreiben, JavaScript-Methoden aufrufen und beliebige Strings mit JavaScript-Code auswerten und ausführen. Da JSObject eine Java-Klasse ist, müssen Sie natürlich etwas von Java-Programmierung verstehen, wenn Sie es nutzen möchten. Die Programmierung mit dem JSObject wird in Kapitel 23 genau erklärt.
Siehe auch Kapitel 12, Kapitel 23; JavaObject in Teil III
JSObject.call( )
Java-Methode in einem Java-Plug-in
Ruft eine Methode eines JavaScript-Objekts auf
Überblick public Object call(String methodenName, Object args[])
Referenz für clientseitiges JavaScript |
921
491-0.book Seite 922 Mittwoch, 4. April 2007 9:55 09
e-bol.net
JSObject.eval( )
Argumente methodenName
Der Name der aufzurufenden JavaScript-Methode. args[]
Ein Array von Java-Objekten, die der Methode als Argumente übergeben werden. Rückgabewert Ein Java-Objekt, das den Rückgabewert der JavaScript-Methode repräsentiert.
Beschreibung Die Methode call() der Java-Klasse JSObject ruft eine benannte Methode des vom JSObject dargestellten JavaScript-Objekts auf. Die Argumente werden als Array von Java-Objekten an die Methode übergeben, und der Rückgabewert der JavaScript-Methode wird als Java-Objekt geliefert. Kapitel 23 beschreibt, wie die Methodenargumente von Java-Objekten in JavaScript-Werte und der Rückgabewert der Methode von einem JavaScript-Wert wieder zurück in ein JavaObjekt konvertiert werden.
JSObject.eval( )
Java-Methode in einem Java-Plug-in
Wertet einen String mit JavaScript-Code aus
Überblick public Object eval(String s)
Argumente s Ein String mit beliebigen, durch Semikola getrennten JavaScript-Anweisungen. Rückgabewert Der JavaScript-Wert des letzten, in s ausgewerteten Ausdrucks, konvertiert in ein Java-Objekt.
Beschreibung Die eval()-Methode der Java-Klasse JSObject wertet den im String s enthaltenen JavaScriptCode im Kontext des JavaScript-Objekts aus, das für das JSObject steht. Diese Methode verhält sich ganz ähnlich wie die globale JavaScript-Funktion eval(). Das Argument s kann beliebig viele, durch Semikola getrennte JavaScript-Anweisungen enthalten. Diese Anweisungen werden in der Reihenfolge ihres Auftretens abgearbeitet. Der Rückgabewert von eval() ist der Wert der letzten Anweisung oder des letzten Ausdrucks in s.
922 | Referenz für clientseitiges JavaScript
491-0.book Seite 923 Mittwoch, 4. April 2007 9:55 09
e-bol.net
JSObject.getMember( )
JSObject.getMember( )
Java-Methode in einem Java-Plug-in
Liest eine Eigenschaft eines JavaScript-Objekts
Überblick public Object getMember(String name)
Argumente name
Der Name der zu lesenden Eigenschaft. Rückgabewert Ein Java-Objekt, das den Wert der angegebenen Eigenschaft des betroffenen JSObject enthält.
Beschreibung
JSObject.getSlot( )
Java-Methode in einem Java-Plug-in
Liest ein Array-Element eines JavaScript-Objekts
Überblick public Object getSlot(int index)
Argumente index
Der Index des zu lesenden Array-Elements. Rückgabewert Der Wert des Array-Elements eines JavaScript-Objekts mit dem angegebenen index.
Beschreibung Die Methode getSlot() der Java-Klasse JSObject liest den Wert eines Array-Elements mit dem angegebenen index für ein JavaScript-Objekt und liefert ihn an Java zurück. Der Rückgabewert kann ein anderes JSObject oder ein Double-, Boolean- oder String-Objekt sein. Er wird aber als generisches Object geliefert, das Sie unter Umständen konvertieren müssen.
Referenz für clientseitiges JavaScript |
923
Referenz für clientseitiges JavaScript
Die Methode getMember() der Java-Klasse JSObject liest den Wert einer angegebenen Eigenschaft eines JavaScript-Objekts und liefert ihn an Java zurück. Der Rückgabewert kann ein anderes JSObject oder ein Double-, Boolean- oder String-Objekt sein. Er wird aber als generisches Object geliefert, das Sie unter Umständen konvertieren müssen.
491-0.book Seite 924 Mittwoch, 4. April 2007 9:55 09
e-bol.net
JSObject.getWindow( )
JSObject.getWindow( )
Java-Methode in einem Java-Plug-in
Gibt ein erstes JSObject eines Browserfensters zurück
Überblick public static JSObject getWindow(java.applet.Applet applet)
Argumente applet
Ein Applet-Objekt, das in dem Webbrowserfenster läuft, für das man ein JSObject erhalten möchte. Rückgabewert Ein JSObject, das das JavaScript-Window-Objekt des Webbrowserfensters repräsentiert, das das angegebene applet enthält.
Beschreibung Die Methode getWindow() ist die erste JSObject-Methode, die jedes Java-Applet aufruft. JSObject definiert keinen Konstruktor, und die statische Methode getWindow() ist die einzige Möglichkeit, ein erstes JSObject zu erhalten, von dem dann weitere JSObject-Objekte beschafft werden können.
JSObject.removeMember( )
Java-Methode in einem Java-Plug-in
Löscht eine Eigenschaft eines JavaScript-Objekts
Überblick public void removeMember(String name)
Argumente name
Der Name der Eigenschaft, die aus dem JSObject gelöscht werden soll.
Beschreibung Die Methode removeMember() der Java-Klasse JSObject löscht eine benannte Eigenschaft aus dem von diesem JSObject dargestellten JavaScript-Objekt.
JSObject.setMember( ) Setzt eine Eigenschaft eines JavaScript-Objekts
Überblick public void setMember(String name, Object wert)
924 | Referenz für clientseitiges JavaScript
Java-Methode in einem Java-Plug-in
491-0.book Seite 925 Mittwoch, 4. April 2007 9:55 09
e-bol.net
JSObject.setSlot( )
Argumente name
Der Name der Eigenschaft, die im JSObject gesetzt werden soll. wert
Der Wert, auf den die benannte Eigenschaft gesetzt werden soll.
Beschreibung Die Methode setMember() der Java-Klasse JSObject setzt den Wert einer benannten Eigenschaft eines JavaScript-Objekts von Java aus. Der angegebene wert kann ein beliebiges JavaObjekt sein. Elementare Java-Werte dürfen dieser Methode nicht übergeben werden. In JavaScript kann der angegebene wert als JavaObject-Objekt angesprochen werden.
JSObject.setSlot( )
Java-Methode in einem Java-Plug-in
Setzt ein Array-Element eines JavaScript-Objekts Referenz für clientseitiges JavaScript
Überblick public void setSlot(int index, Object wert)
Argumente index
Der Index des Array-Elements, das in dem JSObject gesetzt werden soll. wert
Der Wert, auf den es gesetzt werden soll.
Beschreibung Die Methode setSlot() der Java-Klasse JSObject setzt den Wert eines numerierten ArrayElements eines JavaScript-Objekts von Java aus. Der angegebene wert kann ein beliebiges JavaObjekt sein. Elementare Java-Werte dürfen dieser Methode nicht übergeben werden. In JavaScript kann der angegebene wert als JavaObject-Objekt angesprochen werden.
JSObject.toString( )
Java-Methode in einem Java-Plug-in
Gibt den Stringwert eines JavaScript-Objekts zurück
Überblick public String toString( )
Rückgabewert Der String, den ein Aufruf der toString()-Methode des JavaScript-Objekts zurückgibt, das durch das angegebene Java-Objekt JSObject repräsentiert wird.
Referenz für clientseitiges JavaScript |
925
491-0.book Seite 926 Mittwoch, 4. April 2007 9:55 09
e-bol.net
KeyEvent
Beschreibung Die Methode toString() der Java-Klasse JSObject ruft die JavaScript-Methode toString() des JavaScript-Objekts auf, das durch das angegebene JSObject repräsentiert wird, und liefert ihr Ergebnis zurück.
KeyEvent Einzelheiten über ein Tastatur-Event
Firefox und kompatible Browser Event ➝ UIEvent ➝ KeyEvent
Eigenschaften readonly boolean altKey
Gibt an, ob beim Eintreten des Events die Alt-Taste gedrückt war. readonly integer charCode
Diese Zahl ist die Unicode-Codierung des druckbaren Zeichens (soweit vorhanden), das durch ein Tastatur-Event erzeugt wurde. Diese Eigenschaft ist null für nicht-druckende Funktionstasten und wird nicht für keydown- und keyup-Events verwendet. Verwenden Sie String.fromCharCode( ), um diese Eigenschaft in einen String zu konvertieren. readonly boolean ctrlKey
Gibt an, ob beim Eintreten des Events die Strg-Taste gedrückt war. Ist für alle Arten von Maus-Events definiert. readonly integer keyCode
Der virtuelle Tastencode der gedrückten Taste. Diese Eigenschaft wird für alle Arten von Tastatur-Events verwendet. Tastencodes können sich je nach Browser, Betriebssystem und Tastatur voneinander unterscheiden. Wenn auf einer Taste ein druckbares Zeichen steht, ist der virtuelle Tastencode für diese Taste in der Regel der gleiche wie der Zeichencode. Tastencodes für nicht-druckbare Funktionstasten können sich stärker voneinander unterscheiden. Eine Liste häufig verwendeter Codes finden Sie unter Beispiel 17-6. readonly boolean shiftKey
Gibt an, ob beim Eintreten des Events die Umschalt-Taste gedrückt war. Ist für alle Arten von Maus-Events definiert.
Beschreibung Ein KeyEvent-Objekt stellt Einzelheiten zu einem Tastatur-Event zur Verfügung und wird an Event-Handler für die keydown-, keypress- und keyup-Events übergeben. Der DOM Level 2Event-Standard deckt Tastatur-Events nicht ab, und das KeyEvent-Objekt ist bisher nicht standardisiert. Dieser Eintrag beschreibt die Firefox-Implementierung. Vieler dieser Eigenschaften werden auch im IE-Event-Modell unterstützt; vergleichen Sie die für das Objekt Event beschriebenen IE-spezifischen Eigenschaften. Beachten Sie, dass KeyEvent-Objekte nicht nur die hier aufgeführten Eigenschaften definieren, sondern auch die Eigenschaften der Interfaces UIEvent und Event erben. Kapitel 17 enthält mehrere praktische Beispiele zum Arbeiten mit KeyEvent-Objekten.
926 | Referenz für clientseitiges JavaScript
491-0.book Seite 927 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Layer
Siehe auch Event, UIEvent; Kapitel 17
Layer
nur in Netscape 4; in Netscape 6 abgeschafft
Eine veraltete Netscape-API
Beschreibung Das Layer-Objekt war das Verfahren, mit dem Netscape 4 dynamisch positionierbare HTMLElemente unterstützte. Es wurde nie standardisiert und ist inzwischen überholt.
Siehe auch Kapitel 16
Ein Hyperlink oder Anker in einem HTML-Dokument
DOM Level 0 Node ➝ Element ➝ HTMLElement ➝ Link
Eigenschaften Die wichtigste Eigenschaft eines Links ist sein href-Attribut, also die URL, zu der der Link weiterleitet. Außerdem definiert das Link-Objekt eine Anzahl anderer Eigenschaften, die Teile der URL enthalten. Für jede dieser Eigenschaften wird im Beispiel ein Teil der folgenden (fiktiven) URL angegeben: http://www.oreilly.de:1234/katalog/suche.html?q=JavaScript&m=10#ergebnis String hash
Gibt den Ankerteil der URL des Links an, einschließlich des vorangestellten Rautezeichens (#), wie z.B. bei »#results«. Dieser Ankerteil einer URL bezieht sich auf eine namentlich angegebene Position in dem durch den Link referenzierten Dokument. In HTML-Dateien werden Positionen mit dem Attribut name des Tags benannt (siehe Anchor). String host
Gibt den Hostnamen und Port aus der URL eines Links an, z.B. »www.oreilly.com:1234«. String hostname
Gibt den Hostnamen aus der URL eines Links an, z.B. »www.oreilly.com«. String href
Gibt den vollständigen Text aus der URL eines Links an – anders als andere Link-URLEigenschaften, die nur Teile der URL angeben. String pathname
Gibt den Pfadnamen aus der URL eines Links an, z.B. »/catalog/search.html«. String port
Gibt den Port aus der URL eines Links an, z.B. »1234«.
Referenz für clientseitiges JavaScript |
927
Referenz für clientseitiges JavaScript
Link
491-0.book Seite 928 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Link String protocol
Gibt den Protokollteil aus der URL eines Links einschließlich des Doppelpunkts an, z.B. »http:«. String search
Gibt den Abfragestring aus der URL eines Links an, einschließlich des Fragezeichens am Anfang, z.B. »?q=JavaScript&m=10«. Zusätzlich zu diesen URL-bezogenen Eigenschaften definieren Link-Objekte auch Eigenschaften, die den Attributen für die HTML-Tags und entsprechen: Eigenschaft
Attribut
Beschreibung
String accessKey
accesskey
Tastatur-Shortcut
String charset
charset
Codierung des Zieldokuments
String coords
coords
Für -Tags
String hreflang
hreflang
Sprache des verknüpften Dokuments
String name
name
Ankername; siehe Anchor
String rel
rel
Link-Typ
String rev
rev
Typ des Umkehr-Links
String shape
shape
Für -Tags
long tabIndex
tabindex
Position des Links in der Tab-Folge
String target
target
Name des Frames oder Fensters, in dem das Zieldokument angezeigt werden soll
String type
type
Inhaltstyp des Zieldokuments
Methoden blur( )
Entzieht dem Link den Tastaturfokus. focus( )
Scrollt das Dokument so, dass der Anker oder Link sichtbar wird, und gibt dem Link den Tastaturfokus.
Event-Handler Das Link-Objekt hat bei drei Event-Handlern ein spezielles Verhalten: onclick
Wird aufgerufen, wenn der Benutzer auf den Link klickt. onmouseout
Wird aufgerufen, wenn der Benutzer die Maus vom Link wegbewegt. onmouseover
Wird aufgerufen, wenn der Benutzer die Maus über den Link zieht.
928 | Referenz für clientseitiges JavaScript
491-0.book Seite 929 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Link.blur( )
HTML-Syntax Ein Link-Objekt wird mit den Standard-Tags und erzeugt. Das Attribut href ist für alle Link-Objekte erforderlich. Wenn überdies das name-Attribut angegeben ist, wird außerdem ein Anchor-Objekt erzeugt: Linktext oder Bild
// // // // // // //
Die Ziel-URL des Links Erzeugt ein Anker-Objekt Hier soll das neue Dokument angezeigt werden Aufruf, wenn der Link angeklickt wird Aufruf, wenn die Maus auf dem Link ist Aufruf, wenn die Maus den Link verlässt Der sichtbare Teil des Links
Beschreibung
Alle mit den Tags und erzeugten Links werden durch Link-Objekte dargestellt und im links[]-Array des Document-Objekts gespeichert. Natürlich ist das Ziel eines Hypertext-Links eine URL, und viele der Eigenschaften des LinkObjekts spezifizieren den Inhalt dieser URL. In dieser Hinsicht gleicht das Link-Objekt dem Location-Objekt, das ebenfalls diverse URL-Eigenschaften hat.
Beispiel // Hole die Ziel-URL des ersten Hyperlinks im Dokument var url = document.links[0].href;
Siehe auch Anchor, Location
Link.blur( )
DOM Level 0
Entzieht einem Hyperlink den Tastaturfokus
Überblick void blur( );
Beschreibung In Webbrowsern, bei denen Hyperlinks den Tastaturfokus haben können, entzieht diese Methode dem Hyperlink den Tastaturfokus wieder.
Referenz für clientseitiges JavaScript |
929
Referenz für clientseitiges JavaScript
In einem Dokument stellt ein Link-Objekt einen Hyperlink dar. Links werden in der Regel mit -Tags erzeugt, die ein href-Attribut definiert haben. Innerhalb einer clientseitigen Imagemap können sie aber auch mit -Tags erzeugt werden. Hat ein -Tag statt eines href-Attributs ein name-Attribut, so definiert es eine benannte Position in einem Dokument und wird nicht von einem Link-Objekt dargestellt, sondern von einem Anchor-Objekt. Einzelheiten entnehmen Sie bitte Anchor.
491-0.book Seite 930 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Link.focus( )
Link.focus( )
DOM Level 0
Lässt einen Link sichtbar werden und gibt ihm den Tastaturfokus
Überblick void focus( );
Beschreibung Diese Methode scrollt das Dokument so, dass der angegebene Hyperlink sichtbar wird. Wenn der Browser zulässt, dass Links den Tastaturfokus haben können, gibt diese Methode dem Link den Tastaturfokus.
Link.onclick
DOM Level 0
Dieser Event-Handler wird aufgerufen, wenn ein Link angeklickt wird
Überblick Function onclick
Beschreibung Die Eigenschaft onclick eines Link-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer auf den Link klickt. Nachdem der Event-Handler ausgeführt worden ist, folgt der Browser als Standardaktion dem angeklickten Hyperlink. Sie können diese Standardaktion unterbinden, indem Sie false zurückgeben oder indem Sie die anderen Techniken zum Abbrechen von Events verwenden, die in Kapitel 17 beschrieben werden.
Siehe auch Element.addEventListener( ), MouseEvent; Kapitel 17
Link.onmouseout
DOM Level 0
Dieser Event-Handler wird aufgerufen, wenn die Maus einen Link verlässt
Überblick Function onmouseout
Beschreibung Die Eigenschaft onmouseout eines Link-Objekts gibt eine Event-Handler-Funktion an, die aufgerufen wird, wenn der Benutzer die Maus von einem Hypertext-Link wegbewegt. Sie wird oft in Kombination mit dem Event-Handler onmouseover verwendet.
Siehe auch Element.addEventListener( ), Link.onmouseover, MouseEvent; Kapitel 17
930 | Referenz für clientseitiges JavaScript
491-0.book Seite 931 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Link.onmouseover
Link.onmouseover
DOM Level 0
Dieser Event-Handler wird aufgerufen, wenn sich die Maus über einen Link bewegt
Überblick Function onmouseover
Beschreibung Die Eigenschaft onmouseover eines Link-Objekts gibt eine Event-Handler-Funktion an, aufgerufen wird, wenn der Benutzer die Maus über einen Hypertext-Link bewegt. Hält Benutzer die Maus über den Hyperlink, so zeigt der Browser die URL für diesen Link in Statuszeile an. Bei alten Browsern kann statt dieser Standardaktion Ihr eigener Text in Statuszeile angezeigt werden. Aus Sicherheitsgründen (z.B., um Phishing-Attacken vermeiden) haben die meisten modernen Browser diese Funktionalität deaktiviert.
die der der der zu
Siehe auch
Location
JavaScript 1.0 Object ➝ Location
Repräsentiert und steuert die vom Browser angezeigte Webadresse
Überblick location window.location
Eigenschaften Die Eigenschaften eines Location-Objekts betreffen die diversen Teile der URL des aktuellen Dokuments. In den folgenden Eigenschaftsbeschreibungen bezieht sich das jeweilige Beispiel auf einen Teil der folgenden (fiktiven) URL: http://www.oreilly.de:1234/katalog/suche.html?q=JavaScript&m=10#ergebnis
hash
Eine les- und schreibbare String-Eigenschaft, die den Ankerteil der Link-URL des betreffenden Links angibt, einschließlich des Rautezeichens # am Anfang, z.B. »#results«. Dieser Teil der Dokument-URL gibt den Namen eines Ankers im Dokument an. host
Eine les- und schreibbare String-Eigenschaft, die den Hostnamen und Port der URL angibt, z.B. »www.oreilly.com:1234«. hostname
Eine les- und schreibbare String-Eigenschaft, die den Hostnamen einer URL angibt, z.B. »www.oreilly.com«. href
Eine les- und schreibbare String-Eigenschaft, die den vollständigen Text der DokumentURL angibt und sich dadurch von den anderen Location-Eigenschaften unterscheidet, die
491-0.book Seite 932 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Location
jeweils nur Teile der URL enthalten. Wenn Sie diese Eigenschaft auf eine neue URL setzen, liest und zeigt der Browser den Inhalt dieser neuen URL. pathname
Eine les- und schreibbare String-Eigenschaft, die den Pfadnamen einer URL angibt, z.B. »/catalog/search.html«. port
Eine les- und schreibbare String-Eigenschaft (nicht numerisch), die den Port aus der URL eines Links angibt, z.B. »1234«. protocol
Eine les- und schreibbare String-Eigenschaft, die den Protokollteil aus der URL eines Links angibt, einschließlich des Doppelpunkts am Ende, z.B. »http:«. search
Eine les- und schreibbare String-Eigenschaft, die den Abfragestring einer URL angibt, einschließlich des vorangehenden Fragezeichens, z.B. »?q=JavaScript&m=10«.
Methoden reload( )
Lädt das aktuelle Dokument aus dem Cache oder vom Server. replace( )
Ersetzt das aktuelle Dokument durch ein neues, ohne einen neuen Eintrag in der SessionHistory des Browsers zu erzeugen.
Beschreibung Die Eigenschaft location des Window-Objekts bezieht sich auf das Location-Objekt. Dieses repräsentiert die Webadresse (»Location«) des Dokuments, das gerade im Fenster angezeigt wird. Die Eigenschaft href enthält die vollständige URL des Dokuments, und die anderen Eigenschaften des Location-Objekts beschreiben jeweils einen Teil dieser URL. Diese Eigenschaften ähneln den URL-Eigenschaften des Link-Objekts. Wird das Location-Objekt in einen String konvertiert, wird der Wert der Eigenschaft href zurückgegeben. Sie können also statt location.href auch location verwenden. Während das Link-Objekt einen Hyperlink in einem Dokument repräsentiert, repräsentiert das Location-Objekt die URL, die der Browser gerade anzeigt. Das Location-Objekt kann aber noch mehr: Es steuert auch die vom Browser angezeigte Webadresse. Wenn Sie dem LocationObjekt oder seiner href-Eigenschaft einen String mit einer URL zuweisen, lädt der Webbrowser diese neue URL und zeigt das Dokument an, auf das sie verweist. Anstatt location oder location.href zu setzen und die aktuelle URL durch eine ganz andere zu ersetzen, können Sie auch lediglich einen Teil der aktuellen URL modifizieren, indem Sie den anderen Eigenschaften des Location-Objekts Strings zuweisen. Dadurch entsteht eine neue URL, bei der ein Teil anders ist und die der Browser dann lädt und anzeigt. Indem Sie z.B. die hash-Eigenschaft des Location-Objekts setzen, veranlassen Sie den Browser, zu einer bezeichneten Stelle im aktuellen Dokument zu gehen, und indem Sie die search-Eigenschaft setzen, veranlassen Sie ihn, die aktuelle URL mit einem neuen Abfrage-String neu zu laden.
932 | Referenz für clientseitiges JavaScript
491-0.book Seite 933 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Location.reload( )
Das Location-Objekt definiert neben seinen URL-Eigenschaften auch zwei Methoden. Die Methode reload( ) lädt das gerade angezeigte Dokument neu. Die Methode replace( ) lädt ein neues Dokument, ohne ihm einen neuen Eintrag in der Browser-History zu geben. Das neue Dokument ersetzt das derzeitige in der History-Liste des Browsers.
Siehe auch Link, die Eigenschaft URL des Objekts HTMLDocument
Ein optionales Boolesches Argument, das festlegt, ob das Dokument auch dann neu geladen werden soll, wenn der Server berichtet, dass es sich seit dem letzten Ladevorgang nicht mehr geändert hat. Wenn dieses Argument weggelassen wird oder false ist, lädt die Methode die vollständige Seite nur dann neu, wenn sie sich geändert hat, seit sie das letzte Mal geladen wurde.
Beschreibung Die Methode reload() des Location-Objekts lädt das Dokument neu, das zurzeit im Fenster des Location-Objekts angezeigt wird. Wenn Sie sie ohne Argumente oder mit dem Argument false aufrufen, ermittelt sie anhand des HTTP-Headers If-Modified-Since, ob das Dokument auf dem Webserver geändert wurde. Wenn ja, wird das Dokument vom Server neu geladen; wenn nein, wird es aus dem Cache geladen. Dasselbe geschieht, wenn der Benutzer auf den Neu Laden-Button des Browsers klickt. Wird die Methode reload() mit dem Argument true aufgerufen, so lädt sie das Dokument auf jeden Fall vom Server und nicht aus dem Cache, ohne das letzte Änderungsdatum zu berücksichtigen. Dasselbe geschieht, wenn der Benutzer bei gedrückter Umschalt-Taste auf den Neu Laden-Button des Browsers klickt.
Location.replace( )
JavaScript 1.1
Ersetzt ein angezeigtes Dokument durch ein anderes
Überblick location.replace(url)
Referenz für clientseitiges JavaScript |
933
Referenz für clientseitiges JavaScript
Argumente
491-0.book Seite 934 Mittwoch, 4. April 2007 9:55 09
e-bol.net
MimeType
Argumente url
Ein String mit der URL des neuen Dokuments, das das aktuelle ersetzen soll.
Beschreibung Die replace()-Methode des Location-Objekts lädt ein neues Dokument und zeigt es an. Diese Art, ein Dokument zu laden, unterscheidet sich in einer wichtigen Hinsicht vom einfachen Neueinstellen von location oder location.href: Die Methode replace( ) generiert keinen neuen Eintrag im History-Objekt. Wenn Sie replace() verwenden, überschreibt die neue URL den aktuellen Eintrag im History-Objekt. Nach dem Aufruf von replace( ) gibt der Zurück-Button des Browsers nicht die letzte, sondern die vorletzte URL zurück.
Siehe auch History
MimeType Repräsentiert einen MIME-Datentyp
JavaScript 1.1; von IE nicht unterstützt Object ➝ MimeType
Ein schreibgeschützter String, der eine für Menschen lesbare (englischsprachige) Beschreibung des Datentyps liefert, der vom MimeType beschrieben wird. enabledPlugin
Eine schreibgeschützte Referenz auf ein Plug-in-Objekt, das das installierte und aktivierte Plug-in für den angegebenen MIME-Typ darstellt. Wird der MIME-Typ von keinen Plugins verarbeitet (beispielsweise, weil er direkt vom Browser verarbeitet wird), dann ist der Wert dieser Eigenschaft null. Die Eigenschaft ist ebenfalls null, wenn ein Plug-in vorhanden ist, aber deaktiviert wurde. suffixes
Ein schreibgeschützter String mit einer durch Kommata getrennten Liste von Dateinamenserweiterungen (ohne das Zeichen ».« ), die oft für Dateien des betreffenden MIMETyps verwendet werden. Beispiele sind die Erweiterungen »html, htm« für den MIME-Typ »text/html«. type
Ein schreibgeschützter String, der den Namen des MIME-Typs angibt. Es handelt sich um einen eindeutigen String wie z.B. »text/html« oder »image/jpeg«, der den MIME-Typ von allen anderen unterscheidet. Er beschreibt den allgemeinen Datentyp und das verwendete Datenformat. Der Wert der Eigenschaft type kann auch als Index für den Zugriff auf Elemente des Arrays navigator.mimeTypes[] genutzt werden.
934 | Referenz für clientseitiges JavaScript
491-0.book Seite 935 Mittwoch, 4. April 2007 9:55 09
e-bol.net
MouseEvent
Beschreibung Das MimeType-Objekt repräsentiert einen MIME-Typ (also ein Datenformat), der von einem Webbrowser unterstützt wird. Das Format wird entweder direkt vom Browser oder über eine externe Hilfsanwendung oder ein Plug-in für eingebettete Daten unterstützt. MimeTypeObjekte gehören zum Array mimeTypes[]des Navigator-Objekts. Bei IE ist das Array mimeTypes[] immer leer, und es gibt kein Äquivalent zu dieser Funktionalität.
Verwendung Das Array navigator.mimeTypes[] kann entweder mit Zahlen oder mit dem Namen des gewünschten MIME-Typs (dem Namen der type-Eigenschaft) indiziert werden. Um festzustellen, welche MIME-Typen von einem Browser unterstützt werden, können Sie die Elemente des Arrays in numerischer Reihenfolge durchlaufen. Wenn Sie nur wissen möchten, ob ein spezieller Typ unterstützt wird, können Sie auch so etwas wie den folgenden Ausdruck verwenden: var show_movie = (navigator.mimeTypes["video/mpeg"] != null);
Referenz für clientseitiges JavaScript
Siehe auch Navigator, Plugin
MouseEvent Einzelheiten über ein Maus-Event
DOM Level 2 Events Event ➝ UIEvent ➝ MouseEvent
Eigenschaften readonly boolean altKey
Gibt an, ob beim Eintreten des Events die Alt-Taste gedrückt war. Ist für alle Arten von Maus-Events definiert. readonly unsigned short button
Gibt an, welche Maustaste während eines mousedown-, mouseup- oder click-Events ihren Zustand änderte. Der Wert 0 zeigt einen Klick auf die linke Maustaste an, der Wert 2 einen Klick auf die rechte Maustaste und der Wert 1 einen Klick auf die mittlere Maustaste. Beachten Sie, dass diese Eigenschaft definiert ist, um anzugeben, wenn eine Taste ihren Zustand ändert, und nicht, um anzugeben, ob eine Taste während eines mousemoveEvents gedrückt gehalten wird. Überdies ist diese Eigenschaft keine Bitmap: Sie kann Ihnen nicht sagen, ob mehr als eine Maustaste gleichzeitig gedrückt werden. readonly long clientX, clientY
Die X- und Y-Koordinaten des Mauszeigers in Bezug auf die Client Area oder das Browserfenster. Beachten Sie, dass diese Koordinaten nicht das Scrollen eines Dokuments anzeigen. Wenn ein Event ganz oben im Fenster eintritt, ist clientY 0, egal wie weit das Dokument zwischenzeitlich nach unten gescrollt wurde. Diese Eigenschaften sind für alle Arten von Maus-Events definiert.
Referenz für clientseitiges JavaScript |
935
491-0.book Seite 936 Mittwoch, 4. April 2007 9:55 09
Gibt an, ob beim Eintreten des Events die Strg-Taste gedrückt war. Ist für alle Arten von Maus-Events definiert. readonly boolean metaKey
Gibt an, ob beim Eintreten des Events die Alt-Taste gedrückt war. Ist für alle Arten von Maus-Events definiert. readonly Element relatedTarget
Bezieht sich auf ein Element, das mit dem target-Knoten des Events in Zusammenhang steht. Bei mouseover-Events ist dies das Element, das die Maus verließ, als sie zum targetKnoten bewegt wurde. Bei mouseout-Events ist es das Element, das betreten wird, wenn der target-Knoten wieder verlassen wird. relatedTarget ist für andere Arten von Maus-Events nicht definiert. readonly long screenX, screenY
Die X- und Y-Koordinaten des Mauszeigers relativ zur oberen linken Ecke des Benutzerbildschirms. Diese Eigenschaften sind für alle Arten von Maus-Events definiert. readonly boolean shiftKey
Gibt an, ob beim Eintreten des Events die Umschalt-Taste gedrückt war. Ist für alle Arten von Maus-Events definiert.
Methoden initMouseEvent( )
Initialisiert die Eigenschaften eines neu erzeugten MouseEvent-Objekts.
Beschreibung Dieses Interface definiert die Art von Event-Objekt, die an Events der Typen click, mousedown, mousemove, mouseout, mouseover und mouseup übergeben wird. Beachten Sie, dass dieses Interface nicht nur die hier aufgeführten Eigenschaften definiert, sondern auch die Eigenschaften der Interfaces UIEvent und Event erbt.
Siehe auch Event, UIEvent; Kapitel 17
MouseEvent.initMouseEvent( ) Initialisiert die Eigenschaften eines MouseEvent-Objekts
491-0.book Seite 937 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Navigator long detailArg, long screenXArg, long screenYArg, long clientXArg, long clientYArg, boolean ctrlKeyArg, boolean altKeyArg, boolean shiftKeyArg, boolean metaKeyArg, unsigned short buttonArg, Element zielArg);
Argumente Die vielen Argumente dieser Methode geben die Anfangswerte der Eigenschaften dieses MouseEvent-Objekts an, darunter auch die Eigenschaften, die von den Interfaces Event und UIEvent geerbt wurden. Der Name jedes Arguments sagt ganz klar, für welche Eigenschaft es den Wert angibt. Daher werden die Argumente hier nicht einzeln aufgeführt.
Diese Methode initialisiert die verschiedenen Eigenschaften eines neu erzeugten MouseEventObjekts. Sie kann nur auf einem MouseEvent-Objekt aufgerufen werden, das mit Document. createEvent() erzeugt wurde, und das nur so lange, bis das betreffende MouseEvent an Element.dispatchEvent() übergeben wird.
Siehe auch Document.createEvent( ), Event.initEvent( ), UIEvent.initUIEvent( )
Navigator Informationen über den verwendeten Browser
JavaScript 1.0 Object ➝ Navigator
Überblick navigator
Eigenschaften appCodeName
Ein schreibgeschützter String, der den Codenamen des Browsers angibt. In allen Browsern, die auf der Netscape-Codebase beruhen (Netscape, Mozilla, Firefox), ist dieser String »Mozilla«, ein Name, der aus Kompatibilitätsgründen auch von allen Microsoft-Browsern verwendet wird. appName
Eine schreibgeschützte String-Eigenschaft, die den Browser-Namen angibt. Bei Browsern, die auf Netscape basieren, ist der Wert dieser Eigenschaft »Netscape«; beim IE ist er »Microsoft Internet Explorer«. Andere Browser identifizieren sich eventuell richtig oder imitieren aus Kompatibilitätsgründen einen anderen Browser.
Referenz für clientseitiges JavaScript |
937
Referenz für clientseitiges JavaScript
Beschreibung
491-0.book Seite 938 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Navigator appVersion
Ein schreibgeschützter String, der die Versions- und Plattforminformationen für den Browser angibt. Der erste Teil dieses Strings ist eine Versionsnummer. Wenn Sie ihn an parseInt() übergeben, erhalten Sie nur die übergeordnete Versionsnummer, und wenn Sie ihn an parseFloat() übergeben, erhalten Sie die über- und die untergeordnete Versionsnummer als Gleitkommawert. Der Rest des Stringwertes dieser Eigenschaft gibt weitere Einzelheiten bezüglich der Browserversion an, darunter auch das Betriebssystem, auf dem der Browser läuft. Leider hängt das Format dieser Informationen sehr stark davon ab, welcher Browser verwendet wird. cookieEnabled
Dieser schreibgeschützte Boolesche Wert ist true, wenn der Browser Cookies aktiviert hat, und false, wenn er sie deaktiviert hat. mimeTypes[]
Ein Array von MimeType-Objekten, von denen jedes einen der vom Browser unterstützten MIME-Typen repräsentiert (z.B. »text/html« und »image/gif«). Dieses Array kann numerisch oder über den Namen des MIME-Typs indiziert werden. Das Array mimeTypes[] ist im Internet Explorer zwar definiert, aber immer leer, da er das MimeTypeObjekt nicht unterstützt. platform
Ein schreibgeschützter String, der das Betriebssystem und/oder die Hardware-Plattform angibt, auf der der Browser läuft. Es gibt zwar keine standardisierten Werte für diese Eigenschaft, aber typisch sind z.B. Werte wie »Win32«, »MacPPC« und »Linux i586«. plugins[]
Ein Array von Plug-in-Objekten, die je ein mit dem Browser installiertes Plug-in darstellen. Das Plug-in-Objekt gibt Informationen über das Plug-in, einschließlich einer Liste der von ihm unterstützten MIME-Typen. Das Array plugins[] ist im Internet Explorer zwar definiert, aber immer leer, da er das Plug-in-Objekt nicht unterstützt. userAgent
Ein schreibgeschützter String mit dem Wert, den der Browser für den User-Agent-Header in HTTP-Anfragen verwendet. In der Regel ist dies der Wert von navigator.appCodeName, gefolgt von einem Schrägstrich und dem Wert von navigator.appVersion. Ein Beispiel: Mozilla/4.0 (kompatibel; MSIE 4.01; Windows 95)
Funktionen navigator.javaEnabled( )
Testet, ob der verwendete Browser Java unterstützt und ausführen kann.
Beschreibung Das Navigator-Objekt enthält Eigenschaften, die den verwendeten Webbrowser beschreiben. Mit diesen Eigenschaften können Sie plattformspezifische Anpassungen vornehmen. Der Name dieses Objekts bezieht sich natürlich auf den Netscape Navigator, aber alle Browser, die JavaScript implementieren, unterstützen dieses Objekt. Das Navigator-Objekt gibt es nur einmal. Diese Instanz können Sie mit der navigator-Eigenschaft jedes beliebigen Window-Objekts referenzieren.
938 | Referenz für clientseitiges JavaScript
491-0.book Seite 939 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Navigator.javaEnabled( )
In der Vergangenheit wurde das Navigator-Objekt zum »client sniffing« verwendet, um je nach verwendetem Browser unterschiedlichen Code laufen zu lassen. Beispiel 14-3 zeigt eine einfache Methode, das zu machen. Der begleitende Text beschreibt die vielen Fallen, die entstehen, wenn man sich auf das Navigator-Objekt verlässt. Eine bessere Vorgehensweise zum Erreichen von Kompatibilität zwischen Browsern wird in Abschnitt 13.6.3 beschreiben.
Siehe auch MimeType, Plugin
Navigator.javaEnabled( )
JavaScript 1.1
Testet, ob Java zur Verfügung steht
Überblick navigator.javaEnabled( )
true, wenn Java vom aktuellen Browser unterstützt wird und darin auch aktiviert ist, andernfalls false.
Beschreibung Mit navigator.javaEnabled() können Sie prüfen, ob der verwendete Browser Java unterstützt und somit auch Applets darstellen kann.
Konstanten Alle Node-Objekte implementieren eines der oben genannten Subinterfaces. Jedes Node-Objekt hat eine nodeType-Eigenschaft, die angibt, welches der Subinterfaces es implementiert. Diese Konstanten sind die für diese Eigenschaft zulässigen Werte; ihre Namen sind selbsterklärend. Denken Sie daran, dass es sich dabei um statische Eigenschaften der Konstruktorfunktion Node( ) handelt und nicht um Eigenschaften von einzelnen Node-Objekten. Beachten Sie außerdem, dass sie von Internet Explorer nicht unterstützt werden. Um Kompatibilität mit IE zu erreichen, müssen Sie direkt die numerischen Äquivalente verwenden.
Referenz für clientseitiges JavaScript |
939
Referenz für clientseitiges JavaScript
Rückgabewert
491-0.book Seite 940 Mittwoch, 4. April 2007 9:55 09
Element Attr Text CDATASection Verarbeitungsanweisungen Kommentar Dokument DocumentType DocumentFragment
Eigenschaften readonly Attr[] attributes
Handelt es sich dabei um einen Element-Knoten, dann ist die Eigenschaft attributes ein schreibgeschütztes, Array-ähnliches Objekt von Attr-Knoten, die die Attribute dieses Elements darstellt. Beachten Sie, dass dieses Array »live« ist: Änderungen an den Attributen dieses Elements werden über das Array sofort sichtbar. Technisch gesehen ist das Array attributes[] ein NamedNodeMap-Objekt. Das NamedNodeMap-Interface wird im Level 1 DOM-Standard spezifiziert und definiert mehrere Methoden für das Abfragen, Setzen und Löschen von Elementen. Das ElementInterface definiert bessere Methoden zum Setzen und Abfragen von Element-Attributen, und NamedNodeMap hat keine anderen Anwendungen, die für JavaScript auf der Clientseite relevant sind. Aus diesen Gründen wird NamedNodeMap in diesem Buch nicht dokumentiert. Behandeln Sie die Eigenschaft attributes als schreibgeschütztes Array von Attr-Objekten, oder verwenden Sie die von Element definierten Methoden zum Abfragen, Setzen und Löschen von Attributen. readonly Node[] childNodes
Enthält die Kindknoten des aktuellen Knotens. Diese Eigenschaft sollte nie null sein: Bei Knoten ohne Kinder ist childNodes ein Array mit dem length-Wert null. Diese Eigenschaft ist technisch gesehen ein NodeList-Objekt, verhält sich aber genau wie ein schreibgeschütztes Array von Node-Objekten. Beachten Sie, dass das NodeList-Objekt live ist: Änderungen an der Liste von Kindelementen dieses Elements sind über die NodeList sofort sichtbar. readonly Node firstChild
Das erste Kind dieses Knotens oder null, wenn der Knoten keine Kinder hat. readonly Node lastChild
Das letzte Kind dieses Knotens oder null, wenn der Knoten keine Kinder hat. readonly String localName [DOM Level 2]
Gibt in XML-Dokumenten, die Namensräume verwenden, den lokalen Teil des Elementoder Attributnamens an. Diese Eigenschaft wird nie für HTML-Dokumente verwendet. Siehe auch die Eigenschaften namespaceURI und prefix. readonly String namespaceURI [DOM Level 2]
Gibt in XML-Dokumenten, die Namensräume verwenden, die URI des Namensraums eines Element- oder Attribut-Knotens an. Diese Eigenschaft wird nie für HTML-Dokumente verwendet. Siehe auch die Eigenschaften localName und prefix.
940 | Referenz für clientseitiges JavaScript
491-0.book Seite 941 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Node readonly Node nextSibling
Der Geschwisterknoten, der im childNodes[]-Array des parentNode unmittelbar auf diesen Knoten folgt, oder null, wenn kein solcher Knoten vorhanden ist. readonly String nodeName
Der Name des Knotens. Gibt bei Element-Knoten den Tag-Namen des Elements an, der auch mit der Eigenschaft tagName des Element-Interfaces abgerufen werden kann. Bei anderen Knotentypen hängt der Wert vom Typ ab. Einzelheiten finden Sie in der Tabelle im Abschnitt »Beschreibung«. readonly unsigned short nodeType
Der Knotentyp. Er gibt an, welches Subinterface der Knoten implementiert. Die zulässigen Werte finden Sie in der obigen Konstantenliste. Da der Internet Explorer diese Konstanten allerdings nicht unterstützt, sollten Sie eventuell die Werte fest eingeben. In HTML-Dokumenten sind die geläufigen Werte für diese Eigenschaft 1 für ElementKnoten, 3 für Textknoten, 8 für Kommentarknoten und 9 für den einen vorhandenen Toplevel-Document-Knoten. String nodeValue
readonly Document ownerDocument
Das Document-Objekt, zu dem dieser Knoten gehört. Bei Document-Knoten ist diese Eigenschaft null. readonly Node parentNode
Der Elternknoten (oder Container-Knoten) dieses Knotens oder null, wenn kein Elternknoten vorhanden ist. Beachten Sie, dass die Knoten Document, DocumentFragment und Attr nie Elternknoten haben. Knoten, die aus dem Dokument gelöscht oder neu erzeugt und noch nicht eingefügt wurden, haben einen parentNode mit dem Wert null. String prefix [DOM Level 2]
Gibt für XML-Dokumente, die Namensräume verwenden, das Namensraumpräfix des Element- oder Attribut-Knotens an. Diese Eigenschaft wird nie für HTML-Dokumente verwendet. Siehe auch die Eigenschaften localName und namespaceURL. readonly Node previousSibling
Der Geschwisterknoten, der diesem Knoten im childNodes[]-Array des parentNode unmittelbar vorausgeht, oder null, wenn kein solcher Knoten vorhanden ist. readonly String xml [nur IE]
Ist der Knoten ein XML-Dokument oder ein Element innerhalb eines XML-Dokuments, so gibt diese IE-spezifische Eigenschaft den Text des Elements oder Dokuments als String zurück. Vergleichen Sie diese Eigenschaft mit der Eigenschaft innerHTML von HTMLElement. Eine plattformübergreifende Alternative finden Sie unter XMLSerializer.
Referenz für clientseitiges JavaScript |
941
Referenz für clientseitiges JavaScript
Der Wert eines Knotens. Bei Textknoten enthält er den Textinhalt. Bei anderen Knotentypen hängt der Wert von nodeType ab, wie die Tabelle im Abschnitt »Beschreibung« zeigt.
491-0.book Seite 942 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Node
Methoden appendChild( )
Fügt dem Dokumentenbaum einen Knoten hinzu, indem sie ihn an das childNodes[]-Array dieses Knotens anhängt. Befindet sich der Knoten bereits im Dokumentenbaum, so wird er entfernt und dann an seiner neuen Position wieder eingefügt. cloneNode( )
Erstellt eine Kopie entweder nur dieses Knotens oder dieses Knotens und all seiner Nachfahren. hasAttributes( ) [DOM Level 2] Gibt true zurück, wenn dieser Knoten ein Element ist und Attribute hat. hasChildNodes( ) Gibt true zurück, wenn dieser Knoten Kinder hat. insertBefore( )
Fügt unmittelbar vor dem angegebenen Kind dieses Knotens einen Knoten in den Dokumentenbaum ein. Wenn der einzufügende Knoten bereits im Baum ist, wird er entfernt und an seinen neuen Platz gesetzt. isSupported( ) [DOM Level 2] Gibt true zurück, wenn dieser Knoten die angegebene Versionsnummer eines genannten
Features unterstützt. normalize( )
»Normalisiert« alle Text-Knoten-Nachfahren dieses Knotens, indem sie leere Text-Knoten löscht und benachbarte Text-Knoten verschmilzt. removeChild( )
Löscht (und liefert) den angegebenen Kindknoten aus dem Dokumentenbaum. replaceChild( )
Löscht (und liefert) den angegebenen Kindknoten aus dem Dokumentenbaum und ersetzt ihn durch einen anderen Knoten. selectNodes( ) [nur IE]
Diese IE-spezifische Methode führt eine XPath-Abfrage mit diesem Knoten als Wurzel aus und gibt das Ergebnis als eine NodeList zurück. DOM-basierte Alternativen finden Sie unter Document.evaluate( ) und Document.createExpression( ). selectSingleNode( ) [nur IE]
Diese IE-spezifische Methode führt eine XPath-Abfrage mit diesem Knoten als Wurzel aus und gibt das Ergebnis als einzelnen Knoten zurück. DOM-basierte Alternativen finden Sie unter Document.evaluate( ) und Document.createExpression( ). transformNode( ) [nur IE]
Diese IE-spezifische Methode wendet ein XSLT-Stylesheet auf diesen Knoten an und gibt die Ergebnisse als String zurück. Alternativen für andere Browser finden Sie unter XSLTProcessor. transformNodeToObject( ) [nur IE]
Diese IE-spezifische Methode wendet ein XSLT-Stylesheet auf diesen Knoten an und gibt die Ergebnisse als ein neues Document-Objekt zurück. Alternativen für andere Browser finden Sie unter XSLTProcessor.
942 | Referenz für clientseitiges JavaScript
491-0.book Seite 943 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Node
Beschreibung Alle Objekte in einem Dokumentenbaum (einschließlich des Document-Objekts selbst) implementieren das Node-Interface, das die wichtigsten Eigenschaften und Methoden zum Durchlaufen und Bearbeiten des Baums zur Verfügung stellt. (Im Internet Explorer definiert das Node-Interface zusätzlich einige IE-spezifische Eigenschaften und Methoden zum Arbeiten mit XML-Dokumenten, XPath-Ausdrücken und XSLT-Transformationen. Eine genaue Beschreibung finden Sie in Kapitel 21. Mit der Eigenschaft parentNode und dem Array childNodes[] können Sie sich im Dokumentenbaum nach oben und nach unten bewegen. Sie können die Kinder eines gegebenen Knotens aufzählen, indem Sie die Elemente von childNodes[] durchlaufen oder die Eigenschaften firstChild und nextSibling nutzen (oder die Eigenschaften lastChild und previousSibling, wenn die Schleife rückwärts gehen soll). Mit den Methoden appendChild(), insertBefore(), removeChild() und replaceChild() können Sie den Dokumentenbaum bearbeiten, indem Sie die Kinder eines Knotens ändern.
var n; // Speichert den Knoten, mit dem wir gerade arbeiten if (n.nodeType == 1) { // Oder verwende den konstanten Node.ELEMENT_NODE var tagname = n.tagName; // Ist der Knoten ein Element, so ist dies der Tag-Name }
Die Eigenschaften nodeName und nodeValue geben Zusatzinformationen über einen Knoten, doch ihr Wert hängt vom nodeType ab, wie die folgende Tabelle zeigt. Subinterfaces definieren normalerweise Spezialeigenschaften (z.B. die tagName-Eigenschaft von Element-Knoten oder die data-Eigenschaft von Text-Knoten), mit denen sich diese Informationen beschaffen lassen. nodeType
nodeName
nodeValue
ELEMENT_NODE
Der Tag-Name des Elements
null
ATTRIBUTE_NODE
Der Attributname
Der Attributwert
TEXT_NODE
#text
Der Text des Knotens
CDATA_SECTION_NODE
#cdata-section
Der Text des Knotens
PROCESSING_INSTRUCTION_ NODE
Das Ziel der PI
Der Rest der PI
COMMENT_NODE
#comment
Der Text des Kommentars
DOCUMENT_NODE
#document
null
DOCUMENT_TYPE_NODE
Der Name des Dokumenttyps
null
DOCUMENT_FRAGMENT_NODE
#document-fragment
null
Siehe auch Document, Element, Text, XMLSerializer, XPathExpression, XSLTProcessor; Kapitel 15
Referenz für clientseitiges JavaScript |
943
Referenz für clientseitiges JavaScript
Jedes Objekt in einem Dokumentenbaum implementiert das Node-Interface und noch ein spezielleres Subinterface wie z.B. Element oder Text. Die Eigenschaft nodeType gibt an, welches Subinterface ein Knoten implementiert. Mit dieser Eigenschaft können Sie den Typ eines Knotens testen, ehe Sie die Eigenschaften oder Methoden des spezielleren Interfaces nutzen. Ein Beispiel:
491-0.book Seite 944 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Node.appendChild( )
Node.appendChild( )
DOM Level 1 Core
Fügt einen Knoten als letztes Kind dieses Knotens ein
Der Knoten, der in das Dokument eingefügt werden soll. Wenn der Knoten ein DocumentFragment ist, wird nicht er selbst, sondern werden seine einzelnen Kinder eingefügt. Rückgabewert Der hinzugefügte Knoten. Exceptions Diese Methode kann unter den folgenden Umständen eine DOMException mit einem der folgenden code-Werte auslösen: HIERARCHY_REQUEST_ERR
Der Knoten lässt keine Kinder zu oder gestattet keine Kinder des angegebenen Typs, oder neuesKind ist ein Vorfahr dieses Knotens (oder ist selbst dieser Knoten). WRONG_DOCUMENT_ERR Die ownerDocument-Eigenschaft von neuesKind entspricht nicht der ownerDocument-Eigen-
schaft dieses Knotens. NO_MODIFICATION_ALLOWED_ERR
Dieser Knoten ist schreibgeschützt und gestattet keine weiteren Kinder, oder der anzufügende Knoten befindet sich bereits im Dokumentenbaum und hat einen schreibgeschützten Elternknoten, der das Löschen seiner Kinder verbietet.
Beschreibung Diese Methode fügt dem Dokument den Knoten neuesKind hinzu, indem sie ihn als letztes Kind dieses Knotens einfügt. Wenn neuesKind bereits im Dokumentenbaum vorhanden ist, wird es daraus gelöscht und dann an seinem neuen Platz wieder eingefügt. Ist neuesKind ein DocumentFragment-Knoten, so wird es nicht selbst eingefügt. Stattdessen werden alle seine Kinder der Reihe nach am Ende des childNodes[]-Arrays dieses Knotens angefügt. Beachten Sie, dass ein Knoten aus einem Dokument nicht in ein anderes Dokument eingefügt werden kann. Das gilt auch für Knoten, die von einem Dokument erzeugt wurden. Die ownerDocument-Eigenschaft von neuesKind muss also mit der ownerDocument-Eigenschaft dieses Knotens übereinstimmen.
944 | Referenz für clientseitiges JavaScript
491-0.book Seite 945 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Node.cloneNode( )
Beispiel Die folgende Funktion fügt am Ende des Dokuments einen neuen Absatz ein: function appendMessage(message) { var pElement = document.createElement("p"); var messageNode = document.createTextNode(message); pElement.appendChild(messageNode); // Schreibe Text in den Absatz document.body.appendChild(pElement); // Füge dem Dokument den Absatz hinzu }
Siehe auch Node.insertBefore( ), Node.removeChild( ), Node.replaceChild( )
Node.cloneNode( )
DOM Level 1 Core
Dupliziert einen Knoten und optional auch alle seine Nachfahren Referenz für clientseitiges JavaScript
Überblick Node cloneNode(boolean tief);
Argumente tief
Wenn dieses Argument true ist, klont cloneNode() rekursiv alle Nachfahren dieses Knotens. Andernfalls wird nur dieser eine Knoten geklont. Rückgabewert Eine Kopie dieses Knotens.
Beschreibung Die Methode cloneNode() erstellt und liefert eine Kopie des Knotens, auf dem sie aufgerufen wurde. Wenn man ihr das Argument true übergibt, klont sie rekursiv auch alle Nachfahren des Knotens. Andernfalls klont sie nur den Knoten selbst und nicht seine Kinder. Der Rückgabeknoten ist nicht Teil des Dokumentenbaums, und seine parentNode-Eigenschaft ist null. Wenn ein Element-Knoten geklont wird, werden auch alle seine Attribute geklont. Beachten Sie jedoch, dass EventListener-Funktionen, die auf einem Knoten registriert sind, nicht mitgeklont werden.
Node.hasAttributes( )
DOM Level 2 Core
Stellt fest, ob ein Knoten Attribute hat
Überblick boolean hasAttributes( );
Referenz für clientseitiges JavaScript |
945
491-0.book Seite 946 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Node.hasChildNodes( )
Rückgabewert true, wenn dieser Knoten ein oder mehrere Attribute hat; false, wenn nicht. Beachten Sie: Nur Element-Knoten können Attribute haben.
Siehe auch Element.getAttribute( ), Element.hasAttribute( ), Node
Node.hasChildNodes( )
DOM Level 1 Core
Stellt fest, ob ein Knoten Kinder hat
Überblick boolean hasChildNodes( );
Rückgabewert true, wenn der Knoten ein oder mehrere Kinder hat; false, wenn nicht.
Node.insertBefore( )
DOM Level 1 Core
Fügt einen Knoten vor dem angegebenen Knoten in den Dokumentenbaum ein
Der Knoten, der in den Baum eingefügt werden soll. Wenn er ein DocumentFragment ist, werden statt seiner seine Kinder eingefügt. refKind
Das Kind dieses Knotens, vor dem neuesKind eingefügt werden soll. Wenn dieses Argument null ist, wird neuesKind als letztes Kind dieses Knotens eingefügt. Rückgabewert Der eingefügte Knoten. Exceptions Diese Methode kann eine DOMException mit den folgenden code-Werten auslösen: HIERARCHY_REQUEST_ERR
Der Knoten unterstützt keine Kinder oder gestattet keine Kinder des angegebenen Typs, oder neuesKind ist ein Vorfahr dieses Knotens (oder ist selbst dieser Knoten). WRONG_DOCUMENT_ERR Die ownerDocument-Eigenschaft von neuesKind ist eine andere als die dieses Knotens.
946 | Referenz für clientseitiges JavaScript
491-0.book Seite 947 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Node.isSupported( ) NO_MODIFICATION_ALLOWED_ERR
Dieser Knoten ist schreibgeschützt und gestattet keine Einfügungen, oder der Elternknoten von neuesKind ist schreibgeschützt und gestattet keine Löschungen. NOT_FOUND_ERR refKind ist kein Kind dieses Knotens.
Beschreibung Diese Methode fügt den Knoten neuesKind als Kind dieses Knotens in den Dokumentenbaum ein. Der neue Knoten wird in das childNodes[]-Array dieses Knotens gesetzt, sodass er unmittelbar vor dem Knoten refKind kommt. Wenn refKind null ist, wird neuesKind wie bei der Methode appendChild() am Ende von childNodes[] eingefügt. Beachten Sie, dass diese Methode nicht mit einem refKind aufgerufen werden darf, das nicht Kind dieses Knotens ist. Befindet sich neuesKind bereits im Dokumentenbaum, so wird es daraus gelöscht und dann an seinem neuen Platz wieder eingefügt. Ist neuesKind ein DocumentFragment-Knoten, so wird es nicht selbst eingefügt. Stattdessen werden seine Kinder der Reihe nach am angegebenen Platz eingefügt. Referenz für clientseitiges JavaScript
Beispiel Die folgende Funktion fügt am Anfang eines Dokuments einen neuen Absatz ein: function insertMessage(message) { var paragraph = document.createElement("p"); // Erzeuge ein
-Element var text = document.createTextNode(message); // Erzeuge einen Text-Knoten paragraph.appendChild(text); // Schreibe Text in den Absatz // Füge den Absatz vor dem ersten Kind des Body ein document.body.insertBefore(paragraph, document.body.firstChild) }
Siehe auch Node.appendChild( ), Node.removeChild( ), Node.replaceChild( )
Node.isSupported( )
DOM Level 2 Core
Stellt fest, ob ein Knoten ein Feature unterstützt
Der Name des Features, auf das getestet wird. version
Die Versionsnummer des Features oder der leere String, wenn auf eine beliebige Version des Features getestet werden soll.
Referenz für clientseitiges JavaScript |
947
491-0.book Seite 948 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Node.normalize( )
Rückgabewert true, wenn der Knoten die angegebene Version des Features unterstützt, andernfalls false.
Beschreibung Der W3C DOM-Standard ist modular, und die Implementierungen brauchen nicht unbedingt alle Module oder Features des Standards zu unterstützen. Diese Methode testet, ob die Implementierung dieses Knotens die angegebene Version des genannten Features unterstützt. Unter DOMImplementation.hasFeature( ) finden Sie eine Liste von Werten für die Argumente feature und version.
Siehe auch DOMImplementation.hasFeature( )
Node.normalize( )
DOM Level 1 Core
Verschmilzt benachbarte und löscht leere Text-Knoten
Überblick void normalize( );
Beschreibung Diese Methode durchläuft alle Nachfahren dieses Knotens und »normalisiert« das Dokument, indem sie leere Text-Knoten löscht und benachbarte Text-Knoten zu einem einzelnen Knoten verschmilzt. Das kann die Baumstruktur nach dem Einfügen oder Löschen von Knoten vereinfachen.
Siehe auch Text
Node.removeChild( ) Löscht (und liefert) das angegebene Kind dieses Knotens
491-0.book Seite 949 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Node.replaceChild( )
Rückgabewert Der Knoten, der gelöscht wurde. Exceptions Diese Methode kann unter folgenden Umständen eine DOMException mit den folgenden codeWerten auslösen: NO_MODIFICATION_ALLOWED_ERR
Dieser Knoten ist schreibgeschützt und gestattet nicht das Löschen von Kindern. NOT_FOUND_ERR altesKind ist kein Kind dieses Knotens.
Beschreibung
Beispiel Mit folgendem Code können Sie das letzte Kind des Dokument-Bodys entfernen: document.body.removeChild(document.body.lastChild);
Siehe auch Node.appendChild( ), Node.insertBefore( ), Node.replaceChild( )
Der zu ersetzende Knoten. Rückgabewert Der Knoten, der aus dem Dokument entfernt und ersetzt wurde.
Referenz für clientseitiges JavaScript |
949
Referenz für clientseitiges JavaScript
Diese Methode löscht das angegebene Kind aus dem childNodes[]-Array dieses Knotens. Wenn sie mit einem Knoten aufgerufen wird, der kein Kindknoten ist, wird ein Fehler gemeldet. Die Methode removeChild() gibt den altesKind-Knoten zurück, nachdem sie ihn entfernt hat. altesKind ist weiterhin ein gültiger Knoten und kann später wieder in das Dokument eingefügt werden.
491-0.book Seite 950 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Node.selectNodes( )
Exceptions Diese Methode kann eine DOMException mit den folgenden code-Werten auslösen: HIERARCHY_REQUEST_ERR
Der Knoten lässt keine Kinder zu oder gestattet keine Kinder des angegebenen Typs, oder neuesKind ist ein Vorfahr dieses Knotens (oder ist selbst dieser Knoten). WRONG_DOCUMENT_ERR neuesKind und dieser Knoten haben unterschiedliche Werte für ownerDocument. NO_MODIFICATION_ALLOWED_ERR
Dieser Knoten ist schreibgeschützt und gestattet keine Ersetzungen, oder neuesKind ist Kind eines Knotens, der keine Löschungen erlaubt. NOT_FOUND_ERR altesKind ist kein Kind dieses Knotens.
Beschreibung Diese Methode ersetzt ein Kind des Dokumentenbaums durch ein anderes. altesKind ist der zu ersetzende Knoten und muss ein Kind dieses Knotens sein. neuesKind ist der Knoten, der ihn im childNodes[]-Array dieses Knotens ersetzt. Wenn neuesKind bereits Teil dieses Dokuments ist, wird es zuerst daraus entfernt und dann an seinem neuen Platz wieder eingefügt. Ist neuesKind ein DocumentFragment, so wird es nicht selbst eingefügt. Stattdessen werden seine Kinder der Reihe nach am ursprünglich von altesKind eingenommenen Platz eingefügt.
Beispiel Der folgende Code ersetzt einen Knoten n durch das Element und fügt dann den ersetzten Knoten in dieses Element ein. Dadurch bekommt der Knoten wieder einen Elternknoten und wird in fetter Schrift angezeigt: // Hole den ersten Kindknoten des ersten Absatzes im Dokument var n = document.getElementsByTagName("p")[0].firstChild; var b = document.createElement("b"); // Erzeuge ein -Element n.parentNode.replaceChild(b, n); // Ersetze den Knoten durch b.appendChild(n); // Füge den Knoten als Kind von wieder ein
Siehe auch Node.appendChild( ), Node.insertBefore( ), Node.removeChild( )
Node.selectNodes( ) Wählt Knoten über eine XPath-Query aus
Überblick NodeList selectNodes(String query)
950 | Referenz für clientseitiges JavaScript
IE 6
491-0.book Seite 951 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Node.selectSingleNode( )
Argumente query
Der XPath-Abfragestring. Rückgabewert Eine NodeList mit Knoten, die mit query übereinstimmen.
Beschreibung Diese IE-spezifische Methode evaluiert einen XPath-Ausdruck mit diesem Knoten als Wurzelknoten der Abfrage und gibt das Ergebnis als NodeList zurück. Die Methode selectNodes( ) ist bei Knoten von HTML-Dokumenten nicht vorhanden, sondern nur bei Knoten von XMLDokumenten. Da Document-Objekte selbst Knoten sind, kann diese Methode auf ganze XMLDokumente angewendet werden. Eine browserübergreifende Alternative finden Sie unter Document.evaluate( ).
Siehe auch
Node.selectSingleNode( )
IE 6
Finde einen Knoten, der mit einer XPath-Abfrage übereinstimmt
Überblick Node selectSingleNode(String query)
Argumente query
Der XPath-Abfrage-String. Rückgabewert Ein einzelner Knoten, der mit query übereinstimmt, oder null, wenn keine Übereinstimmungen vorhanden sind.
Beschreibung Diese IE-spezifische Methode wertet einen XPath-Ausdruck mit diesem Knoten als Kontextknoten aus. Sie gibt den ersten gefundenen passenden Knoten zurück, oder null, wenn keine Knoten passen. Die Methode selectSingleNode( ) ist bei Knoten von HTML-Dokumenten nicht vorhanden, sondern nur bei Knoten von XML-Dokumenten. Da Document-Objekte selbst Knoten sind, kann diese Methode auf ganze XML-Dokumente angewendet werden. Eine browserübergreifende Alternative finden Sie unter Document.evaluate( ).
Siehe auch Document.evaluate( ), XPathExpression; Kapitel 21
Referenz für clientseitiges JavaScript |
951
Referenz für clientseitiges JavaScript
Document.evaluate( ), XPathExpression; Kapitel 21
491-0.book Seite 952 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Node.transformNode( )
Node.transformNode( )
IE 6
Transformiert mit XSLT einen Knoten in einen String
Überblick String transformNode(Document xslt)
Argumente xslt
Ein XSLT-Stylesheet, das in ein Document-Objekt geparst wird. Rückgabewert Der erstellte Text, wenn das angegebene Stylesheet auf diesen Knoten und seine Nachfahren angewendet wird.
Beschreibung Diese IE-spezifische Methode transformiert einen Knoten und seine Nachfahren nach den in einem XSLT-Stylesheet angegebenen Regeln und gibt das Ergebnis als ungeparsten String zurück. Die Methode transformNode( ) ist bei Knoten von HTML-Dokumenten nicht vorhanden, sondern nur bei Knoten von XML-Dokumenten. Da Document-Objekte selbst Knoten sind, kann diese Methode auf ganze XML-Dokumente angewendet werden. Ähnliche Funktionalitäten in anderen Browsern finden Sie unter XSLTProcessor.
Siehe auch XSLTProcessor, Node.transformNodeToObject( ); Kapitel 21
Node.transformNodeToObject( )
IE 6
Transformiert mit XSLT einen Knoten in ein Dokument
Ein in ein Document-Objekt geparstes XSLT-Stylesheet. Rückgabewert Das in ein Document-Objekt geparste Ergebnis der Transformation.
Beschreibung Diese IE-spezifische Methode transformiert einen Knoten und seine Nachfahren nach den in einem XSLT-Stylesheet angegebenen Regeln und gibt das Ergebnis als Document-Objekt
952 | Referenz für clientseitiges JavaScript
491-0.book Seite 953 Mittwoch, 4. April 2007 9:55 09
e-bol.net
NodeList
zurück. Die Methode transformNodeToObject( ) ist bei Knoten von HTML-Dokumenten nicht vorhanden, sondern nur bei Knoten von XML-Dokumenten. Da Document-Objekte selbst Knoten sind, kann diese Methode auf ganze XML-Dokumente angewendet werden. Ähnliche Funktionalitäten in anderen Browsern finden Sie unter XSLTProcessor.
Siehe auch XSLTProcessor, Node.transformNode( ); Kapitel 21
NodeList Ein schreibgeschütztes Knoten-Array
DOM Level 1 Core Object ➝ NodeList
Eigenschaften readonly unsigned long length
Die Anzahl der Knoten im Array. Referenz für clientseitiges JavaScript
Methoden item( )
Gibt das angegebene Array-Element zurück.
Beschreibung Das NodeList-Interface definiert eine schreibgeschützte, geordnete Liste (d.h. ein Array) von Knotenobjekten. Die Eigenschaft length gibt an, wie viele Knoten in der Liste sind, und mit der Methode item() können Sie den Knoten an der angegebenen Listenposition abrufen. Die Elemente der NodeList sind immer gültige Node-Objekte: Eine NodeList enthält niemals null Elemente. In JavaScript verhalten sich NodeList-Objekte wie JavaScript-Arrays, und Sie können mit der Array-Notation mit eckigen Klammern ein Element der Liste abfragen, ohne item() aufrufen zu müssen. Sie können jedoch mit der Array-Notation der NodeList keine neuen Knoten zuweisen. Da es einfacher ist, sich ein NodeList-Objekt als schreibgeschütztes JavaScript-Array vorzustellen, verwendet dieses Buch statt NodeList die Schreibweise Element[] oder Node[] (d.h. ein Element-Array oder Node-Array). Die Methoden Document.getElementsByTagName( ), Element.getElementsByTagName( ) und HTMLDocument.getElementsByName( ) werden in diesem Buch so dokumentiert, als ob sie statt einer NodeList ein Element[] zurückgeben. In ähnlicher Weise ist auch die childNodes-Eigenschaft des Node-Objekts technisch gesehen ein NodeList-Objekt, doch der Referenzeintrag »Node« definiert sie als NodeNode[], und die Eigenschaft selbst wird normalerweise als »das childNodes[]-Array« bezeichnet. Beachten Sie, dass NodeList-Objekte »live« sind: Sie sind keine statischen Schnappschüsse, sondern reflektieren Änderungen am Dokumentenbaum sofort. Wenn Sie z.B. eine NodeList haben, die die Kinder eines speziellen Knotens repräsentiert, und eines dieser Kinder löschen, so wird es aus Ihrer NodeList entfernt. Seien Sie vorsichtig, wenn Sie die Elemente einer Node-
Referenz für clientseitiges JavaScript |
953
491-0.book Seite 954 Mittwoch, 4. April 2007 9:55 09
e-bol.net
NodeList.item( )
List durchlaufen und Ihr Schleifenrumpf den Dokumentenbaum in einer Weise ändert, die den Inhalt der NodeList beeinflussen könnte (indem er z.B. Knoten löscht).
Siehe auch Document, Element
NodeList.item( )
DOM Level 1 Core
Holt ein Element einer NodeList
Überblick Node item(unsigned long index);
Argumente index
Die Position (der Index) des gewünschten Knotens in der NodeList. Der Index des ersten Knotens in der NodeList ist 0 und der Index des letzten length–1. Rückgabewert Der Knoten an der angegebenen NodeList-Position oder null, wenn index kleiner als null oder größer oder gleich der Länge von NodeList ist.
Beschreibung Diese Methode gibt das angegebene Element einer NodeList zurück. In JavaScript können Sie statt item() die Array-Notation mit eckigen Klammern verwenden.
Option Eine Option in einem Select-Element
DOM Level 2 HTML Node ➝ Element ➝ HTMLElement ➝ HTMLOptionElement
Konstruktor Wie alle anderen Tags können Option-Objekte mit Document.createElement( ) erzeugt werden. Im DOM Level 0 können Sie Option-Objekte auch mit dem Konstruktor Option() dynamisch wie folgt erzeugen: new Option(String text, String value, boolean defaultSelected, boolean selected)
Argumente text
Ein optionales String-Argument, das die text-Eigenschaft des Option-Objekts angibt. value
Ein optionales String-Argument, das die value-Eigenschaft des Option-Objekts angibt.
954 | Referenz für clientseitiges JavaScript
491-0.book Seite 955 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Option defaultSelected
Ein optionales Boolesches Argument, das die defaultSelected-Eigenschaft des OptionObjekts angibt. selected
Ein optionales Boolesches Argument, das die selected-Eigenschaft des Option-Objekts angibt.
Eigenschaften boolean defaultSelected
Der Anfangswert des selected-Attributs des -Elements. Wenn das Formular zurückgesetzt wird, wird die Eigenschaft selected auf den Wert dieser Eigenschaft gesetzt. Wenn Sie diese Eigenschaft setzen, wird der Wert der selected-Eigenschaft gleich mitgesetzt. boolean disabled Wenn true, ist dieses -Element deaktiviert und der Benutzer hat keine Erlaubnis, es auszuwählen. Bildet das Attribut disabled ab.
Referenz für clientseitiges JavaScript
readonlyHTMLFormElementform Eine Referenz auf das -Element, in dem dieses Element enthalten ist. readonly long index
Die Position dieses -Elements innerhalb des -Elements. String label
Der Text, der für die Option angezeigt werden soll. Bildet das label-Attribut ab. Wenn diese Eigenschaft nicht angegeben ist, wird stattdessen der in einfachem Text gespeicherte Inhalt des -Elements verwendet. boolean selected
Der aktuelle Zustand dieser Option: Ist er true, so ist die Option ausgewählt. Ihren Anfangswert bezieht diese Eigenschaft aus dem selected-Attribut. readonly String text
Der einfache Text im -Element. Er ist die Beschriftung der Option. String value
Der mit dem Formular übermittelte Wert, wenn diese Option bei der Formularübermittlung eingeschaltet ist. Bildet das value-Attribut ab.
HTML-Syntax Ein Option-Objekt wird mit einem -Tag innerhalb eines -Tags erzeugt, das sich in einem befindet. In der Regel erscheinen mehrere -Tags innerhalb des -Tags: plain_text_label [ ]
// Der zurückgegebene Wert, wenn das Formular übermittelt wird // Gibt an, ob diese Option anfangs aktiviert ist // Der für diese Option darzustellende Text
Referenz für clientseitiges JavaScript |
955
491-0.book Seite 956 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Packages ... ...
Beschreibung Das Option-Objekt beschreibt eine einzelne Option innerhalb eines Select-Objekts. Die Eigenschaften dieses Objekts geben an, ob es standardmäßig oder gegenwärtig aktiviert ist, wo es im options[]-Array seines Select-Objekts steht, welche Beschriftung es anzeigt und welchen Wert es an den Server übergibt, wenn es bei der Formularübermittlung aktiviert ist. Achtung: Obwohl der von dieser Option angezeigte Text außerhalb des -Tags angegeben wird, muss er einfacher, unformatierter Text ohne HTML-Tags sein, damit er in Listenfeldern und Dropdown-Menüs, die keine HTML-Formatierungen unterstützen, auch korrekt angezeigt wird. Mit dem Option( )-Konstruktor können Sie neue Option-Objekte zur Darstellung in einem Select-Objekt dynamisch erzeugen. Nachdem ein neues Option-Objekt erzeugt wurde, kann es mit Select.add( ) an die Liste der Optionen in einem Select-Objekt angefügt werden. Eine genaue Beschreibung finden Sie in Select.options[].
Siehe auch Select, Select.options[]; Kapitel 18
Packages Siehe Packages in Teil III
Password Siehe Input
Plugin Beschreibt ein installiertes Plug-in
JavaScript 1.1; von IE nicht unterstützt Object ➝ Plugin
Ein schreibgeschützter String, der eine für Menschen lesbare Beschreibung des angegebenen Plug-ins enthält. Der Text dieser Beschreibung wird von den Schöpfern des Plug-ins verfasst und kann z.B. Hersteller- und Versionsinformationen sowie eine knappe Beschreibung der Funktion des Plug-ins umfassen.
956 | Referenz für clientseitiges JavaScript
491-0.book Seite 957 Mittwoch, 4. April 2007 9:55 09
e-bol.net
Plugin filename
Ein schreibgeschützter String mit dem Namen der Festplattendatei, die das eigentliche Programm des Plug-ins enthält. Dieser Name ist plattformabhängig. Die name-Eigenschaft ist zur Identifikation eines Plug-ins nützlicher als filename. length
Jedes Plug-in-Objekt ist gleichzeitig ein Array von MimeType-Objekten, die angeben, welche Datenformate es unterstützt. Wie bei allen Arrays gibt auch hier die length-Eigenschaft an, wie viele Elemente das Array hat. name
Die name-Eigenschaft eines Plug-in-Objekts ist ein schreibgeschützter String, der den Namen des Plug-ins angibt. Jedes Plug-in sollte einen Namen haben, der es eindeutig identifiziert. Der Name eines Plug-ins kann als Index für das navigator.plugins[]-Array verwendet werden. Diesen Umstand können Sie nutzen, um auf einfache Weise festzustellen, ob ein Plug-in eines bestimmten Namens auf dem verwendeten Browser installiert ist: var flash_installed = (navigator.plugins["Shockwave Flash"] != null);
Die Array-Elemente des Plug-in-Objekts sind MimeType-Objekte, die die von dem Plug-in unterstützten Datenformate angeben. Die Eigenschaft length gibt die Anzahl der MimeTypeObjekte in diesem Array an.
Beschreibung Ein Plug-in ist ein Software-Modul, das von einem Browser aufgerufen werden kann, um spezielle Typen von eingebetteten Daten im Browserfenster anzuzeigen. Plug-ins werden vom Plug-in-Objekt repräsentiert, und die Eigenschaft plugins[] des Navigator-Objekts ist ein Array aus Plug-in-Objekten, die die im Browser installierten Plug-ins darstellen. IE unterstützt das Plug-in-Objekt nicht, und das Array navigator.plugins[] ist in diesem Browser immer leer. navigator.plugins[] kann mit Zahlen indiziert werden. Das ist hilfreich, wenn Sie die gesamte
Liste der installierten Plug-ins auf der Suche nach einem bestimmten Plug-in durchlaufen wollen (beispielsweise ein Plug-in, das den MIME-Typ für die Daten unterstützt, die Sie in ihrer Webseite einbetten wollen). Sie können das Array aber auch mit den Plug-in-Namen indizieren. Wenn Sie wissen möchten, ob ein bestimmtes Plug-in auf dem Browser des Benutzers installiert ist, können Sie das also folgendermaßen prüfen: var flash_installed = (navigator.plugins["Shockwave Flash"] != null);
Der Name, den Sie mit dieser Technik als Array-Index verwenden, ist derselbe, der den Wert der name-Eigenschaft des Plug-ins bildet. Das Plug-in-Objekt ist insofern etwas ungewöhnlich, als es sowohl normale Objekteigenschaften als auch Array-Elemente hat. Die Eigenschaften des Plug-in-Objekts liefern Informationen über das Plug-in, und seine Array-Elemente sind MimeType-Objekte, die angeben, welche Formate für eingebettete Daten das Plug-in unterstützt. Bitte verwechseln Sie den Umstand, dass Plug-in-Objekte in einem Array des Navigator-Objekts gespeichert sind,
Referenz für clientseitiges JavaScript |
957
Referenz für clientseitiges JavaScript
Array-Elemente
491-0.book Seite 958 Mittwoch, 4. April 2007 9:55 09
e-bol.net
ProcessingInstruction
nicht mit dem Umstand, dass jedes Plug-in-Objekt selbst ein Array von MimeType-Objekten ist. Da hier zwei Arrays im Spiel sind, können Sie Code wie den folgenden schreiben: navigator.plugins[i][j] navigator.plugins["LiveAudio"][0]
// Der j-te MIME-Typ des i-ten Plug-ins // Erster MIME-Typ des Plug-ins LiveAudio
Zum Schluss sollten Sie auch noch beachten, dass einerseits die Array-Elemente eines Plug-inObjekts die von diesem Plug-in unterstützten MIME-Typen spezifizieren, Sie andererseits mit der Eigenschaft enabledPlugin des MimeType-Objekts aber auch ermitteln können, welches Plug-in einen bestimmten MIME-Typ unterstützt.
Siehe auch Navigator, MimeType
ProcessingInstruction Eine Verarbeitungsanweisung in einem XML-Dokument
DOM Level 1 XML Node ➝ ProcessingInstruction
Eigenschaften String data
Der Inhalt der Verarbeitungsanweisung (vom ersten nicht-leeren Zeichen hinter dem Ziel bis ausschließlich zum schließenden ?>). readonly String target
Das Ziel der Verarbeitungsanweisung. Es ist der erste Bezeichner, der auf das öffnende