Signatur
Beschreibung
Die Schnittstelle CloseWatcher bündelt alle plattformspezifischen „Schließ“-Anfragen in einer einzigen Programmierschnittstelle. Am Desktop ist das meist die Esc-Taste, unter Android die Zurück-Taste bzw. Zurück-Geste und bei Bildschirmlesern eine eigene Schließgeste. Ohne CloseWatcher müsste man jede dieser Eingaben einzeln abfangen, und die Zurück-Geste unter Android lässt sich praktisch nur über Tricks mit der History-API nachbilden.
Das Vorgehen ist einfach: Beim Öffnen einer Komponente erzeugt man mit new CloseWatcher() eine Instanz und hört auf das Ereignis close. Löst der Nutzer eine Schließaktion aus, schickt der Browser zuerst ein abbrechbares cancel-Ereignis und danach close. Mit event.preventDefault() im cancel-Handler kann man das Schließen verhindern, zum Beispiel um bei ungespeicherten Änderungen nachzufragen.
requestClose(): verhält sich wie eine echte Schließanfrage des Nutzers, löst alsocancelund danachcloseaus.close(): löst sofortcloseaus, ohnecancel, und deaktiviert den Watcher.destroy(): deaktiviert den Watcher, ohne ein Ereignis auszulösen.- Ereignisse:
cancelundclose, erreichbar überaddEventListener()oder die Eigenschaftenoncancelundonclose.
Mehrere aktive Watcher bilden einen Stapel. Eine Schließaktion trifft immer nur den zuletzt erzeugten Watcher, also das oberste Overlay. Verschachtelte Popups schließen sich so in der richtigen Reihenfolge von innen nach außen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $options | Object | {} | Optionales Konfigurationsobjekt für den Konstruktor new CloseWatcher(options). |
| $options.signal | AbortSignal | Ein AbortSignal. Wird es abgebrochen, ruft der Browser automatisch destroy() auf. Praktisch, um den Watcher zusammen mit anderen Listenern aufzuräumen. |
Rückgabewert
CloseWatcher-Instanz zurück. Sie liegt oben auf dem Stapel der Watcher. Die Methoden requestClose(), close() und destroy() geben jeweils undefined zurück.Beispiele
Eigene Seitenleiste per Esc bzw. Zurück-Geste schließen
const sidebar = document.querySelector('#sidebar');
const openBtn = document.querySelector('#open-sidebar');
const closeBtn = document.querySelector('#close-sidebar');
let watcher = null;
const openSidebar = () => {
sidebar.hidden = false;
// Watcher nur anlegen, wenn die API verfügbar ist
if ('CloseWatcher' in window) {
watcher = new CloseWatcher();
watcher.onclose = () => {
sidebar.hidden = true;
watcher = null;
console.log('Seitenleiste geschlossen');
};
}
};
// Der eigene Schließen-Knopf nutzt denselben Weg
closeBtn.addEventListener('click', () => {
if (watcher) watcher.close();
else sidebar.hidden = true;
});
openBtn.addEventListener('click', openSidebar);
Schließen bei ungespeicherten Änderungen abfangen (cancel-Ereignis)
const editor = document.querySelector('#editor-overlay');
const textarea = editor.querySelector('textarea');
let dirty = false;
textarea.addEventListener('input', () => { dirty = true; });
const watcher = new CloseWatcher();
watcher.addEventListener('cancel', (event) => {
// cancel ist nur nach einer Nutzeraktivierung abbrechbar
if (dirty && event.cancelable) {
event.preventDefault();
if (confirm('Änderungen verwerfen?')) {
watcher.close(); // schließt ohne erneutes cancel
}
}
});
watcher.addEventListener('close', () => {
editor.hidden = true;
console.log('Editor geschlossen');
});
Aufräumen mit AbortSignal und requestClose()
const controller = new AbortController();
const watcher = new CloseWatcher({ signal: controller.signal });
watcher.oncancel = () => console.log('cancel');
watcher.onclose = () => console.log('close');
// Verhält sich wie eine echte Schließanfrage des Nutzers
watcher.requestClose();
// Später: alle verknüpften Listener und Watcher auf einmal entfernen
controller.abort(); // entspricht watcher.destroy()
// Wichtig · Fallstricke
Browser-Unterstützung: CloseWatcher gibt es bisher nur in Chromium-basierten Browsern ab Version 120. Firefox und Safari unterstützen die Schnittstelle nicht standardmäßig. Deshalb vorher mit 'CloseWatcher' in window prüfen und eine Ersatzlösung vorsehen, etwa einen keydown-Listener für Escape.
- Schutz vor Missbrauch: Ohne vorherige Nutzeraktivierung (Klick, Tastendruck) werden neue Watcher mit dem vorhandenen gruppiert. Außerdem ist
canceldann nicht abbrechbar. Seiten können den Nutzer so nicht mit der Zurück-Taste „einsperren“. Deshalb vorpreventDefault()immerevent.cancelableprüfen. - Einmalig: Nach
closeoderdestroy()ist der Watcher dauerhaft inaktiv. Beim erneuten Öffnen der Komponente muss man einen neuen Watcher anlegen. - Aufräumen nicht vergessen: Wird die Komponente auf anderem Weg geschlossen, zum Beispiel über einen eigenen Knopf,
close()oderdestroy()aufrufen. Sonst fängt der verwaiste Watcher die nächste Zurück-Geste ab. - Nicht doppelt verwenden: Native
<dialog>-Elemente und daspopover-Attribut haben dieses Verhalten schon eingebaut.CloseWatcherist nur für selbst gebaute Komponenten gedacht.