Signatur
Beschreibung
intercept() ist der zentrale Baustein für clientseitiges Routing mit der Navigation API. Sie rufen die Methode im Listener für das navigate-Event von window.navigation auf. Der Browser lädt dann kein neues Dokument. Stattdessen aktualisiert er die URL auf event.destination.url, legt einen neuen Verlaufseintrag an (bzw. ersetzt oder wechselt ihn) und führt Ihren handler aus. Dort rendern Sie den neuen Inhalt.
Anders als bei history.pushState() und dem Abfangen von click-Events auf Links erfasst ein einziger Listener alle Arten von Navigation: Linkklicks, Formularversand, Zurück/Vor-Tasten und programmatische Aufrufe wie navigation.navigate(). Der Browser zeigt außerdem einen Ladeindikator an, solange das Promise des Handlers aussteht. Er kümmert sich auch um die Wiederherstellung der Scrollposition und das Zurücksetzen des Fokus.
Ob eine Navigation abgefangen werden darf, zeigt event.canIntercept. Navigationen zu einem anderen Ursprung (Cross-Origin) und bestimmte Traversal-Fälle lassen sich nicht abfangen. Für reine Sprünge zu Ankern (event.hashChange) oder Downloads (event.downloadRequest) ist ein Abfangen oft nicht sinnvoll.
Ist der Handler erfolgreich, feuert navigation das Event navigatesuccess. Wird das Promise abgelehnt, feuert navigateerror. Das Promise finished des Aufrufs von navigation.navigate() verhält sich genauso.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $options | object | {} | Optionales Konfigurationsobjekt mit folgenden Eigenschaften. |
| $options.handler | () => Promise<void> | void | Callback, der den neuen Inhalt lädt und darstellt. Er läuft, nachdem die URL aktualisiert wurde. Gibt er ein Promise zurück, gilt die Navigation erst als abgeschlossen, wenn dieses erfüllt ist. | |
| $options.focusReset | "after-transition" | "manual" | "after-transition" | Mit "after-transition" setzt der Browser den Fokus nach Abschluss des Handlers auf das erste Element mit autofocus oder auf <body> zurück. Mit "manual" steuern Sie den Fokus selbst. |
| $options.scroll | "after-transition" | "manual" | "after-transition" | Mit "after-transition" scrollt der Browser nach Abschluss des Handlers automatisch: bei Traversal oder Reload zur gespeicherten Position, sonst an den Seitenanfang oder zum Fragment. Mit "manual" lösen Sie das Scrollen selbst aus, z. B. mit event.scroll(). |
| $options.precommitHandler | (controller: NavigationPrecommitController) => Promise<void> | Neuere, noch nicht überall verfügbare Option. Der Callback läuft bevor die URL übernommen wird, etwa um Daten vorab zu laden oder mit controller.redirect() umzuleiten. Nur bei abbrechbaren Navigationen (event.cancelable) erlaubt. |
Rückgabewert
navigatesuccess/navigateerror oder über die Promises committed/finished von navigation.navigate().Beispiele
Einfacher SPA-Router
// Alle Navigationen innerhalb derselben Origin abfangen
navigation.addEventListener('navigate', (event) => {
// Nicht abfangbare Navigationen, Anker-Sprünge und Downloads dem Browser überlassen
if (!event.canIntercept || event.hashChange || event.downloadRequest !== null) {
return;
}
const url = new URL(event.destination.url);
if (url.pathname.startsWith('/artikel/')) {
event.intercept({
async handler() {
const res = await fetch(`/api${url.pathname}`, { signal: event.signal });
const artikel = await res.json();
document.querySelector('main').textContent = artikel.titel;
document.title = artikel.titel;
},
});
}
});
Scrollen und Fokus selbst steuern
navigation.addEventListener('navigate', (event) => {
if (!event.canIntercept) return;
event.intercept({
scroll: 'manual',
focusReset: 'manual',
async handler() {
const main = document.querySelector('main');
main.innerHTML = '<p>Lade …</p>';
const html = await fetch(event.destination.url, { signal: event.signal })
.then((r) => r.text());
main.innerHTML = new DOMParser()
.parseFromString(html, 'text/html')
.querySelector('main').innerHTML;
// Erst scrollen, wenn der Inhalt da ist
event.scroll();
main.querySelector('h1')?.focus();
},
});
});
Erfolg und Fehler auswerten
navigation.addEventListener('navigate', (event) => {
if (!event.canIntercept) return;
event.intercept({
async handler() {
const res = await fetch(event.destination.url, { signal: event.signal });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
},
});
});
navigation.addEventListener('navigatesuccess', () => {
console.log('Navigation abgeschlossen:', navigation.currentEntry.url);
});
navigation.addEventListener('navigateerror', (e) => {
console.error('Navigation fehlgeschlagen:', e.message);
});
// Programmatisch navigieren und auf das Ende warten
const { finished } = navigation.navigate('/profil');
await finished;
// Wichtig · Fallstricke
- Synchron aufrufen:
intercept()muss während des Event-Dispatchs aufgerufen werden, also nicht nach einemawaitim Listener. Sonst wirft die Methode einenInvalidStateError. Den gleichen Fehler gibt es, wenn das Event bereits mitpreventDefault()abgebrochen wurde. - canIntercept prüfen: Ist
event.canInterceptfalse(z. B. bei Cross-Origin-Zielen) oder ist das Event nicht vertrauenswürdig (isTrusted === false), wirft die Methode einenSecurityError. - Abbruch beachten: Startet der Nutzer während des Handlers eine neue Navigation, wird
event.signalabgebrochen. Geben Sie das Signal anfetch()weiter, damit veraltete Antworten nicht den neuen Inhalt überschreiben. - Sie können
intercept()mehrfach aufrufen, auch aus verschiedenen Listenern. Alle Handler laufen dann parallel, und die Navigation ist erst abgeschlossen, wenn alle fertig sind. - Bei Traversal zu einem anderen Dokument lässt sich die Navigation nicht abfangen. Innerhalb desselben Dokuments ist ein Zurück/Vor zwar abfangbar, aber nicht mit
preventDefault()abbrechbar. - Kompatibilität: Die Navigation API gibt es seit Chromium 102. Safari und Firefox unterstützen sie erst in neueren Versionen. Prüfen Sie die Unterstützung mit
'navigation' in windowund greifen Sie sonst auf die History-API zurück.precommitHandlerist noch deutlich weniger verbreitet. - Sicherheit: Wenn Sie abgerufenes HTML mit
innerHTMLeinsetzen, droht XSS. Verwenden Sie nur vertrauenswürdige Quellen oder bereinigen Sie das HTML vorher.