Routing lato client moderno: API Navigation

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

[Nome di persona]
Sam Thorogood
Jake Archibald
Jake Archibald

Supporto dei browser

  • 102
  • 102
  • x
  • x

Fonte

Le applicazioni a pagina singola, o APS, sono definite da una funzionalità di base che riscrive in modo dinamico i contenuti mentre l'utente interagisce con il sito, anziché il metodo predefinito di caricamento di pagine completamente nuove dal server.

Sebbene le APS siano state in grado di offrirti questa funzionalità tramite l'API History (o in casi limitati, modificando la parte #hash del sito), si tratta di un'API confusa sviluppata molto prima che le APS diventassero la norma e il web chiede un approccio completamente nuovo. L'API Navigation è un'API proposta che riorganizza completamente questo spazio, anziché tentare semplicemente di applicare patch ai margini dell'API History. Ad esempio, Scroll Restoration ha applicato la patch all'API History anziché provare a reinventarla.

Questo post descrive ad alto livello l'API Navigation. Se vuoi leggere la proposta tecnica, consulta la bozza di report nel repository WICG.

Esempio di utilizzo

Per utilizzare l'API Navigation, inizia aggiungendo un listener "navigate" all'oggetto navigation globale. Questo evento è fondamentalmente centralizzato: si attiva per tutti i tipi di navigazioni, sia 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 ignorare il comportamento predefinito del browser per quell'azione. Per le APS, ciò probabilmente significa mantenere l'utente sulla stessa pagina e caricare o modificare i contenuti del sito.

Un NavigateEvent viene trasmesso al listener "navigate" 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 in precedenza) per gestire la navigazione.
  • Chiamata a preventDefault(). L'operazione può annullare completamente la navigazione.

In questo esempio viene chiamato 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 altro codice per monitorare l'avanzamento della navigazione.

Sia intercept() che preventDefault() sono in genere consentiti, ma ci sono 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 preme i pulsanti Indietro o Avanti del browser; non dovresti riuscire a bloccare gli utenti sul tuo sito. (Questo argomento è in corso su GitHub.)

Anche se non riesci a interrompere o intercettare la navigazione stessa, l'evento "navigate" continuerà a essere attivato. È informativo, quindi il codice potrebbe, ad esempio, registrare un evento Analytics per indicare che un utente sta per abbandonare il 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. Questa è una proposta difficile quando si usano API meno recenti. Se ti è capitato di scrivere il routing per il tuo SPA utilizzando l'API History, potresti aver aggiunto un codice simile al 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 finire all'interno della pagina e non sono l'unico modo per consentire agli utenti di navigare tra le pagine. Ad esempio, possono inviare un modulo o persino utilizzare una mappa immagine. La tua pagina potrebbe trattare questi aspetti, ma c'è una lunga serie di possibilità che potrebbero essere semplificate, un risultato raggiunto dalla nuova API di navigazione.

Inoltre, quanto riportato sopra non consente di gestire la navigazione a ritroso e indietro. C'è un altro evento per questo, "popstate".

Personalmente, l'API History spesso ritiene che possa essere d'aiuto in queste possibilità. Tuttavia, presenta solo due aree: 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", tranne nel caso in cui, ad esempio, imposti i listener per gli eventi di clic manualmente, come mostrato sopra.

Decidere come gestire una navigazione

Il 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 multiorigine e i attraversamenti tra documenti non possono essere intercettati.
destination.url
È probabilmente l'informazione più importante da considerare durante la gestione della navigazione.
hashChange
True se la navigazione è sullo stesso documento e l'hash è l'unica parte dell'URL diversa dall'URL corrente. Nelle APS moderne, l'hash deve essere usato per rimandare a diverse parti del documento corrente. Quindi, se hashChange è true, probabilmente non è necessario intercettare questa navigazione.
downloadRequest
Se è vero, la navigazione è stata avviata da un link con un attributo download. Nella maggior parte dei casi, non è necessario intercettarlo.
formData
Se il valore non è null, 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
È un'opzione 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 a questa:

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 }) dall'interno del 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 ad acquisire la posizione di scorrimento per lo stato corrente, quindi può essere facoltativamente ripristinato in un secondo momento, quindi chiama il callback handler. Se il tuo handler restituisce una promessa (che avviene automaticamente con le async functions), questa promessa indica al browser quanto tempo richiede la navigazione e se ha esito positivo.

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 atto, nel corso del tempo, cambiando il documento da un URL precedente e uno stato a uno nuovo. Ciò presenta una serie di potenziali vantaggi, tra cui l'accessibilità: i browser possono far emergere l'inizio, la fine o i potenziali errori di una navigazione. Chrome, ad esempio, attiva l'indicatore di caricamento nativo e consente all'utente di interagire con il pulsante di interruzione. Al momento questo problema non si verifica quando l'utente naviga utilizzando i pulsanti Indietro/Avanti, ma verrà risolto a breve.

