Routing lato client moderno: API Navigation

Standardizzazione del routing lato client tramite una nuovissima API che revisiona completamente la creazione di applicazioni a pagina singola.

Supporto dei browser

  • 102
  • 102
  • x
  • x

Origine

Le applicazioni a pagina singola, o SPA, sono definite da una funzionalità principale: la riscrittura dinamica dei contenuti in base all'interazione dell'utente con il sito, anziché il metodo predefinito di caricamento di pagine completamente nuove dal server.

Anche se le APS sono state in grado di offrirti questa funzionalità tramite l'API History (o in casi limitati, modificando la parte #hash del sito), si tratta di una intricata API sviluppata molto prima che le SPA diventassero la norma e il web si sta aspettando un approccio completamente nuovo. L'API Navigation è un'API proposta che revisiona completamente questo ambito, anziché tentare semplicemente di modificare i punti deboli dell'API History. Ad esempio, scroll Restoration ha applicato la patch all'API History anziché provare a reinventarla.

Questo post descrive l'API di navigazione a livello generale. Se desideri leggere la proposta tecnica, consulta la bozza di rapporto nel repository WICG.

Esempio di utilizzo

Per utilizzare l'API Navigation, aggiungi innanzitutto un listener "navigate" all'oggetto navigation globale. Questo evento è fondamentalmente centralizzato: verrà attivato per tutti i tipi di navigazione, indipendentemente dal fatto che l'utente abbia eseguito un'azione (ad esempio fare clic su un link, inviare un modulo o andare avanti e indietro) o quando la navigazione viene attivata in modo programmatico (ovvero tramite il codice del tuo sito). Nella maggior parte dei casi, consente al codice di sostituire il comportamento predefinito del browser per tale azione. Per le APS, questo probabilmente significa mantenere l'utente sulla stessa pagina e caricare o modificare i contenuti del sito.

Al listener "navigate" viene trasmesso un NavigateEvent, che contiene informazioni sulla navigazione, come l'URL di destinazione, e ti consente di rispondere alla navigazione da un'unica posizione centralizzata. Un listener "navigate" di base potrebbe avere il seguente aspetto:

navigation.addEventListener('navigate', navigateEvent => {
  // Exit early if this navigation shouldn't be intercepted.
  // The properties to look at are discussed later in the article.
  if (shouldNotIntercept(navigateEvent)) return;

  const url = new URL(navigateEvent.destination.url);

  if (url.pathname === '/') {
    navigateEvent.intercept({handler: loadIndexPage});
  } else if (url.pathname === '/cats/') {
    navigateEvent.intercept({handler: loadCatsPage});
  }
});

Puoi gestire la navigazione in due modi:

  • Chiamata a intercept({ handler }) (come descritto sopra) per gestire la navigazione.
  • Chiamata al numero preventDefault() e la navigazione potrebbe essere annullata completamente.

Questo esempio chiama intercept() nell'evento. Il browser chiama il callback handler, che dovrebbe configurare lo stato successivo del sito. Verrà creato un oggetto di transizione, navigation.transition, che può essere utilizzato da altri codici per monitorare l'avanzamento della navigazione.

In genere, intercept() e preventDefault() sono consentiti, ma si verificano casi in cui non è possibile chiamarli. Non puoi gestire le navigazioni tramite intercept() se si tratta di una navigazione multiorigine. Inoltre, non puoi annullare una navigazione tramite preventDefault() se l'utente sta premendo i pulsanti Indietro o Avanti nel browser; non dovresti essere in grado di bloccare gli utenti sul tuo sito. (questo argomento è trattato su GitHub.)

Anche se non riesci a interrompere o intercettare la navigazione, l'evento "navigate" verrà comunque attivato. Poiché è informativo, il tuo codice potrebbe, ad esempio, registrare un evento Analytics per indicare che un utente sta uscendo dal sito.

Perché aggiungere un altro evento alla piattaforma?

