Einführung in Ereignisse
Ereignisse sind Vorgänge, die im System, das Sie programmieren, geschehen und über die das System Sie informiert, damit Ihr Code darauf reagieren kann. Wenn ein Benutzer beispielsweise auf einer Webseite einen Button klickt, möchten Sie möglicherweise auf diese Aktion reagieren, indem Sie ein Informationsfenster anzeigen. In diesem Artikel besprechen wir einige wichtige Konzepte rund um Ereignisse und betrachten die Grundlagen ihrer Funktionsweise in Browsern.
| Voraussetzungen: | Grundverständnis von HTML und den CSS-Grundlagen, sowie Vertrautheit mit den JavaScript-Grundlagen, die in vorherigen Lektionen behandelt wurden. |
|---|---|
| Lernziele: |
|
Was ist ein Ereignis?
Ereignisse sind Vorgänge, die im System, das Sie programmieren, geschehen — das System erzeugt (oder "löst") eine Art Signal, wenn ein Ereignis auftritt, und bietet einen Mechanismus, durch den automatisch eine Aktion ausgeführt werden kann (das heißt, ein Code ausgeführt wird), wenn das Ereignis stattfindet. Ereignisse werden im Browserfenster ausgelöst und sind normalerweise an ein bestimmtes Element gebunden, das sich darin befindet. Dies könnte ein einzelnes Element sein, eine Gruppe von Elementen, das im aktuellen Tab geladene HTML-Dokument oder das gesamte Browserfenster. Es gibt viele verschiedene Arten von Ereignissen, die auftreten können.
Zum Beispiel:
- Der Benutzer wählt, klickt oder bewegt den Cursor über ein bestimmtes Element.
- Der Benutzer drückt eine Taste auf der Tastatur.
- Der Benutzer ändert die Größe oder schließt das Browserfenster.
- Eine Webseite lädt vollständig.
- Ein Formular wird abgesendet.
- Ein Video wird abgespielt, pausiert oder endet.
- Ein Fehler tritt auf.
Aus dieser Übersicht (und einem Blick auf den Ereignisindex) können Sie entnehmen, dass es eine Menge von Ereignissen gibt, die ausgelöst werden können.
Um auf ein Ereignis zu reagieren, fügen Sie ihm einen Ereignislistener hinzu. Dies ist eine Codefunktion, die das Auslösen des Ereignisses überwacht. Wenn das Ereignis ausgelöst wird, wird eine Ereignishandler-Funktion (die im Listener referenziert oder enthalten ist) aufgerufen, um auf das Auslösen des Ereignisses zu reagieren. Wenn ein solcher Codeblock eingerichtet ist, um auf ein Ereignis zu reagieren, sprechen wir von der Registrierung eines Ereignishandlers.
Ein Beispiel: Umgang mit einem Klick-Ereignis
Im folgenden Beispiel haben wir einen einzelnen <button> auf der Seite:
<button>Change color</button>
Dann haben wir etwas JavaScript. Wir werden dies im nächsten Abschnitt genauer betrachten, aber vorerst können wir einfach sagen: Es fügt einen Ereignislistener für das "click"-Ereignis des Buttons hinzu, und die enthaltene Handlerfunktion reagiert auf das Ereignis, indem sie den Seitenhintergrund auf eine zufällige Farbe setzt:
const btn = document.querySelector("button");
function random(number) {
return Math.floor(Math.random() * (number + 1));
}
btn.addEventListener("click", () => {
const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
document.body.style.backgroundColor = rndCol;
});
Die Beispielausgabe ist wie folgt. Versuchen Sie, auf den Button zu klicken:
Nutzung von addEventListener()
Wie wir im letzten Beispiel gesehen haben, haben Objekte, die Ereignisse auslösen können, eine addEventListener()-Methode, und dies ist der empfohlene Mechanismus zum Hinzufügen von Ereignislistenern.
Sehen wir uns den Code aus dem letzten Beispiel genauer an:
const btn = document.querySelector("button");
function random(number) {
return Math.floor(Math.random() * (number + 1));
}
btn.addEventListener("click", () => {
const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
document.body.style.backgroundColor = rndCol;
});
Das HTML <button>-Element löst ein click-Ereignis aus, wenn der Benutzer darauf klickt. Wir rufen die addEventListener()-Methode darauf auf, um einen Ereignislistener hinzuzufügen; dieser nimmt zwei Parameter:
- den String
"click", um anzugeben, dass wir dasclick-Ereignis überwachen möchten. Buttons können viele andere Ereignisse auslösen, wie zum Beispiel"mouseover", wenn der Benutzer die Maus über den Button bewegt, oder"keydown", wenn der Benutzer eine Taste drückt und der Button den Fokus hat. - eine Funktion, die aufgerufen wird, wenn das Ereignis auftritt. In unserem Fall erzeugt die definierte anonyme Funktion eine zufällige RGB-Farbe und setzt die
background-colorder Seite<body>auf diese Farbe.
Sie könnten auch eine separate benannte Funktion erstellen und diese im zweiten Parameter von addEventListener() referenzieren, so wie hier:
const btn = document.querySelector("button");
function random(number) {
return Math.floor(Math.random() * (number + 1));
}
function changeBackground() {
const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
document.body.style.backgroundColor = rndCol;
}
btn.addEventListener("click", changeBackground);
Überwachen anderer Ereignisse
Es gibt viele verschiedene Ereignisse, die von einem Button-Element ausgelöst werden können. Lassen Sie uns experimentieren.
Erstellen Sie zunächst eine lokale Kopie von random-color-addeventlistener.html und öffnen Sie sie in Ihrem Browser.
Es ist nur eine Kopie des einfachen Zufallsfarb-Beispiels, das wir bereits ausprobiert haben. Versuchen Sie nun, click nacheinander durch die folgenden verschiedenen Werte zu ersetzen und beobachten Sie die Ergebnisse im Beispiel:
focusundblur— Die Farbe ändert sich, wenn der Button fokussiert und unfokussiert wird; versuchen Sie, die Tabulatortaste zu drücken, um den Button zu fokussieren, und drücken Sie erneut die Tabulatortaste, um den Fokus vom Button zu entfernen. Diese werden häufig verwendet, um Informationen über das Ausfüllen von Formularfeldern anzuzeigen, wenn diese fokussiert sind, oder um eine Fehlermeldung anzuzeigen, wenn ein Formularfeld mit einem falschen Wert ausgefüllt wurde.dblclick— Die Farbe ändert sich nur, wenn der Button doppelt geklickt wird.mouseoverundmouseout— Die Farbe ändert sich, wenn der Mauszeiger über den Button schwebt oder wenn der Zeiger den Button verlässt.
Einige Ereignisse wie click sind auf nahezu jedem Element verfügbar. Andere sind spezifischer und nur in bestimmten Situationen nützlich: Zum Beispiel ist das play-Ereignis nur auf Elementen verfügbar, die eine Wiedergabefunktion haben, wie z.B. <video>.
Entfernen von Listenern
Wenn Sie einen Ereignislistener mit addEventListener() hinzugefügt haben, können Sie ihn wieder entfernen, falls gewünscht. Der gebräuchlichste Weg, dies zu tun, ist mit der removeEventListener()-Methode. Die folgende Zeile würde zum Beispiel den click-Ereignishandler entfernen, den wir zuvor gesehen haben:
btn.removeEventListener("click", changeBackground);
Für einfache, kleine Programme ist das Bereinigen alter, nicht mehr benötigter Ereignishandler nicht notwendig, aber für größere, komplexere Programme kann es die Effizienz verbessern. Auch ermöglicht Ihnen die Fähigkeit, Ereignishandler zu entfernen, dasselbe Button, unterschiedliche Aktionen unter verschiedenen Umständen auszuführen: Sie müssen lediglich Handler hinzufügen oder entfernen.
Hinzufügen mehrerer Listener für ein einzelnes Ereignis
Indem Sie mehrmals addEventListener() aufrufen und unterschiedliche Handler bereitstellen, können Sie mehrere Handler-Funktionen auf ein einzelnes Ereignis reagieren lassen:
myElement.addEventListener("click", functionA);
myElement.addEventListener("click", functionB);
Beide Funktionen würden nun ausgeführt, wenn das Element geklickt wird.
Andere Mechanismen für Ereignislistener
Wir empfehlen, addEventListener() zu verwenden, um Ereignishandler zu registrieren. Es ist die leistungsstärkste Methode und skaliert am besten mit komplexeren Programmen. Es gibt jedoch zwei andere Möglichkeiten, Ereignishandler zu registrieren, die Sie möglicherweise sehen werden: Ereignishandler-Eigenschaften und Inline-Ereignishandler.
Ereignishandler-Eigenschaften
Objekte (wie Schaltflächen), die Ereignisse auslösen können, haben normalerweise auch Eigenschaften, deren Name mit on gefolgt vom Namen eines Ereignisses beginnt. Zum Beispiel haben Elemente eine Eigenschaft onclick.
Dies wird als Ereignishandler-Eigenschaft bezeichnet. Um das Ereignis zu überwachen, können Sie die Handler-Funktion der Eigenschaft zuweisen.
Beispielsweise könnten wir das Zufallsfarb-Beispiel so umschreiben:
const btn = document.querySelector("button");
function random(number) {
return Math.floor(Math.random() * (number + 1));
}
btn.onclick = () => {
const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
document.body.style.backgroundColor = rndCol;
};
Sie können auch die Handler-Eigenschaft auf eine benannte Funktion setzen:
const btn = document.querySelector("button");
function random(number) {
return Math.floor(Math.random() * (number + 1));
}
function bgChange() {
const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
document.body.style.backgroundColor = rndCol;
}
btn.onclick = bgChange;
Ereignishandler-Eigenschaften haben im Vergleich zu addEventListener() Nachteile. Einer der bedeutendsten ist, dass Sie keine mehreren Listener für ein einzelnes Ereignis hinzufügen können. Das folgende Muster funktioniert nicht, da alle nachfolgenden Versuche den Eigenschaftswert zu setzen, frühere überschreiben würden:
element.onclick = function1;
element.onclick = function2;
Inline-Ereignishandler — verwenden Sie diese nicht
Sie könnten auch ein Muster wie dieses in Ihrem Code sehen:
<button onclick="bgChange()">Press me</button>
function bgChange() {
const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
document.body.style.backgroundColor = rndCol;
}
Die früheste Methode zum Registrieren von Ereignishandlern im Web umfasste Ereignishandler-Attribute (oder Inline-Ereignishandler) wie das obige Beispiel — der Attributwert enthält den JavaScript-Code, den Sie ausführen möchten, wenn das Ereignis eintritt.
Im obigen Beispiel wird eine Funktion innerhalb eines <script>-Elements auf derselben Seite aufgerufen, aber Sie könnten auch JavaScript direkt innerhalb des Attributs einfügen, zum Beispiel:
<button onclick="alert('Hello, this is my old-fashioned event handler!');">
Press me
</button>
Sie können HTML-Attributäquivalente für viele der Ereignishandler-Eigenschaften finden; Sie sollten diese jedoch nicht verwenden — sie gelten als schlechte Praxis. Es mag leicht erscheinen, ein Ereignishandler-Attribut zu verwenden, wenn Sie etwas sehr Schnelles tun, aber sie werden schnell unübersichtlich und ineffizient.
Es ist von vornherein keine gute Idee, HTML und JavaScript zu vermischen, da das Lesen erschwert wird. Es ist gute Praxis, Ihr JavaScript getrennt zu halten, und wenn es sich in einer separaten Datei befindet, können Sie es auf mehrere HTML-Dokumente anwenden.
Selbst in einer einzigen Datei sind Inline-Ereignishandler keine gute Idee. Ein Button ist in Ordnung, aber was ist, wenn Sie 100 Buttons haben? Sie müssten 100 Attribute zur Datei hinzufügen; es würde schnell zu einem Wartungsalptraum. Mit JavaScript könnten Sie leicht eine Ereignishandler-Funktion zu allen Buttons auf der Seite hinzufügen, unabhängig davon, wie viele es gibt, indem Sie etwas wie dies verwenden:
const buttons = document.querySelectorAll("button");
for (const button of buttons) {
button.addEventListener("click", bgChange);
}
Schließlich werden viele gängige Serverkonfigurationen Inline-JavaScript als Sicherheitsmaßnahme nicht zulassen.
Sie sollten nie die HTML-Ereignishandler-Attribute verwenden — diese sind veraltet, und ihre Verwendung ist schlechte Praxis.
Ereignisobjekte
Manchmal sehen Sie innerhalb einer Ereignishandler-Funktion einen Parameter mit einem Namen wie event, evt oder e.
Dies wird als Ereignisobjekt bezeichnet, und es wird automatisch an Ereignishandler weitergegeben, um zusätzliche Funktionen und Informationen bereitzustellen.
Schauen wir uns unser Random-Color-Beispiel noch einmal an, um ein Ereignisobjekt zu integrieren:
const btn = document.querySelector("button");
function random(number) {
return Math.floor(Math.random() * (number + 1));
}
function bgChange(e) {
const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
e.target.style.backgroundColor = rndCol;
console.log(e);
}
btn.addEventListener("click", bgChange);
Hinweis: Sie können den vollständigen Quellcode für dieses Beispiel auf GitHub finden (auch sehen Sie es live laufen).
Hier sehen Sie, dass wir ein Ereignisobjekt e in die Funktion aufnehmen und in der Funktion eine Hintergrundfarbenstil auf e.target festlegen — was der Button selbst ist.
Die target-Eigenschaft des Ereignisobjekts ist immer ein Verweis auf das Element, auf dem das Ereignis aufgetreten ist.
In diesem Beispiel setzen wir also eine zufällige Hintergrundfarbe auf den Button, nicht auf die Seite.
Hinweis:
Sie können jeden beliebigen Namen für das Ereignisobjekt verwenden — Sie müssen nur einen Namen wählen, den Sie innerhalb der Ereignishandler-Funktion referenzieren können.
e, evt und event werden häufig von Entwicklern verwendet, weil sie kurz und leicht zu merken sind.
Es ist immer gut, konsistent zu sein — mit sich selbst und mit anderen, wenn möglich.
Zusätzliche Eigenschaften von Ereignisobjekten
Die meisten Ereignisobjekte haben einen standardmäßigen Satz von Eigenschaften und Methoden, die auf dem Ereignisobjekt verfügbar sind; siehe die Event-Objektreferenz für eine vollständige Liste.
Einige Ereignisobjekte fügen zusätzliche Eigenschaften hinzu, die für den bestimmten Ereignistyp relevant sind. Zum Beispiel das keydown-Ereignis, das ausgelöst wird, wenn der Benutzer eine Taste drückt. Sein Ereignisobjekt ist ein KeyboardEvent, ein spezialisiertes Event-Objekt mit einer key-Eigenschaft, die Ihnen mitteilt, welche Taste gedrückt wurde:
<input id="textBox" type="text" />
<div id="output"></div>
const textBox = document.querySelector("#textBox");
const output = document.querySelector("#output");
textBox.addEventListener("keydown", (event) => {
output.textContent = `You pressed "${event.key}".`;
});
Versuchen Sie, in das Textfeld zu tippen und sehen Sie die Ausgabe:
Verhindern des Standardverhaltens
Manchmal stoßen Sie auf eine Situation, in der Sie verhindern möchten, dass ein Ereignis das tut, was es standardmäßig tut. Das häufigste Beispiel ist das eines Webformulars, zum Beispiel eines benutzerdefinierten Registrierungsformulars. Wenn Sie die Daten ausfüllen und auf die Schaltfläche "Senden" klicken, besteht das natürliche Verhalten darin, dass die Daten an eine angegebene Seite auf dem Server zur Verarbeitung gesendet werden und der Browser auf eine Art "Erfolgsmeldungs"-Seite umgeleitet wird (oder auf dieselbe Seite, wenn eine andere nicht angegeben wurde).
Das Problem entsteht, wenn der Benutzer die Daten nicht korrekt eingereicht hat — als Entwickler möchten Sie die Übermittlung an den Server verhindern und eine Fehlermeldung anzeigen, die besagt, was falsch ist und was zu tun ist, um es zu korrigieren. Einige Browser unterstützen automatische Formular-Datenprüfungsfunktionen, aber da viele dies nicht tun, wird empfohlen, sich nicht darauf zu verlassen und eigene Validierungsprüfungen zu implementieren. Schauen wir uns ein Beispiel an.
Zuerst ein einfaches HTML-Formular, das Sie dazu auffordert, Ihren Vor- und Nachnamen einzugeben:
<form action="#">
<div>
<label for="fname">First name: </label>
<input id="fname" type="text" />
</div>
<div>
<label for="lname">Last name: </label>
<input id="lname" type="text" />
</div>
<div>
<input id="submit" type="submit" />
</div>
</form>
<p></p>
Nun etwas JavaScript — hier implementieren wir eine grundlegende Prüfung in einem Handler für das submit-Ereignis (das Submit-Ereignis wird bei einem Formular ausgelöst, wenn es gesendet wird), das überprüft, ob die Textfelder leer sind.
Wenn dem so ist, rufen wir die preventDefault()-Funktion auf dem Ereignisobjekt auf — das die Formularübermittlung stoppt — und zeigen dann eine Fehlermeldung im Absatz unter unserem Formular an, um dem Benutzer mitzuteilen, was falsch ist:
const form = document.querySelector("form");
const fname = document.getElementById("fname");
const lname = document.getElementById("lname");
const para = document.querySelector("p");
form.addEventListener("submit", (e) => {
if (fname.value === "" || lname.value === "") {
e.preventDefault();
para.textContent = "You need to fill in both names!";
}
});
Offensichtlich ist dies eine ziemlich schwache Formularvalidierung — sie würde den Benutzer beispielsweise nicht daran hindern, das Formular mit Leerzeichen oder Zahlen in den Feldern zu validieren — aber es ist für Beispielzwecke in Ordnung.
Sie können das vollständige Beispiel live ausführen — probieren Sie es dort aus. Für den vollständigen Quellcode siehe preventdefault-validation.html.
Es betrifft nicht nur Webseiten
Ereignisse sind nicht einzigartig für JavaScript — die meisten Programmiersprachen haben eine Art von Ereignismodell, und die Funktionsweise des Modells unterscheidet sich oft von der in JavaScript. In der Tat unterscheidet sich das Ereignismodell in JavaScript für Webseiten vom Ereignismodell für JavaScript, wie es in anderen Umgebungen verwendet wird.
Zum Beispiel ist Node.js eine sehr beliebte JavaScript-Laufzeitumgebung, die es Entwicklern ermöglicht, JavaScript zum Erstellen von Netzwerk- und serverseitigen Anwendungen zu verwenden.
Das Node.js-Ereignismodell beruht auf Listenern, die auf Ereignisse horchen, und Emittern, die periodisch Ereignisse auslösen — es klingt nicht so anders, aber der Code unterscheidet sich erheblich, da Funktionen wie on() zum Registrieren eines Ereignislisteners verwendet werden, und once() zum Registrieren eines Ereignislisteners, der sich abmeldet, nachdem er einmal ausgeführt wurde.
Die Node.js HTTP connect event docs bieten ein gutes Beispiel.
Sie können JavaScript auch verwenden, um plattformübergreifende Add-ons zu entwickeln — Erweiterungen der Browserfunktionalität — mit einer Technologie namens WebExtensions.
Das Ereignismodell ist dem der Webereignisse ähnlich, jedoch etwas anders — Ereignislistener-Eigenschaften werden in camel case geschrieben (wie z.B. onMessage statt onmessage) und müssen mit der addListener-Funktion kombiniert werden.
Siehe die Seite zu runtime.onMessage für ein Beispiel.
Sie müssen an diesem Punkt Ihres Lernens nichts über andere solche Umgebungen verstehen; wir wollten nur klarstellen, dass sich Ereignisse in unterschiedlichen Programmierumgebungen unterscheiden können.
Zusammenfassung
In diesem Kapitel haben wir gelernt, was Ereignisse sind, wie man auf Ereignisse horcht und wie man auf sie reagiert.
Sie haben inzwischen gesehen, dass Elemente auf einer Webseite innerhalb anderer Elemente verschachtelt sein können. Zum Beispiel haben wir im Beispiel Verhindern des Standardverhaltens einige Textfelder, die in <div>-Elementen platziert sind, die wiederum in einem <form>-Element platziert sind. Was passiert, wenn ein Klick-Ereignislistener an das <form>-Element gebunden ist und der Benutzer in eines der Textfelder klickt? Die zugehörige Ereignishandler-Funktion wird immer noch über einen als Event-Bubbling bezeichneten Prozess ausgelöst, der in der nächsten Lektion behandelt wird.