Quando intercetti le navigazioni, il nuovo URL diventerà effettivo subito prima della chiamata del callback handler. Se non aggiorni subito il DOM, viene creato un periodo in cui vengono visualizzati i contenuti precedenti insieme al nuovo URL. Questo influisce, ad esempio, sulla risoluzione relativa dell'URL durante il recupero dei dati o il caricamento di nuove risorse secondarie.

Un modo per ritardare la modifica dell'URL è in discussione su GitHub, ma in genere è consigliabile aggiornare immediatamente la pagina con un 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 è anche molto veloce perché rispondi immediatamente all'utente.

Segnali di interruzione

Poiché puoi svolgere un lavoro asincrono in un gestore intercept(), la navigazione potrebbe diventare ridondante. Ciò si verifica quando:

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

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

La versione breve è fondamentalmente fornisce un oggetto che attiva un evento quando dovresti interrompere il tuo lavoro. In particolare, puoi passare AbortSignal a tutte le chiamate che effettui al numero fetch(), il che annullerà le richieste di rete in volo se la navigazione viene prerilasciata. Questa operazione salverà la larghezza di banda dell'utente e rifiuterà il Promise restituito da fetch(), impedendo l'esecuzione di azioni quali l'aggiornamento del DOM per mostrare una navigazione nelle pagine ora non valida.

Ecco l'esempio precedente, ma con getArticleContent incorporato, che mostra come AbortSignal può essere usato 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 tenterà di gestire lo scorrimento automaticamente.

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 i attraversamenti, ciò significa ripristinare la posizione di scorrimento alla posizione che si trovava l'ultima volta che questa voce della cronologia è stata visualizzata.

Per impostazione predefinita, ciò si verifica una volta risolta la promessa restituita dal tuo handler, ma se hai 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 dello scorrimento automatico impostando l'opzione scroll di intercept() su "manual":

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

Gestione dello stato attivo

Una volta risolta la promessa restituita da handler, il browser attiverà 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 di errore

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

  • Se il valore Promise restituito soddisfa (o non hai chiamato intercept()), l'API Navigation attiverà "navigatesuccess" con un Event.
  • Se il criterio Promise restituito viene rifiutato, l'API attiverà "navigateerror" con un ErrorEvent.

Questi eventi consentono al codice di gestire il successo o gli errori in modo centralizzato. Ad esempio, potresti avere successo nascondendo un indicatore di avanzamento mostrato in precedenza, come questo:

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

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 messaggio ErrorEvent, è particolarmente pratico in quanto gli eventuali errori ricevuti dal codice durante la configurazione di una nuova pagina sono garantiti. Puoi semplicemente await fetch(), sapendo che se la rete non è disponibile, l'errore verrà inoltrato a "navigateerror".

navigation.currentEntry fornisce l'accesso alla voce corrente. Si tratta di un oggetto che descrive dove si trova l'utente in questo momento. 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 cambia l'URL o lo stato della voce corrente. Si trova sempre nello stesso slot. Al contrario, se un utente preme Indietro e poi riapre la stessa pagina, key cambierà perché questa nuova voce crea un nuovo spazio.

Per uno sviluppatore, key è utile perché l'API di navigazione consente di far arrivare direttamente l'utente a una voce con una chiave di corrispondenza. Puoi mantenerlo, 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 Navigation mostra la nozione di "stato", ovvero informazioni fornite dallo sviluppatore che vengono memorizzate in modo permanente nella voce corrente della cronologia, ma non direttamente visibili all'utente. Questo valore è estremamente simile a history.state nell'API History, ma è migliorato rispetto a quest'ultimo.

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

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

Per impostazione predefinita, è undefined.

Stato dell'impostazione

Anche se gli oggetti di stato possono essere modificati, queste modifiche non vengono salvate con la voce della cronologia, quindi:

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 nello 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 eseguire una navigazione che sostituisca la voce corrente:

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

In seguito, il tuo listener di eventi "navigate" potrà rilevare questa modifica tramite navigateEvent.destination:

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

Aggiornamento dello stato in modo sincrono

In genere, è meglio aggiornare lo stato in modo asincrono tramite navigation.reload({state: newState}), in modo che il listener "navigate" possa applicare questo stato. Tuttavia, a volte la modifica dello stato è già stata applicata completamente nel momento in cui il codice ne viene a conoscenza, ad esempio quando l'utente attiva/disattiva un elemento <details> o cambia lo stato dell'input di un modulo. In questi casi, ti consigliamo di aggiornare lo stato in modo che le modifiche vengano mantenute tramite ricaricamenti e attraversamenti. Questo è possibile utilizzando updateCurrentEntry():

navigation.updateCurrentEntry({state: newState});