Un listener di eventi "navigate" centralizza la gestione delle modifiche agli URL all'interno di un'APS. Si tratta di una proposta difficile quando si utilizzano API meno recenti. Se in passato hai creato i percorsi per la tua SPA utilizzando l'API History, potresti aver aggiunto un codice come il seguente:

function updatePage(event) {
  event.preventDefault(); // we're handling this link
  window.history.pushState(null, '', event.target.href);
  // TODO: set up page based on new URL
}
const links = [...document.querySelectorAll('a[href]')];
links.forEach(link => link.addEventListener('click', updatePage));

Questo va bene, ma non è esaustivo. I link possono entrare e uscire dalla tua pagina e non sono l'unico modo in cui gli utenti possono navigare tra le pagine. Ad esempio, possono inviare un modulo o anche utilizzare una mappa immagine. La tua pagina potrebbe gestire questi aspetti, ma c'è una lunga serie di possibilità che potrebbe essere semplicemente semplificata, un risultato raggiunto dalla nuova API di navigazione.

Inoltre, non gestisce la navigazione back-forward. C'è un altro evento per questo, "popstate".

Personalmente, l'API History spesso ritiene che potrebbe essere utile per queste possibilità. Tuttavia, in realtà ha solo due aree di superficie: rispondere se l'utente preme Indietro o Avanti nel browser, oltre a eseguire il push e la sostituzione degli URL. Non ha un'analogia con "navigate", a meno che, ad esempio, imposti manualmente i listener per gli eventi di clic, come mostrato sopra.

Decidere come gestire una navigazione

navigateEvent contiene molte informazioni sulla navigazione che puoi utilizzare per decidere come gestire una determinata navigazione.

Le proprietà principali sono:

canIntercept
Se è falso, non puoi intercettare la navigazione. Le navigazioni tra origini e gli attraversamenti tra documenti non possono essere intercettati.
destination.url
Probabilmente l'informazione più importante da considerare per la gestione della navigazione.
hashChange
True se la navigazione è nello stesso documento e l'hash è l'unica parte dell'URL diversa dall'URL corrente. Nelle APS moderne, l'hash deve essere utilizzato per il collegamento a parti diverse del documento corrente. Quindi, se hashChange è true, probabilmente non è necessario intercettare questa navigazione.
downloadRequest
Se questo è vero, la navigazione è stata avviata da un link con un attributo download. Nella maggior parte dei casi, non è necessario intercettare questi dati.
formData
Se questo valore non è null, significa che la navigazione fa parte dell'invio di un modulo POST. Assicurati di tenerne conto quando gestisci la navigazione. Se vuoi gestire solo le navigazioni GET, evita di intercettare le navigazioni in cui formData non è null. Consulta l'esempio sulla gestione degli invii di moduli più avanti nell'articolo.
navigationType
Questo è uno tra "reload", "push", "replace" o "traverse". Se è "traverse", non è possibile annullare questa navigazione tramite preventDefault().

Ad esempio, la funzione shouldNotIntercept utilizzata nel primo esempio potrebbe essere simile alla seguente:

function shouldNotIntercept(navigationEvent) {
  return (
    !navigationEvent.canIntercept ||
    // If this is just a hashChange,
    // just let the browser handle scrolling to the content.
    navigationEvent.hashChange ||
    // If this is a download,
    // let the browser perform the download.
    navigationEvent.downloadRequest ||
    // If this is a form submission,
    // let that go to the server.
    navigationEvent.formData
  );
}

Intercettazione

Quando il codice chiama intercept({ handler }) dal suo listener "navigate", informa il browser che sta preparando la pagina per il nuovo stato aggiornato e che la navigazione potrebbe richiedere del tempo.

Il browser inizia registrando la posizione di scorrimento per lo stato corrente, in modo che possa essere ripristinato facoltativamente in un secondo momento, quindi richiama il callback handler. Se handler restituisce una promessa (che avviene automaticamente con le async functions), questa promessa indica al browser il tempo necessario per la navigazione e se è riuscita.

