Start · Sprachen · JavaScript · Referenz · CloseWatcher

CloseWatcher

Schnittstelle

Mit <code>CloseWatcher</code> reagieren eigene UI-Komponenten wie Popups, Seitenleisten oder Overlays auf Schließaktionen des Geräts, etwa die <code>Esc</code>-Taste oder die Android-Zurück-Geste, genau so wie ein natives <code>&lt;dialog&gt;</code>.

seit JavaScript Chromium 120+ (Chrome, Edge, Opera); nicht Baselin Kategorie: webapi

Signatur

interface CloseWatcher extends EventTarget

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 also cancel und danach close aus.
  • close(): löst sofort close aus, ohne cancel, und deaktiviert den Watcher.
  • destroy(): deaktiviert den Watcher, ohne ein Ereignis auszulösen.
  • Ereignisse: cancel und close, erreichbar über addEventListener() oder die Eigenschaften oncancel und onclose.

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

Typ
CloseWatcher
Beschreibung
Der Konstruktor gibt eine neue, aktive 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);
Seitenleiste geschlossen

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');
});
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()
cancel close

// 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 cancel dann nicht abbrechbar. Seiten können den Nutzer so nicht mit der Zurück-Taste „einsperren“. Deshalb vor preventDefault() immer event.cancelable prüfen.
  • Einmalig: Nach close oder destroy() 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() oder destroy() aufrufen. Sonst fängt der verwaiste Watcher die nächste Zurück-Geste ab.
  • Nicht doppelt verwenden: Native <dialog>-Elemente und das popover-Attribut haben dieses Verhalten schon eingebaut. CloseWatcher ist nur für selbst gebaute Komponenten gedacht.