C'è anche un evento per 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 persino duplicare il tuo codice di stato tra l'evento "navigate" e l'evento "currententrychange", mentre navigation.reload({state: newState}) ti consentirebbe di gestirlo in un unico posto.

Parametri stato e URL

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 archiviare lo stato nell'URL.

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

Accedi a tutte le voci

Tuttavia, la "voce attuale" non è tutta. L'API fornisce anche un modo per accedere all'intero elenco di voci visitate da un utente durante la navigazione del tuo sito tramite la sua chiamata navigation.entries(), che restituisce un array di istantanee di voci. Questa funzionalità potrebbe essere utilizzata, ad esempio, per mostrare un'interfaccia utente diversa in base al modo in cui l'utente è arrivato a una determinata pagina o semplicemente per esaminare gli URL precedenti o i loro stati. Questo è impossibile con l'attuale API History.

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

Esempi

L'evento "navigate" viene attivato per tutti i tipi di navigazione, come indicato sopra. In realtà esiste una lunga appendice nelle specifiche di tutti i tipi possibili.

Per molti siti il caso più comune si verifica quando l'utente fa clic su un <a href="...">, ma esistono due tipi di navigazione rilevanti e più complessi che vale la pena trattare.

Navigazione programmatica

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

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

Si tratta di una migliore aggregazione dei metodi meno recenti, come location.assign() e friends, e 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'invoker può attendere fino a quando la transizione non viene "confermata" (l'URL visibile è cambiato e un nuovo elemento NavigationHistoryEntry è disponibile) o "completata" (tutte le promesse restituite da intercept({ handler }) sono state completate o rifiutate a causa di un errore o sono state prerilasciate 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 con 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 determina la visualizzazione della pagina successiva. L'alternativa potrebbe essere impostare una variabile globale o includerla all'interno del parametro #hash. Entrambe le opzioni sono un po' imbarazzanti.) In particolare, questa info non verrà riprodotta se un utente in un secondo momento causa la navigazione, ad esempio tramite i pulsanti Indietro e Avanti. Di fatto, in questi casi sarà sempre undefined.

Dimostrazione dell'apertura da sinistra o destra

navigation offre anche una serie di altri metodi di navigazione, tutti che restituiscono un oggetto contenente { committed, finished }. Ho già menzionato traverseTo() (che accetta 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 "navigate" centralizzato.

Invii di moduli

In secondo luogo, l'invio di <form> HTML tramite POST è un tipo speciale di navigazione e l'API di navigazione è in grado di intercettarlo. Anche se include un payload aggiuntivo, la navigazione viene comunque gestita centralmente dal listener "navigate".

L'invio del modulo può essere rilevato cercando la proprietà formData nella NavigateEvent. Ecco un esempio che trasforma semplicemente qualsiasi modulo inviato in un modulo 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 non essere un problema: il server potrebbe restituire lo stato iniziale corretto, che è il modo più veloce per inviare contenuti agli utenti. Tuttavia, i siti che utilizzano il codice lato client per creare le pagine potrebbero dover creare una funzione aggiuntiva per inizializzare la pagina.

Un'altra scelta intenzionale di progettazione dell'API Navigation è che operi solo all'interno di un singolo frame, cioè la pagina di primo livello o un singolo <iframe> specifico. Ciò ha una serie di implicazioni interessanti che sono ulteriormente documentate nelle specifiche, ma in pratica ridurranno la confusione degli sviluppatori. La precedente API History ha una serie di casi limite confusi, come il supporto per i frame, e l'API Navigation reinventata gestisce questi casi limite sin dall'inizio.

Infine, non c'è ancora consenso sulla modifica o sul riordinamento programmatico dell'elenco delle voci in cui l'utente ha navigato. Questa opzione è attualmente in fase di discussione, ma un'opzione potrebbe essere consentire solo le eliminazioni: le voci storiche o "tutte le voci future". Quest'ultimo consentirebbe lo stato temporaneo. Ad esempio, in qualità di sviluppatore, ho potuto:

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

Questa opzione potrebbe essere perfetta per creatività modali o interstitial temporanee: il nuovo URL è qualcosa da cui un utente può uscire utilizzando il gesto Indietro, ma poi non può andare avanti per aprirlo di nuovo (perché la voce è stata rimossa). Questo non è possibile con l'attuale API History.

Prova l'API Navigation

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

Sebbene la versione classica dell'API History sembri semplice, non è molto ben definita e presenta un gran numero di problemi nei casi d'angolo e in che modo è stata implementata in modo diverso a seconda del browser. Ci auguriamo che tu voglia fornire un feedback sulla nuova API Navigation.

Riferimenti

Ringraziamenti

Grazie a Thomas Steiner, Domenic Denicola e Nate Chapin per la recensione di questo post. Immagine hero di Unsplash, di Jeremy Zero.