Webprogrammierung — 9. Lektion

Events

Beim Interagieren mit anderen Programmen oder dem Nutzer werden sogenannte Events (Ereignisse) ausgelöst. Damit ein Programm oder eine Webseite auf Ereignisse reagieren kann, deren Eintreten nicht vorhersehbar ist, werden häufig Eventhandler eingesetzt. Es werden Ereignisse mit Ereignisbehandlungsroutinen verknüpft, die beim Eintreten des Ereignisses ausgeführt werden.
Eine Übersicht über Events und Eventhandler ist hier zu finden:
http://de.selfhtml.org/javascript/sprache/eventhandler.htm oder
https://wiki.selfhtml.org/wiki/JavaScript/DOM/Event/Übersicht/

Aktionen auf Knopfdruck

Mit dem Attribut onclick eines input-Elementes vom Typ button wird ein JavaScript-Programm angegeben, das ausgeführt wird, wenn der betreffende Knopf angeklickt (gedrückt und wieder losgelassen) wurde.
Die Funktion alert zeigt eine übergebene Zeichenkette in einer Benachrichtigungsbox. Wenn der Wert eines Attributes Leerzeichen enthält, muss er in Anführungszeichen gesetzt werden. Üblicherweise nimmt man dafür doppelte Anführungszeichen. Braucht man innerhalb eines Wertes ebenfalls Anführungszeichen, so muss man dafür die einfachen verwenden.
Im nächsten Beispiel wird auf Knopfdruck ein Text und seine Farbe (einmalig) geändert.
Die Funktion getElementById sucht unter allen Elementen unterhalb von document das Element, bei dem der id-Wert mit dem übergebenen Wert übereinstimmt und gibt einen Zeiger darauf zurück. Sollte die fragliche ID (fälschlicherweise) mehrfach vergeben sein, so wird das erste gefundene Element genommen. Sollte kein Element mit der ID gefunden werden, ist der Rückgabewert null.
Die Variable innerHTML enthält den in dem gefundenen Element vorhandenen HTML-Code (als eine Zeichenkette). Wird diese Zeichenkette überschrieben, wird der neue Inhalt zum neuen Inhalt des Elementes. Wenn kein Element gefunden wurde, kann auf diese Variable auch nicht zugegriffen werden (das Programm ist fehlerhaft und wird nicht weiter ausgeführt).
Über die Variable style kann auf weitere Variablen zugegriffen werden, die die Gestaltung betreffen (z.B. color). Diese Variablennamen stimmen häufig aber nicht immer mit den Attributen aus CSS überein (treten in CSS-Attributnamen Bindestriche auf, werden in JavaScript die Namen in CamelCase-Schreibweise angegeben, z.B. backgroundColor oder borderStyle).
Da Formatierung (HTML), Gestaltung (CSS) und Verhalten (JavaScript) getrennt werden sollten, ist es besser, für das angestrebte Erscheinungsbild eine Klasse mittels CSS anzulegen und über JavaScript die Zugehörigkeit zu Klassen zu steuern.
Die Funktion getElementsByClassName liefert eine sogenannte Live Node List von allen Elementen unterhalb von document, die zu der Klasse gehören, deren Name übergeben wurde. Die Anzahl der gefundenen Elemente ist die Länge der Liste und steht in der Variablen length.
Ein Element hat u.a. die im vorigen Beispiel erwähnten Attribute innerHTML und style, aber beispielsweise auch classList, was wiederum ein Objekt ist und u.a. die Methoden add und remove hat.
Eine Live Node List ändert sich, wenn Elemente hinzukommen oder wegfallen, auch ohne dass die Variable neu gesetzt werden muss (daher die Bezeichnung live).
Eine Liste der Attribute und Methoden, die jedes Element hat, ist zu finden unter https://www.w3schools.com/jsref/dom_obj_all.asp.

jQuery

Mit jQuery wird seit dem Jahre 2006 eine JavaScript-Bibliothek entwickelt, die inzwischen weit verbreitet ist. Mit jQuery erfolgt die Selektion von Elementen zum Manipulieren oder Verknüpfen mit Eventhandlern ähnlich wie bei CSS.

Einbinden von jQuery

Die Bibliothek jQuery wird eingebunden wie jedes andere JavaScript-Programm. Unter http://code.jquery.com/ findet man verschiedene Versionen. Man kann auf eine Datei dort verlinken oder sich eine Datei herunterladen und diese (dann lokale) Datei einbinden. Letzteres hat den Vorteil, dass man seinen Webauftritt offline erstellen kann (sonst muss jQuery bei jedem Testen der Seiten aus dem Internet geladen werden).
Wie andere JavaScript-Funktionen werden auch jQuery-Funktionen aus Blöcken heraus aufgerufen, die in einem script-Element stehen.

