Start · Sprachen · JavaScript · Referenz · Navigation: navigate

Navigation: navigate

Ereignis

Wird am <code>window.navigation</code>-Objekt ausgelöst, sobald eine Navigation beginnt – egal ob per Link, Formular, Vor/Zurück oder Skript – und lässt sich abfangen.

seit JavaScript Chrome/Edge 102+, Opera 88+, Firefox 147+, Safari Kategorie: webapi

Signatur

navigation.addEventListener("navigate", handler)

Beschreibung

Das navigate-Ereignis des Navigation-Interfaces ist die zentrale Stelle, an der eine Single-Page-Application alle Navigationen der Seite beobachten und übernehmen kann: Link-Klicks, abgeschickte Formulare, location.href-Zuweisungen, history.pushState(), navigation.navigate() sowie die Vor- und Zurück-Schaltflächen des Browsers. Der Handler bekommt ein NavigateEvent übergeben.

Die wichtigste Methode ist event.intercept({ handler }). Damit wird aus einer normalen Dokument-Navigation eine Navigation innerhalb desselben Dokuments: Der Browser aktualisiert die URL und den Verlaufseintrag, lädt die Seite aber nicht neu. Stattdessen wird der übergebene asynchrone handler ausgeführt, der den neuen Inhalt darstellt. Solange das zurückgegebene Promise noch nicht erfüllt ist, zeigt der Browser einen Ladeindikator an. Außerdem kümmert er sich um Fokus und Scroll-Position.

Nützliche Eigenschaften des Ereignisses sind unter anderem destination.url (Ziel-URL), navigationType ("push", "replace", "reload", "traverse"), canIntercept, hashChange, downloadRequest, formData, userInitiated und signal. Das signal ist ein AbortSignal, das ausgelöst wird, wenn die Navigation abgebrochen oder durch eine neue ersetzt wird. Mit event.preventDefault() lässt sich eine Navigation ganz unterbinden, sofern cancelable auf true steht.

Statt addEventListener kann man auch die Eigenschaft navigation.onnavigate setzen. Ein Handler, der so zugewiesen wird, ersetzt allerdings jeden vorher zugewiesenen.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Name des Ereignisses: "navigate".
$handler Pflicht (event: NavigateEvent) => void Callback, das ein NavigateEvent erhält. Es darf event.intercept() oder event.preventDefault() nur synchron aufrufen.
$options boolean | AddEventListenerOptions false Übliche Listener-Optionen wie once, signal oder capture.

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück. Die Navigation wird über das NavigateEvent-Objekt gesteuert.

Beispiele

SPA-Routing mit intercept()

const renderPage = async (url, signal) => {
  const res = await fetch(`/partials${url.pathname}`, { signal });
  document.querySelector('main').innerHTML = await res.text();
};

navigation.addEventListener('navigate', (event) => {
  // Nur abfangen, wenn es erlaubt und sinnvoll ist
  if (!event.canIntercept || event.hashChange || event.downloadRequest !== null) return;

  const url = new URL(event.destination.url);
  if (!url.pathname.startsWith('/app/')) return; // normale Navigation

  event.intercept({
    async handler() {
      await renderPage(url, event.signal);
    }
  });
});

Navigation bei ungespeicherten Änderungen verhindern (onnavigate)

let hasUnsavedChanges = true;

navigation.onnavigate = (event) => {
  if (hasUnsavedChanges && event.cancelable && event.navigationType !== 'reload') {
    const ok = confirm('Ungespeicherte Änderungen verwerfen?');
    if (!ok) event.preventDefault();
  }
};

// Später wieder entfernen
// navigation.onnavigate = null;

Navigationen protokollieren und Listener entfernen

const logNavigation = (event) => {
  console.log(event.navigationType, event.destination.url, {
    userInitiated: event.userInitiated,
    sameDocument: event.destination.sameDocument
  });
};

navigation.addEventListener('navigate', logNavigation);

// Programmgesteuerte Navigation löst das Ereignis ebenfalls aus
navigation.navigate('/app/profil');

// Nach Bedarf abmelden
navigation.removeEventListener('navigate', logNavigation);
push https://example.com/app/profil { userInitiated: false, sameDocument: false }

Formular-Absendung abfangen

navigation.addEventListener('navigate', (event) => {
  if (!event.formData || !event.canIntercept) return;

  event.intercept({
    async handler() {
      const res = await fetch(event.destination.url, {
        method: 'POST',
        body: event.formData,
        signal: event.signal
      });
      const { message } = await res.json();
      document.querySelector('#status').textContent = message;
    }
  });
});

// Wichtig · Fallstricke

  • Browser-Unterstützung: Die Navigation-API gibt es seit Chrome/Edge 102 und Opera 88, in Firefox seit Version 147 und in Safari seit 26.2. Ältere Browser kennen sie nicht. Deshalb vorher mit if ('navigation' in window) prüfen und sonst auf popstate bzw. Klick-Handler zurückfallen.
  • intercept() und preventDefault() müssen synchron im Handler aufgerufen werden. Nach einem await ist das nicht mehr möglich.
  • intercept() funktioniert nur, wenn canIntercept auf true steht. Bei ursprungsübergreifenden (Cross-Origin-)Zielen ist das nicht der Fall, dann wird ein SecurityError geworfen. Deshalb immer vorher canIntercept prüfen.
  • Zurück-/Vor-Navigationen (navigationType === "traverse") lassen sich mit preventDefault() nur verhindern, wenn sie innerhalb desselben Dokuments stattfinden, die Seite selbst sie ausgelöst hat oder eine Nutzeraktivierung vorliegt. Sonst ist cancelable false.
  • Das Ereignis wird nur für Navigationen im eigenen Browsing-Kontext ausgelöst. Navigationen in iframes oder anderen Fenstern bekommt man nicht mit.
  • event.signal an fetch() weiterreichen. So werden veraltete Anfragen abgebrochen, wenn der Nutzer schnell hintereinander navigiert.
  • Wer abgerufenes HTML per innerHTML einfügt, muss sich gegen XSS schützen: nur vertrauenswürdige Quellen verwenden oder den Inhalt bereinigen.