navigation.addEventListener('navigate', navigateEvent => {
  if (shouldNotIntercept(navigateEvent)) return;
  const url = new URL(navigateEvent.destination.url);

  if (url.pathname.startsWith('/articles/')) {
    navigateEvent.intercept({
      async handler() {
        const articleContent = await getArticleContent(url.pathname);
        renderArticlePage(articleContent);
      },
    });
  }
});

Di conseguenza, questa API introduce un concetto semantico che il browser comprende: una navigazione SPA è attualmente in corso, nel tempo, cambiando il documento da un URL e uno stato precedenti a nuovi. Ciò presenta una serie di potenziali vantaggi, tra cui l'accessibilità: i browser possono mostrare l'inizio, la fine o il potenziale errore di una navigazione. Ad esempio, Chrome attiva l'indicatore di caricamento nativo e consente all'utente di interagire con il pulsante di interruzione. Al momento il problema non si verifica quando l'utente naviga utilizzando i pulsanti Indietro/Avanti, ma il problema verrà risolto a breve.

Quando vengono intercettate le navigazioni, il nuovo URL avrà effetto appena prima della chiamata del callback handler. Se non aggiorni immediatamente il DOM, verrà creato un periodo in cui i vecchi contenuti vengono visualizzati insieme al nuovo URL. Questo influisce su aspetti come la risoluzione dell'URL relativo durante il recupero dei dati o il caricamento di nuove risorse secondarie.

Un modo per ritardare la modifica dell'URL è esaminato su GitHub, ma in genere è consigliabile aggiornare immediatamente la pagina con una sorta di segnaposto per i contenuti in arrivo:

navigation.addEventListener('navigate', navigateEvent => {
  if (shouldNotIntercept(navigateEvent)) return;
  const url = new URL(navigateEvent.destination.url);

  if (url.pathname.startsWith('/articles/')) {
    navigateEvent.intercept({
      async handler() {
        // The URL has already changed, so quickly show a placeholder.
        renderArticlePagePlaceholder();
        // Then fetch the real data.
        const articleContent = await getArticleContent(url.pathname);
        renderArticlePage(articleContent);
      },
    });
  }
});

Questo non solo evita i problemi di risoluzione degli URL, ma risulta anche veloce perché rispondi immediatamente all'utente.

Interrompi indicatori

Poiché puoi eseguire il lavoro asincrono in un gestore intercept(), è possibile che la navigazione risulti ridondante. Questo si verifica quando:

  • L'utente fa clic su un altro link o sul codice esegue un'altra navigazione. In questo caso, la navigazione precedente viene abbandonata a favore di quella nuova.
  • L'utente fa clic sul pulsante di interruzione nel browser.

Per gestire una di queste possibilità, l'evento passato al listener "navigate" contiene una proprietà signal, ovvero AbortSignal. Per maggiori informazioni, consulta la sezione Recupero interrotto.

La versione breve consiste essenzialmente nel fornire un oggetto che attiva un evento nel momento in cui dovresti interrompere il lavoro. In particolare, puoi passare AbortSignal a tutte le chiamate che effettui a fetch(): in questo modo, le richieste di rete in volo verranno annullate se la navigazione viene prerilasciata. Ciò salverà la larghezza di banda dell'utente e rifiuterà il Promise restituito da fetch(), impedendo al seguente codice di azioni come l'aggiornamento del DOM per mostrare una navigazione nelle pagine ora non valida.

Questo è l'esempio precedente, ma con getArticleContent incorporato, che mostra come è possibile utilizzare AbortSignal con fetch():