Aufruf von jQuery-Funktionen

Ähnlich wie bei CSS werden Elemente einer Seite durch Selektoren ausgewählt und Funktionen darauf angewendet. Die Auswahl erfolgt über
$(Selektor),
wobei Selektor im Allgemeinen eine in einfachen oder doppelten Anführungszeichen stehende Zeichenfolge ist, die einen von CSS bekannten Selektor (Universal-, Typ-, Klassen-, Individualselektor oder eine Kombination von solchen) enthält. Beispielsweise wählt $('#zeitanzeige') aus dem Beispiel im Abschnitt zuvor das Element mit der ID zeitanzeige aus (erkennbar am vorangestellten Doppelkreuz). Das Dollarzeichen ist eine Abkürzung für jQuery. Die beiden Anweisungen (die erste aus dem Beispiel zuvor)
$('#zeitanzeige').text(Date());    und    jQuery('#zeitanzeige').text(Date());
sind also äquivalent.
Die auszuführende Funktion (im obigen Beispie text) steht durch Punkt getrennt an dem Auswahl-Aufruf (dazwischen dürfen auch Leerzeichen und Zeilenumbrüche zur besseren Lesbarkeit stehen). Sollte diese Funktion wieder ein jQuery-Objekt liefern, so kann sofort wieder ein Funktionsname mit vorangestelltem Punkt angehängt werden, so dass mehrere Funktionen in Folge abgearbeitet werden können. Am Ende einer Anweisung muss immer ein Semikolon stehen.
Welche Funktionen auf die ausgewählten Elemente angewendet werden können, hängt von den fraglichen Objekten ab. Wir werden hier exemplarisch nur einige wenige vorstellen. Dazu zählen das Auslesen und Schreiben von Text (wie im Beispiel zuvor), das Ein- und Ausblenden von Bereichen, das Verändern von CSS-Attributen, das Verändern der Klassenzugehörigkeit und das Verknüpfen von Aktionen mit Ereignissen. Etwas mehr findet man unter https://www.javascript-kurs.de/jquery-tutorial.htm und noch mehr unter https://www.w3schools.com/jquery/.
Es ist darauf zu achten, dass die Elemente bereits erzeugt wurden, bevor man sie mit jQuery manipuliert. Im Beispiel oben wird erst das span-Element mit der ID zeitanzeige erzeugt und danach der enthaltene Text verändert (von leerer Zeichenkette zur Datumsanzeige). Stünde der jQuery-Aufruf vor dem span-Element, wäre das Element beim Aufruf noch nicht vorhanden, es würde also nichts ausgewählt werden und demzufolge würde auch von keinem Element der Text gesetzt werden.

Bereit zur Manipulation

Bevor ein Dokument nicht vollständig geladen wurde (die Struktur, das Document Object Model (DOM) aufgebaut wurde), kann man nicht sicher auf alle Elemente zugreifen. Daher sollten Manipulationen an der Seite, die nicht durch Interaktion mit dem Nutzer ausgelöst werden, erst ausgeführt werden, wenn das Dokument bereit ist. Mit jQuery lässt sich dies dadurch erreichen, dass man der ready-Funktion von $(document) eine Funktion übergibt, die ausgeführt wird, sobald das Dokument vollständig geladen (bereit) ist. Man beachte, dass bei $(document) keine Anführungszeichen stehen!
Der Aufruf ist wie folgt:
$(document).ready(Funktion);
Da die Funktion, die nach Bereitsstellung des Dokumentes abgearbeitet werden soll, normalerweise nicht noch einmal aufgerufen wird, gibt man sie üblicherweise sofort als Parameter, ohne Namen und eigene Parameter an:
$(document).ready( function(){Anweisungen} );
Die dort stehenden Anweisungen sind dann jene, die nacheinander ausgeführt werden, wenn das Dokument geladen ist. Der Aufruf von $(document).ready() bewirkt, dass die übergebene Funktion auf eine „To-Do-Liste” gesetzt und mit der Bedingung verknüpft wird, sie erst auszuführen, wenn das Dokument bereit ist. Damit kann dieser Aufruf an beliebiger (syntaktisch korrekter) Stelle stehen. Üblicherweise setzt man ihn jedoch in den head-Bereich oder lagert ihn in eine js-Datei aus, die ebenfalls im head-Bereich eingebunden wird.
Die im folgenden Beispiel verwendete alert-Funktion zeigt den übergebenen Text in einer kleinen Dialogbox an. Man achte auf die Reihenfolge der Ausführungen.
Um die Wirkungsweise zu sehen, bitte auf den Link zum Beispiel klicken: Beispiel zu $(document).ready() Die Seite wird hier nicht wie üblich eingebunden, da sonst bei jedem Laden der gesamten Lektion dieses Beispiel ausgeführt werden würde.

