Abschnitt 12 · Lektion 4
Standardverhalten verhindern
Manche Elemente tun beim Ereignis von sich aus etwas, und zwar ohne dass jemand dafür Code geschrieben hat. Ein Link führt woandershin. Ein Formular wird abgeschickt und die Seite neu geladen. Die Leertaste scrollt. Ein Rechtsklick öffnet ein Menü.
Das ist das Standardverhalten, und event.preventDefault() schaltet es für dieses eine Ereignis ab.
Ein Link, der bleibt
<p><a id="gebremst" href="details.html">Mit preventDefault</a></p>
<p><a id="frei" href="details.html">Ohne preventDefault, Vorsicht</a></p>
<p id="ausgabe">noch nichts</p> <h1>Details</h1>
<p>Das ist die zweite Seite. Du bist hier gelandet, weil der Klick
nicht abgefangen wurde.</p>
<p><a href="index.html">Zurück</a></p> body {
font-family: system-ui, sans-serif;
max-width: 40rem;
margin: 0;
padding: 1rem;
line-height: 1.6;
color: #1c1917;
}
p {
margin: 0 0 0.75rem;
} const ausgabe = document.getElementById("ausgabe");
document.getElementById("gebremst").addEventListener("click", (event) => {
event.preventDefault();
ausgabe.textContent = "Der Link wurde abgefangen";
console.log("abgefangen, die Seite bleibt stehen");
});
// Derselbe Handler ohne die eine Zeile. Der Text wird gesetzt,
// und gleich danach ist die Seite bei details.html.
document.getElementById("frei").addEventListener("click", () => {
ausgabe.textContent = "Gleich ist diese Seite weg";
console.log("hier läuft noch alles, aber nicht mehr lange");
});
console.log("Klick den ersten Link. Dann, wenn du magst, den zweiten."); Der Handler läuft, egal ob du preventDefault aufrufst oder nicht. Der Unterschied kommt danach: Ohne die Zeile macht der Browser weiter mit dem, was er ohnehin vorhatte, und navigiert.
Im Beispiel siehst du beide Fälle nebeneinander. Der erste Link setzt den Text und bleibt stehen. Beim zweiten wird der Text ebenfalls gesetzt, und einen Wimpernschlag später steht /details.html in der Adresszeile und darunter die zweite Seite. Die liegt als eigene Datei im Editor, du kannst sie also anschauen. Über „Zurück” in der Adresszeile oder den Link auf der Seite kommst du wieder her.
Achte dabei auf die Console: Deine console.log-Zeilen sind nach dem Wechsel weg. Eine Navigation lädt ein neues Dokument, und damit ist alles verloren, was im alten im Speicher stand. Genau darum geht es beim nächsten Beispiel.
Wichtig ist die Umkehrung: Ein Link, der wirklich woandershin führen soll, behält sein Standardverhalten. preventDefault gehört nicht vorsorglich in jeden Handler, sondern genau dorthin, wo du die eingebaute Reaktion ausdrücklich nicht willst.
Der wichtigste Fall
<form id="formular">
<input name="name" value="Ida">
<button type="submit">Absenden</button>
</form>
<p id="ausgabe">noch nichts abgeschickt</p> body {
font-family: system-ui, sans-serif;
max-width: 40rem;
margin: 0;
padding: 1rem;
line-height: 1.6;
color: #1c1917;
}
p {
margin: 0 0 0.75rem;
}
button,
input,
select,
textarea {
font: inherit;
}
button {
padding: 0.4rem 0.8rem;
border: 1px solid #d6d3d1;
border-radius: 6px;
background: #fafaf9;
cursor: pointer;
}
input,
select,
textarea {
padding: 0.35rem 0.5rem;
border: 1px solid #d6d3d1;
border-radius: 6px;
} const ausgabe = document.getElementById("ausgabe");
document.getElementById("formular").addEventListener("submit", (event) => {
// Ohne diese Zeile schickt der Browser das Formular ab
// und lädt die Seite neu. Alles darunter liefe zwar noch,
// aber sichtbar bliebe davon nichts.
event.preventDefault();
ausgabe.textContent = "Abgeschickt, ohne Neuladen";
console.log("Der Handler behält die Kontrolle.");
});
// Das ist der häufigste Einsatz von preventDefault überhaupt,
// und Abschnitt 13 baut darauf auf.
console.log("Drück den Knopf oder die Eingabetaste im Feld."); Bei Formularen ist preventDefault fast immer nötig. Ohne die Zeile schickt der Browser die Daten ab und lädt die Seite neu, und dann ist alles weg: der Zustand im Speicher, die Anzeige, der halb ausgefüllte Rest.
Der Handler läuft dabei noch, und genau das macht den Fehler so verwirrend. Es sieht kurz so aus, als hätte alles funktioniert, dann ist die Seite neu.
Abschnitt 13 baut auf dieser einen Zeile auf. Hier reicht: Wer ein Formular in JavaScript behandelt, ruft preventDefault auf.
Nicht zu verwechseln
<div id="aussen">
<a id="link" href="details.html">Klick mich</a>
</div>
<pre id="protokoll"></pre> body {
font-family: system-ui, sans-serif;
max-width: 40rem;
margin: 0;
padding: 1rem;
line-height: 1.6;
color: #1c1917;
}
#aussen {
padding: 12px;
background: #e2e8f0;
} const protokoll = document.getElementById("protokoll");
function notiere(text) {
protokoll.textContent = `${protokoll.textContent}${text}\n`;
}
document.getElementById("link").addEventListener("click", (event) => {
event.preventDefault();
notiere("Link: abgefangen");
});
// Dieser Listener läuft trotzdem. preventDefault sagt nur,
// dass der Browser seine eingebaute Reaktion lassen soll,
// nicht dass das Ereignis hier aufhört.
document.getElementById("aussen").addEventListener("click", (event) => {
notiere(`außen: läuft auch, defaultPrevented = ${event.defaultPrevented}`);
});
console.log("Ein Klick, zwei Zeilen im Protokoll."); Diese beiden werden regelmäßig verwechselt, obwohl sie nichts miteinander zu tun haben.
preventDefault() sagt dem Browser: Lass deine eingebaute Reaktion sein. Das Ereignis läuft weiter durch die Seite, alle anderen Listener laufen ebenfalls.
stopPropagation() sagt den anderen Listenern: Ihr bekommt das hier nicht mehr. Das Standardverhalten des Browsers bleibt davon unberührt, der Link navigiert also trotzdem.
Im dritten Beispiel steht ein Listener innen und einer außen. Der innere fängt das Standardverhalten ab, der äußere läuft trotzdem und sieht an event.defaultPrevented, dass jemand vor ihm abgefangen hat. Was stopPropagation dagegen tut und warum man damit sparsam umgeht, ist Lektion 12.5.
Und return false
In alten Anleitungen steht statt preventDefault oft ein return false am Ende des Handlers. Das funktioniert nur in der alten Schreibweise mit onclick im Markup, und dort tut es genau eine Sache: preventDefault. Dass es zusätzlich die Weitergabe nach oben stoppt, ist eine Erinnerung an jQuery, wo return false wirklich beides macht.
In einem Handler, den du mit addEventListener hinterlegt hast, bewirkt return false gar nichts. Der Rückgabewert interessiert dort niemanden.
Wenn du es in fremdem Code siehst, weißt du damit sofort zweierlei: Es ist alt, und ob es überhaupt etwas tut, hängt daran, wo es steht.
Zum Mitnehmen
preventDefault unterbindet die eingebaute Reaktion des Browsers. stopPropagation unterbindet die Weitergabe an andere Listener. Die beiden haben nichts miteinander zu tun.
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
Was in dieser Lektion steckt
-
Artikel mit 3 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe im Editor, direkt im Browser geprüft
Öffnet sich mit dem Basis Konto.