navigation.addEventListener('navigate', navigateEvent => {
  if (shouldNotIntercept(navigateEvent)) return;
  const url = new URL(navigateEvent.destination.url);

  if (url.pathname.startsWith('/articles/')) {
    navigateEvent.intercept({
      async handler() {
        // The URL has already changed, so quickly show a placeholder.
        renderArticlePagePlaceholder();
        // Then fetch the real data.
        const articleContentURL = new URL(
          '/get-article-content',
          location.href
        );
        articleContentURL.searchParams.set('path', url.pathname);
        const response = await fetch(articleContentURL, {
          signal: navigateEvent.signal,
        });
        const articleContent = await response.json();
        renderArticlePage(articleContent);
      },
    });
  }
});

Gestione dello scorrimento

Quando intercept() una navigazione, il browser tenta di gestire automaticamente lo scorrimento.

Per le navigazioni verso una nuova voce della cronologia (quando navigationEvent.navigationType è "push" o "replace"), ciò significa tentare di scorrere fino alla parte indicata dal frammento di URL (il bit dopo #) o reimpostare lo scorrimento fino alla parte superiore della pagina.

Per i ricaricamenti e gli attraversamenti, devi ripristinare la posizione di scorrimento nel punto in cui si trovava l'ultima volta che la voce della cronologia è stata visualizzata.

Per impostazione predefinita, questo accade una volta risolta la promessa restituita da handler, ma se ha senso scorrere prima, puoi chiamare navigateEvent.scroll():

navigation.addEventListener('navigate', navigateEvent => {
  if (shouldNotIntercept(navigateEvent)) return;
  const url = new URL(navigateEvent.destination.url);

  if (url.pathname.startsWith('/articles/')) {
    navigateEvent.intercept({
      async handler() {
        const articleContent = await getArticleContent(url.pathname);
        renderArticlePage(articleContent);
        navigateEvent.scroll();

        const secondaryContent = await getSecondaryContent(url.pathname);
        addSecondaryContent(secondaryContent);
      },
    });
  }
});

In alternativa, puoi disattivare completamente la gestione automatica dello scorrimento impostando l'opzione scroll di intercept() su "manual":

navigateEvent.intercept({
  scroll: 'manual',
  async handler() {
    // …
  },
});

Gestione della messa a fuoco

Una volta risolta la promessa restituita da handler, il browser concentrerà il primo elemento con l'attributo autofocus impostato o l'elemento <body> se nessun elemento ha questo attributo.

Puoi disattivare questo comportamento impostando l'opzione focusReset di intercept() su "manual":

navigateEvent.intercept({
  focusReset: 'manual',
  async handler() {
    // …
  },
});

Eventi di successo e fallimento

Quando viene chiamato il gestore intercept(), si verifica una delle due seguenti situazioni:

  • Se l'oggetto Promise restituito viene soddisfatto (o non hai chiamato intercept()), l'API di navigazione attiverà "navigatesuccess" con un Event.
  • Se l'oggetto Promise restituito rifiuta, l'API attiverà "navigateerror" con un ErrorEvent.

Questi eventi consentono al tuo codice di gestire le operazioni riuscite o non riuscite in modo centralizzato. Ad esempio, per ottenere risultati ottimali, nascondendo un indicatore di avanzamento visualizzato in precedenza, come questo:

navigation.addEventListener('navigatesuccess', event => {
  loadingIndicator.hidden = true;
});

In alternativa, in caso di errore potresti visualizzare un messaggio di errore:

navigation.addEventListener('navigateerror', event => {
  loadingIndicator.hidden = true; // also hide indicator
  showMessage(`Failed to load page: ${event.message}`);
});

Il listener di eventi "navigateerror", che riceve un ErrorEvent, è particolarmente utile perché garantisce la ricezione di eventuali errori dal codice che determina la configurazione di una nuova pagina. Puoi semplicemente await fetch() sapendo che se la rete non è disponibile, l'errore verrà inoltrato a "navigateerror".

navigation.currentEntry fornisce accesso alla voce corrente. Questo è un oggetto che descrive la posizione attuale dell'utente. Questa voce include l'URL corrente, i metadati che possono essere utilizzati per identificare la voce nel tempo e lo stato fornito dallo sviluppatore.

I metadati includono key, una proprietà stringa univoca di ogni voce che rappresenta la voce corrente e il relativo slot. Questa chiave rimane invariata anche se l'URL o lo stato della voce corrente cambia. Si trova ancora nello stesso spazio. Al contrario, se un utente preme Indietro e poi riapre la stessa pagina, key cambierà man mano che questa nuova voce crea un nuovo spazio.

Per uno sviluppatore, key è utile perché l'API di navigazione consente di indirizzare direttamente l'utente a una voce con una chiave di corrispondenza. Puoi conservarlo, anche negli stati di altre voci, per passare facilmente da una pagina all'altra.

// On JS startup, get the key of the first loaded page
// so the user can always go back there.
const {key} = navigation.currentEntry;
backToHomeButton.onclick = () => navigation.traverseTo(key);

// Navigate away, but the button will always work.
await navigation.navigate('/another_url').finished;

Stato

L'API di navigazione segnala lo "stato", ovvero informazioni fornite dallo sviluppatore archiviate in modo permanente sulla voce corrente della cronologia, ma che non sono direttamente visibili all'utente. È molto simile, ma è migliorato, rispetto a history.state nell'API History.

Nell'API di navigazione, puoi chiamare il metodo .getState() della voce corrente (o di qualsiasi voce) per restituire una copia del suo stato:

console.log(navigation.currentEntry.getState());

Il valore predefinito è undefined.

Stato dell'impostazione

Sebbene gli oggetti di stato possano essere mutati, queste modifiche non vengono salvate con la voce della cronologia, pertanto:

const state = navigation.currentEntry.getState();
console.log(state.count); // 1
state.count++;
console.log(state.count); // 2
// But:
console.info(navigation.currentEntry.getState().count); // will still be 1

Il modo corretto per impostare lo stato è durante la navigazione degli script:

navigation.navigate(url, {state: newState});
// Or:
navigation.reload({state: newState});

Dove newState può essere qualsiasi oggetto clonabile.

Se vuoi aggiornare lo stato della voce corrente, è preferibile effettuare una navigazione che sostituisca la voce corrente:

navigation.navigate(location.href, {state: newState, history: 'replace'});

A questo punto, il listener di eventi "navigate" potrà rilevare questa modifica tramite navigateEvent.destination:

navigation.addEventListener('navigate', navigateEvent => {
  console.log(navigateEvent.destination.getState());
});

Aggiornamento dello stato sincrono

In genere, è meglio aggiornare lo stato in modo asincrono tramite navigation.reload({state: newState}), dopodiché il listener "navigate" potrà applicarlo. Tuttavia, a volte il cambiamento di stato è già stato completamente applicato nel momento in cui il codice viene a conoscenza del problema, ad esempio quando l'utente attiva/disattiva un elemento <details> o cambia lo stato di un input di modulo. In questi casi, ti consigliamo di aggiornare lo stato in modo che le modifiche vengano mantenute attraverso ricaricamenti e attraversamenti. Ciò è possibile utilizzando updateCurrentEntry():

navigation.updateCurrentEntry({state: newState});

C'è anche un evento per cui venire a conoscenza di questo cambiamento:

navigation.addEventListener('currententrychange', () => {
  console.log(navigation.currentEntry.getState());
});

Tuttavia, se ti ritrovi a reagire ai cambiamenti di stato in "currententrychange", potresti dividere o addirittura duplicare il tuo codice di gestione dello stato tra l'evento "navigate" e l'evento "currententrychange", mentre navigation.reload({state: newState}) ti consentirebbe di gestirlo in un unico posto.

Confronto tra parametri URL e stato

Poiché lo stato può essere un oggetto strutturato, si potrebbe avere la tentazione di utilizzarlo per tutto lo stato dell'applicazione. Tuttavia, in molti casi è meglio memorizzare quello stato nell'URL.

Se prevedi che lo stato venga mantenuto quando l'utente condivide l'URL con un altro utente, memorizzalo nell'URL. In caso contrario, l'oggetto di stato è l'opzione migliore.

Accedi a tutte le voci

Tuttavia, la "voce corrente" non è solo. L'API consente inoltre di accedere all'intero elenco di voci esplorate da un utente mentre utilizzava il tuo sito tramite la chiamata navigation.entries(), che restituisce un array di voci snapshot. Questa funzionalità può essere utilizzata, ad esempio, per mostrare un'interfaccia utente diversa in base a come l'utente ha raggiunto una determinata pagina o semplicemente per esaminare gli URL o i relativi stati precedenti. Ciò non è possibile con l'API History attuale.

Puoi anche rimanere in ascolto di un evento "dispose" su singoli NavigationHistoryEntry, che viene attivato quando la voce non fa più parte della cronologia del browser. Questo può accadere durante una pulizia generale, ma anche durante la navigazione. Ad esempio, se ritorni indietro di 10 luoghi e poi passi avanti, le 10 voci della cronologia verranno eliminate.

Esempi

L'evento "navigate" si attiva per tutti i tipi di navigazione, come indicato sopra. Esiste una lunga appendice nelle specifiche relative a tutti i tipi possibili.

Sebbene per molti siti il caso più comune si verifichi quando l'utente fa clic su un <a href="...">, ci sono due tipi di navigazione importanti e più complessi che vale la pena trattare.

Navigazione programmatica

La prima è la navigazione programmatica, in cui la navigazione è causata da una chiamata al metodo all'interno del codice lato client.

Puoi chiamare navigation.navigate('/another_page') da qualsiasi punto del codice per attivare una navigazione. Questa operazione verrà gestita dal listener di eventi centralizzato registrato nel listener "navigate" e il listener centralizzato verrà chiamato in modo sincrono.

Il suo scopo è una migliore aggregazione dei metodi precedenti come location.assign() e degli amici, nonché dei metodi pushState() e replaceState() dell'API History.

Il metodo navigation.navigate() restituisce un oggetto che contiene due istanze Promise in { committed, finished }. In questo modo l'invocatore può attendere fino a quando la transizione non viene "commessa" (l'URL visibile è cambiato ed è disponibile un nuovo NavigationHistoryEntry) o "terminata" (tutte le promesse restituite da intercept({ handler }) sono complete o rifiutate, a causa di un errore o prerilasciata da un'altra navigazione).

Il metodo navigate ha anche un oggetto opzioni in cui puoi impostare:

  • state: lo stato della nuova voce della cronologia, disponibile tramite il metodo .getState() in NavigationHistoryEntry.
  • history: che può essere impostato su "replace" per sostituire la voce attuale della cronologia.
  • info: un oggetto da passare all'evento di navigazione tramite navigateEvent.info.

In particolare, info può essere utile, ad esempio, per indicare una particolare animazione che attiva la visualizzazione della pagina successiva. L'alternativa potrebbe essere impostare una variabile globale o includerla come parte di #hash. Entrambe le opzioni sono un po' imbarazzanti.) In particolare, questo info non verrà riprodotto se in un secondo momento un utente attiva la navigazione, ad esempio tramite i pulsanti Avanti e Indietro. Infatti, in questi casi sarà sempre undefined.