Anzeigen von e-Mail-Adressen

Es sollten keine e-Mail-Adressen im Klartext in html-Dateien stehen, da sie automatisch „abgegrast” werden können, um an Adressen für Spam-Mails zu kommen. In vielen Fällen behelfen sich die Autoren mit Bildern, die eingebunden werden und auf denen ein menschlicher Nutzer leicht eine e-Mail-Adresse erkennt, oder mit Umschreibungen, indem z.B. der Klammeraffe durch „(at)” und ein Punkt durch „(dot)” ersetzt werden.
Mit JavaScript kann man einen Text erzeugen und ihn erst im Browser anzeigen lassen. Eine e-Mail-Adresse wird an ihrer Struktur erkannt: Klammeraffe, davor und danach Buchstaben, Ziffern oder andere Zeichen, am Ende eine typische Endung wie „de”, „com”, „org” usw. Häufig kann man auch auf eine e-Mail-Adresse klicken, wodurch ein verknüpftes Mailprogramm gestartet wird. Dies wird dadurch erreicht, dass die e-Mail-Adresse in einem Link mit dem Zusatz mailto: verwendet wird. Also ist auch dieses Wort verräterisch. Wenn in html-Dateien solche Strukturen vermieden werden, ist ein automatisches Erkennen deutlich erschwert.
Eine Möglichkeit ist in folgendem Beispiel umgesetzt. Die nötigen Zeichenketten werden aus einzelnen Zeichen und Zeichenketten zusammengesetzt. Damit der Klammeraffe auch nicht als einzelnes Zeichen auftritt, wird es durch den Aufruf
String.fromCharCode(64)
aus dem ASCII-Wert 64 erzeugt. Mit der Funktion werden noch weitere Zeichen erzeugt, um die Zeichenketten auch nicht zerstückelt im Text vorkommen zu lassen.
Mit dem Aufruf
$('#ema').text(s);
wird der Text des Elementes mit der ID ema gesetzt. Mit dem Aufruf
$('#ema').attr("href",m+s);
wird von dem gleichen Element das Attribut href auf den Wert gesetzt, der durch Aneinanderhängen der auf den Variablen m und s gespeicherten Zeichenketten entsteht.
Eine andere Möglichkeit ist, eine e-Mail-Adresse verschlüsselt in der html-Datei zu transportieren und sie durch eine JavaScript-Funktion nach dem Laden der Seite zu entschlüsseln und an die richtigen Stellen zu schreiben. Im folgenden Beispiel sind die Zeichenkette mailto: und die e-Mail-Adresse verschlüsselt abgelegt (Caesar-Chiffrierung um ein Zeichen weiter, also jedes Zeichen ist durch seinen Nachfolger in der Zeichentabelle ersetzt). Zum Anzeigen werden diese beiden Zeichenketten entschlüsselt (zeichenweise wird der Vorgänger aus der Zeichentabelle genommen) und auf den Variablen m und s gespeichert. Alles andere ist wie im Beispiel zuvor.

Aktionen auf Mausereignisse

Mittels CSS kann man das Erscheinungsbild von Elementen verändern, sobald sich der Mauszeiger über dem Element befindet. Mittels JavaScript kann man auch andere Elemente beeinflussen. Die durch mouseenter(), mouseleave() und click()verknüpften Funktionen werden aufgerufen, wenn der Mauszeiger in das Element hinein kommt, wenn er es wieder verlässt bzw. wenn das Element angeklickt wurde.
In obigem Beispiel werden die Elemente der Klasse frage (ausgewählt durch $('.frage')) mit jeweils einer Funktion verknüpft, die beim Hineinbewegen der Maus (mouseenter) bzw. Hinausbewegen (mouseleave) ausgeführt wird. Außerdem werden das Element mit der ID alle und jenes mit der ID umschalt (ausgewählt durch $('#alle') bzw. $('#umschalt')) mit jeweils einer Funktion verknüpft, die ausgeführt wird, wenn das betreffende Element angeklickt wird (click). Was in den jeweiligen Funktionen abläuft, wird im nächsten Abschnitt behandelt. Alle diese Verbindungen (Element – Ereignis – Aktion) können erst dann hergestellt werden, wenn die fraglichen Elemente erzeugt sind. Deshalb stehen diese Aufrufe in der Funktion, die ausgeführt wird, wenn das Dokument geladen wurde.

Ein- und Ausblenden von Elementen

In dem obigen Beispiel gibt es Bereiche, die Fragen enthalten und die deshalb einer Klasse frage zugeordnet wurden, und Bereiche, die Antworten enthalten und deshalb einer Klasse antwort zugeordnet wurden. Sie sind über CSS so angeordnet, dass neben einer Frage immer ihre Antwort steht. Um den Nutzer die Antwort erst einmal selbst finden zu lassen, werden sie am Anfang nicht eingeblendet (durch display: none; in der css-Datei). Die leeren div-Elemente (Klasse fe) sorgen dafür (durch clear: both; in der css-Datei), dass nach einem Frage-Antwort-Paar die Nebeneinanderstellung aufgehoben wird, so dass das nächste Paar darunter erscheint.
Solange sich die Maus über einer Frage befindet, soll das betreffende Feld farblich hervorgehoben sein. Darauf wird aber erst im nächsten Abschnitt eingegangen.
Wenn die Maus sich auf ein Fragefeld begibt, soll die zugehörige Antwort eingeblendet werden; wenn die Maus das Feld wieder verlässt, soll die Antwort ausgeblendet werden. Das zugehörende Antwortfeld wird an der ID identifiziert. Die IDs der Fragefelder sind f1 und f2, die IDs der Antwortfelder setzen sich zusammen aus der ID der zugehörigen Frage und dem Anhängsel -antw. Wenn sich die Maus nun in ein Fragefeld begibt, wird die mit dem Element und dem Ereignis verknüpfte Funktion ausgeführt. Die Variable this zeigt auf das Element, um das es genau geht (in der Funktion an sich wissen wir nur, dass es sich um irgendein Element der Klasse frage handelt). Mit this.id greifen wir auf die ID des Elementes zu. Der Wert ist eine Zeichenkette (so wie im id-Attribut angegeben). Um nun mittels jQuery eine Aktion des Antwortfeldes auszuführen, muss der Selektor des Antwortfeldes erst zusammengesetzt werden. Er entsteht durch das Aneinanderhängen von Doppelkreuz (als Zeichen, dass der Rest der Zeichenkette eine ID ist), der ID des Fragefeldes und dem Zusatz -antw, zusammen also '#'+this.id+'-antw'. Mit $('#'+this.id+'-antw') greifen wir somit auf das gewünschte Antwortfeld zu. Das Gleiche geschieht, wenn die Maus ein Fragefeld verlässt (nur dass dann mit dem Antwortfeld etwas anderes geschieht).
Beim Klick auf die Schaltfläche zum Anzeigen aller Antworten sollen alle Antworten, also alle Bereiche der Klasse antwort, eingeblendet werden. Beim Klick auf die Schaltfläche zum Ausblenden aller Antworten sollen alle Antworten, also alle Bereiche der Klasse antwort, versteckt werden. Beim Klick auf die Schaltfläche zum Umschalten der Sichtbarkeit sollen alle Antworten, also alle Bereiche der Klasse antwort, die nicht zu sehen sind, angezeigt werden und alle, die zu sehen sind, weggeblendet werden. In allen drei Fällen soll eine Aktion mit jedem Element der Klasse antwort ausgeführt werden. Die Auswahl erfolgt durch $('.antwort').
Das Ein- und Ausblenden wird durch folgende Funktionen realisiert:
slideDown(ms):
Element wird von oben nach unten eingeblendet (wirkt nur, wenn es vorher nicht angezeigt wurde), der Parameter gibt die Dauer des Einblendens in Millisekunden an (ohne Parameter wird ein Standardwert genommen)
slideUp(ms):
Element wird von unten nach oben ausgeblendet (wirkt nur, wenn es vorher angezeigt wurde), der Parameter gibt die Dauer des Ausblendens in Millisekunden an (ohne Parameter wird ein Standardwert genommen)
show(ms):
Element wird von links oben nach rechts unten eingeblendet (wirkt nur, wenn es vorher nicht angezeigt wurde), der Parameter gibt die Dauer des Einblendens in Millisekunden an (ohne Parameter wird 0 genommen)
hide(ms):
Element wird von rechts unten nach links oben ausgeblendet (wirkt nur, wenn es vorher angezeigt wurde), der Parameter gibt die Dauer des Ausblendens in Millisekunden an (ohne Parameter wird 0 genommen)
toggle(ms):
Element wird von rechts unten nach links oben ausgeblendet (wirkt nur, wenn es vorher angezeigt wurde), der Parameter gibt die Dauer des Ausblendens in Millisekunden an (ohne Parameter wird 0 genommen)