Demo dell'apertura da sinistra o da destra

navigation offre anche una serie di altri metodi di navigazione, che restituiscono tutti un oggetto contenente { committed, finished }. Ho già menzionato traverseTo() (che accetta uno key che indica una voce specifica nella cronologia dell'utente) e navigate(). Sono inclusi anche back(), forward() e reload(). Tutti questi metodi vengono gestiti, proprio come navigate(), dal listener di eventi centralizzato di "navigate".

Invii di moduli

In secondo luogo, l'invio dell'HTML <form> tramite POST è un tipo speciale di navigazione e l'API di navigazione può intercettarlo. Anche se include un payload aggiuntivo, la navigazione è comunque gestita a livello centrale dal listener "navigate".

L'invio del modulo può essere rilevato cercando la proprietà formData in NavigateEvent. Ecco un esempio che trasforma semplicemente qualsiasi modulo inviato in uno che rimane nella pagina corrente tramite fetch():

navigation.addEventListener('navigate', navigateEvent => {
  if (navigateEvent.formData && navigateEvent.canIntercept) {
    // User submitted a POST form to a same-domain URL
    // (If canIntercept is false, the event is just informative:
    // you can't intercept this request, although you could
    // likely still call .preventDefault() to stop it completely).

    navigateEvent.intercept({
      // Since we don't update the DOM in this navigation,
      // don't allow focus or scrolling to reset:
      focusReset: 'manual',
      scroll: 'manual',
      handler() {
        await fetch(navigateEvent.destination.url, {
          method: 'POST',
          body: navigateEvent.formData,
        });
        // You could navigate again with {history: 'replace'} to change the URL here,
        // which might indicate "done"
      },
    });
  }
});

Cosa manca?

Nonostante la natura centralizzata del listener di eventi "navigate", l'attuale specifica dell'API Navigation non attiva "navigate" al primo caricamento di una pagina. Per i siti che utilizzano il rendering lato server (SSR) per tutti gli stati, questo potrebbe essere sufficiente perché il server potrebbe restituire lo stato iniziale corretto, che è il modo più veloce per fornire contenuti agli utenti. Tuttavia, i siti che sfruttano il codice lato client per creare le proprie pagine potrebbero dover creare una funzione aggiuntiva per inizializzare la pagina.

Un'altra scelta di progettazione intenzionale dell'API di navigazione è che opera solo all'interno di un singolo frame, ovvero la pagina di primo livello o un singolo elemento <iframe> specifico. Ciò presenta una serie di implicazioni interessanti che sono più documentate nella specifica, ma che nella pratica ridurranno la confusione degli sviluppatori. L'API History precedente presenta una serie di casi limite poco chiari, come il supporto dei frame, e l'API di navigazione reinventata gestisce questi casi limite fin dall'inizio.

Infine, non c'è ancora un consenso sulla modifica o riorganizzazione programmatica dell'elenco di voci che l'utente ha sfogliato. Questo argomento è attualmente in fase di discussione, ma un'opzione potrebbe essere consentire solo le eliminazioni: voci storiche o "tutte le voci future". mentre la seconda consente lo stato temporaneo. Ad esempio, in qualità di sviluppatore potrei:

  • Fai una domanda all'utente passando al nuovo URL o stato
  • consentire all'utente di completare il proprio lavoro (o tornare indietro)
  • rimuovere una voce della cronologia al completamento di un'attività

Questo potrebbe essere perfetto per gli annunci modali temporanei o interstitial: un utente può utilizzare il gesto Indietro per uscire dal nuovo URL, ma non può andare avanti per aprirlo di nuovo (perché la voce è stata rimossa). Ciò non è possibile con l'attuale API History.

Prova l'API di navigazione

L'API Navigation è disponibile nella versione 102 di Chrome senza flag. Puoi anche provare una demo di Domenic Denicola.

Sebbene sembri chiara, l'API History classica non è molto ben definita e presenta un gran numero di problemi intorno ai casi d'angolo e in che modo è stata implementata in modo diverso da un browser all'altro. Ci auguriamo che tu voglia inviarci il tuo feedback sulla nuova API di navigazione.

Riferimenti

Ringraziamenti

Ringraziamo Thomas Steiner, Domenic Denicola e Nate Chapin per aver recensito questo post. Immagine hero da Unsplash, di Jeremy Zero.