CSS-Änderungen

In dem obigen Beispiel soll farblich erkennbar sein, über welcher Frage sich der Mauszeiger gerade befindet. Damit beim Verlassen des Feldes die Ausgangsfarben wieder hergestellt werden können, werden sie als erstes abgefragt (genauer gesagt die des ersten Fragefeldes). Somit muss bei einer Änderung des Stils nicht auch das JavaScript-Programm geändert werden. Die Funktion css liefert bei Übergabe eines Parameters den CSS-Wert dieses Attributes; falls das Attribut nicht existiert, ist der Wert undefined.
Gesetzt werden sollen die Farben von dem Element, das mit der Mausbewegung und dem dadurch ausgelösten Ereignis (mouseenter oder mouseleave) verbunden ist. Dieses Element wird durch $(this) ausgewählt (keine Anführungsstriche). Das Setzen von CSS-Attributen erfolgt ebenfalls mittels der Funktion css, allerdings sind dann zwei Parameter zu übergeben, von denen der erste ein CSS-Attribut angibt und der zweiten einen Wert dafür. Handelt es sich bei der ersten Zeichenkette nicht um ein Attribut, wird nichts gesetzt. Ist es ein Attribut aber die zweite Zeichenkette kein zulässiger Wert dafür, bekommt das Attribut keinen neuen Wert. Handelt es sich um die leere Zeichenkette, wird das Attribut auf den über die Stylesheets (oder den Standardwert falls sonst nicht vorhanden) angegebenen Wert gesetzt. (Man hätte also in diesem Beispiel auf das Auslesen der Werte am Anfang verzichten können.)
Allgemeine Zusammenfassung:
css(Attribut):
liefert den CSS-Wert von Attribut oder undefined, falls Attribut unbekannt
css(Attribut,Wert):
belegt Attribut mit Wert oder Standardwert, falls Wert die leere Zeichenkette ist

Klassenzugehörigkeit

Falls in obigem Beispiel in der css-Datei die Ausgangsfarben bereits so gesetzt werden, wie über JavaScript für die Hervorhebung verwendet wird, erfolgt keine Hervorhebung mehr. Daher ist es besser, die Gestaltung vollständig durch CSS zu realisieren. In diesem Falle ist es einfach umzusetzen, da man nur einen Definitionsblock für den Selektor .frage:hover benötigt, in dem die Farben zum Hervorheben gesetzt werden. Damit muss mittels JavaScript gar nichts mehr unternommen werden.
Soll sich etwas ändern, was mit CSS-Mitteln nicht erreicht werden kann, sollten mehrere Klassen vorgesehen werden (eine für vor der Änderung, eine für danach) und die Zugehörigkeit mittels JavaScript geändert werden. Das obige Beispiel wird nun dahingehend erweitert, dass eine schon besuchte Frage farblich gekennzeichnet wird – ähnlich der visited-Pseudoklasse für Links. Da diese Pseudoklasse für beliebige Elemente nicht existiert, erzeugen wir unsere eigene und nennen sie gesehen. Wenn der Mauszeiger ein Fragefeld verlässt, dann soll das Element dieser Klasse zugeordnet werden. Dies geschieht durch den Aufruf
$(this).addClass("gesehen");
in der Funktion, die beim Ereignis mouseleave ausgeführt wird. Die Zugehörigkeit zur Klasse frage wird durch removeClass("frage") aufgehoben. Beides kann in eine Anweisung zusammengezogen werden. Zum Umschalten der Klassenzugehörigkeit (wenn Mitglied, dann entfernen; wenn kein Mitglied, dann hinzunehmen) gibt es die (hier nicht verwendete) Funktion toggleClass(Klassenname).
Wie in der Version zuvor zu beobachten ist, kann man sich auch von einer bereits gesehenen Frage erneut die Antwort anzeigen lassen, obwohl die Frage gar nicht mehr zur Klasse frage gehört. Um auch die Verknüpfung des Elementes mit den Aktionen bei den Ereignissen zu lösen, reicht es nicht, das Element aus der Klasse zu nehmen, über die die Verknüpfung hergestellt wurde. Das Loslösen einer Verbindung erreicht man mit unbind().