Standardizzazione del routing lato client tramite una nuova API che rivoluziona completamente la creazione di applicazioni a pagina singola.
Le applicazioni a pagina singola (SPA) sono definite da una funzionalità principale: la riscrittura dinamica dei contenuti man mano che l'utente interagisce con il sito, anziché il metodo predefinito di caricamento di pagine completamente nuove dal server.
Sebbene le SPA siano 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 macchinosa sviluppata molto prima che le SPA diventassero la norma e il web richiede un approccio completamente nuovo. L'API Navigation è un'API proposta che rivoluziona completamente questo spazio, anziché cercare di correggere semplicemente i difetti dell'API History. Ad esempio, Scroll Restoration ha applicato una patch all'API History anziché cercare di reinventarla.
Questo post descrive l'API Navigation a livello generale. Per 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 globale navigation.
Questo evento è fondamentalmente centralizzato: viene 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 che la navigazione venga attivata a livello di programmazione (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, probabilmente significa mantenere l'utente sulla stessa pagina e caricare o modificare i contenuti del sito.
Un NavigateEvent viene passato al listener "navigate", che contiene informazioni sulla navigazione, come l'URL di destinazione, e ti consente di rispondere alla navigazione in un unico punto centralizzato.
Un ascoltatore di "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:
- Chiamando
intercept({ handler })(come descritto sopra) per gestire la navigazione. - Chiamando
preventDefault(), che può annullare completamente la navigazione.
Questo esempio chiama intercept() sull'evento.
Il browser chiama il callback handler, che deve configurare lo stato successivo del sito.
Verrà creato un oggetto di transizione, navigation.transition, che altro codice può utilizzare per monitorare l'avanzamento della navigazione.
In genere, sia intercept() che preventDefault() sono consentiti, ma in alcuni casi non è possibile chiamarli.
Non puoi gestire le navigazioni tramite intercept() se la navigazione è tra origini diverse.
Inoltre, non puoi annullare una navigazione tramite preventDefault() se l'utente preme i pulsanti Indietro o Avanti nel browser. Non devi poter intrappolare gli utenti sul tuo sito.
(Questo argomento è in discussione su GitHub).
Anche se non puoi interrompere o intercettare la navigazione stessa, l'evento "navigate" verrà comunque attivato.
È informativo, quindi il tuo codice potrebbe, ad esempio, registrare un evento Analytics per indicare che un utente sta abbandonando il tuo sito.
Perché aggiungere un altro evento alla piattaforma?
Un listener di eventi "navigate" centralizza la gestione delle modifiche degli URL all'interno di una SPA.
Si tratta di una proposta difficile da realizzare utilizzando API precedenti.
Se hai mai scritto il routing per la tua SPA utilizzando l'API History, potresti aver aggiunto un codice simile a questo:
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));
Va bene, ma non è esaustivo. I link possono comparire e scomparire dalla pagina e non sono l'unico modo in cui gli utenti possono navigare tra le pagine. Ad esempio, possono inviare un modulo o persino utilizzare una mappa immagine. La tua pagina potrebbe occuparsi di questi aspetti, ma esiste una lunga serie di possibilità che potrebbero essere semplificate, cosa che la nuova API Navigation consente di fare.
Inoltre, quanto sopra non gestisce la navigazione avanti/indietro. C'è un altro evento per questo, "popstate".
Personalmente, l'API History spesso sembra in grado di contribuire a queste possibilità.
Tuttavia, ha solo due aree di superficie: la risposta se l'utente preme Indietro o Avanti nel browser, oltre all'invio e alla sostituzione degli URL.
Non ha un'analogia con "navigate", tranne se configuri manualmente i listener per gli eventi di clic, ad esempio, come mostrato sopra.
Decidere come gestire una navigazione
Il navigateEvent contiene molte informazioni sulla navigazione che puoi utilizzare per decidere come gestire una navigazione specifica.
Le proprietà principali sono:
canIntercept- Se il valore è false, non puoi intercettare la navigazione. Le navigazioni multiorigine e gli attraversamenti tra documenti non possono essere intercettati.
destination.url- Probabilmente l'informazione più importante da considerare quando si gestisce la navigazione.
hashChange- Vero se la navigazione avviene nello stesso documento e l'hash è l'unica parte dell'URL diversa dall'URL corrente.
Nelle SPA moderne, l'hash deve essere utilizzato per collegarsi a diverse parti del documento corrente. Pertanto, se
hashChangeè true, probabilmente non devi intercettare questa navigazione. downloadRequest- Se questo valore è true, la navigazione è stata avviata da un link con un attributo
download. Nella maggior parte dei casi, non è necessario intercettare questa richiesta. formData- Se questo valore non è nullo, 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
formDatanon è null. Vedi l'esempio sulla gestione degli invii di moduli più avanti nell'articolo. navigationType- Questo valore è uno tra
"reload","push","replace"o"traverse". Se è"traverse", la navigazione non può essere annullata tramitepreventDefault().
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", comunica al browser che sta preparando la pagina per il nuovo stato aggiornato e che la navigazione potrebbe richiedere un po' di tempo.
Il browser inizia acquisendo la posizione di scorrimento per lo stato attuale, in modo che possa essere ripristinata in un secondo momento, quindi chiama il callback handler.
Se handler restituisce una promessa (cosa che accade automaticamente con le funzioni asincrone), questa indica al browser la durata della 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);
},
});
}
});
Pertanto, questa API introduce un concetto semantico che il browser comprende: al momento è in corso una navigazione SPA che, nel tempo, modifica il documento da un URL e uno stato precedenti a uno nuovo. Ciò comporta una serie di potenziali vantaggi, tra cui l'accessibilità: i browser possono mostrare l'inizio, la fine o il potenziale errore di una navigazione. Chrome, ad esempio, attiva il suo indicatore di caricamento nativo e consente all'utente di interagire con il pulsante Interrompi. Al momento questo non accade quando l'utente naviga tramite i pulsanti Indietro/Avanti, ma il problema verrà risolto a breve.
Conferma della navigazione
Quando intercetti le navigazioni, il nuovo URL avrà effetto poco prima che venga chiamata la tua funzione di callback handler.
Se non aggiorni immediatamente il DOM, si crea un periodo in cui i vecchi contenuti vengono visualizzati insieme al nuovo URL.
Ciò influisce su aspetti come la risoluzione degli URL relativi durante il recupero dei dati o il caricamento di nuove risorse secondarie.
Un modo per ritardare la modifica dell'URL è in fase di discussione 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);
},
});
}
});
In questo modo non solo si evitano problemi di risoluzione degli URL, ma la risposta è anche più rapida perché rispondi immediatamente all'utente.
Segnali di interruzione
Poiché puoi eseguire operazioni asincrone in un gestore intercept(), è possibile che la navigazione diventi ridondante.
Ciò si verifica quando:
- L'utente fa clic su un altro link o un codice esegue un'altra navigazione. In questo caso, la vecchia navigazione viene abbandonata a favore di quella nuova.
- L'utente fa clic sul pulsante "Interrompi" nel browser.
Per gestire una di queste possibilità, l'evento passato al listener "navigate" contiene una proprietà signal, che è un AbortSignal.
Per saperne di più, consulta Recupero annullabile.
In breve, fornisce un oggetto che attiva un evento quando devi interrompere il lavoro.
In particolare, puoi passare un AbortSignal a qualsiasi chiamata che effettui a fetch(), che annullerà le richieste di rete in volo se la navigazione viene interrotta.
In questo modo, la larghezza di banda dell'utente viene salvata e il Promise restituito da fetch() viene rifiutato, impedendo a qualsiasi codice successivo di eseguire azioni come l'aggiornamento del DOM per mostrare una navigazione di pagina ora non valida.
Ecco l'esempio precedente, ma con getArticleContent in linea, che mostra come AbortSignal può essere utilizzato 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 lo scorrimento automaticamente.
Per la navigazione in una nuova voce della cronologia (quando navigationEvent.navigationType è "push" o "replace"), ciò significa tentare di scorrere fino alla parte indicata dal frammento di URL (la parte dopo #) o reimpostare lo scorrimento all'inizio della pagina.
Per i ricaricamenti e gli spostamenti, ciò significa ripristinare la posizione di scorrimento all'ultima volta che è stata visualizzata questa voce della cronologia.
Per impostazione predefinita, questa operazione viene eseguita una volta risolta la promessa restituita da handler, ma se è opportuno scorrere in precedenza, 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 del focus
Una volta risolta la promessa restituita da handler, il browser si concentrerà sul primo elemento con l'attributo autofocus impostato o sull'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 esito positivo e negativo
Quando viene chiamato il gestore intercept(), si verifica una delle due seguenti situazioni:
- Se il valore
Promiserestituito soddisfa la condizione (o se non hai chiamatointercept()), l'API Navigation attiverà"navigatesuccess"con unEvent. - Se il valore
Promiserestituito viene rifiutato, l'API attiverà"navigateerror"con un valoreErrorEvent.
Questi eventi consentono al tuo codice di gestire la riuscita o il mancato completamento in modo centralizzato. Ad esempio, potresti gestire l'esito positivo nascondendo un indicatore di avanzamento visualizzato in precedenza, come questo:
navigation.addEventListener('navigatesuccess', event => {
loadingIndicator.hidden = true;
});
Oppure potresti mostrare un messaggio di errore in caso 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é riceve sicuramente tutti gli errori del codice che configura una nuova pagina.
Puoi semplicemente await fetch() sapendo che se la rete non è disponibile, l'errore verrà alla fine indirizzato a "navigateerror".
Voci di navigazione
navigation.currentEntry fornisce l'accesso alla voce corrente.
Si tratta di un oggetto che descrive la posizione attuale dell'utente.
Questa voce include l'URL corrente, i metadati che possono essere utilizzati per identificare questa 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 cambiano.
Si trova ancora 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 slot.
Per uno sviluppatore, key è utile perché l'API Navigation consente di indirizzare direttamente l'utente a una voce con una chiave corrispondente.
Puoi tenerlo a portata di mano, 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 una nozione di "stato", ovvero informazioni fornite dallo sviluppatore che vengono archiviate in modo permanente nella voce della cronologia corrente, ma che non sono direttamente visibili all'utente.
È molto simile a history.state nell'API History, ma è stata migliorata.
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, questo valore è undefined.
Stato dell'impostazione
Sebbene gli oggetti di stato possano essere modificati, 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 dello 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, ti consigliamo di eseguire una navigazione che la sostituisca:
navigation.navigate(location.href, {state: newState, history: 'replace'});
A questo punto, il listener di eventi "navigate" può rilevare questa modifica tramite navigateEvent.destination:
navigation.addEventListener('navigate', navigateEvent => {
console.log(navigateEvent.destination.getState());
});
Aggiornamento sincrono dello stato
In genere, è meglio aggiornare lo stato in modo asincrono tramite navigation.reload({state: newState}), quindi il listener "navigate" può applicare lo stato. Tuttavia, a volte la modifica dello stato è già stata applicata completamente quando il codice ne viene a conoscenza, ad esempio quando l'utente attiva/disattiva un elemento <details> o modifica lo stato di un input del modulo. In questi casi, potresti voler aggiornare lo stato in modo che queste modifiche vengano mantenute durante i ricaricamenti e gli attraversamenti. Ciò è possibile utilizzando updateCurrentEntry():
navigation.updateCurrentEntry({state: newState});
È previsto anche un evento per saperne di più su questa modifica:
navigation.addEventListener('currententrychange', () => {
console.log(navigation.currentEntry.getState());
});
Tuttavia, se ti ritrovi a reagire alle modifiche dello stato in "currententrychange", potresti dividere o addirittura duplicare il 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.
Stato e parametri URL
Poiché lo stato può essere un oggetto strutturato, è allettante utilizzarlo per tutto lo stato dell'applicazione. Tuttavia, in molti casi è meglio memorizzare lo 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 state è l'opzione migliore.
Accedere a tutte le voci
Tuttavia, la "voce corrente" non è tutto.
L'API fornisce anche un modo per accedere all'intero elenco di voci che un utente ha esplorato durante l'utilizzo del tuo sito tramite la chiamata navigation.entries(), che restituisce un array di voci di snapshot.
Questo potrebbe essere utilizzato, ad esempio, per mostrare una UI diversa in base al modo in cui l'utente ha raggiunto una determinata pagina o semplicemente per esaminare gli URL precedenti o i relativi stati.
Ciò non è possibile con l'attuale API History.
Puoi anche ascoltare un evento "dispose" sui singoli NavigationHistoryEntry, che viene attivato quando la voce non fa più parte della cronologia del browser. Ciò può verificarsi nell'ambito della pulizia generale, ma anche durante la navigazione. Ad esempio, se torni indietro di 10 posizioni e poi vai avanti, queste 10 voci della cronologia verranno eliminate.
Esempi
L'evento "navigate" viene attivato per tutti i tipi di navigazione, come indicato sopra.
Esiste un'appendice lunga nelle specifiche di tutti i tipi possibili.
Sebbene per molti siti il caso più comune sia quando l'utente fa clic su un <a href="...">, esistono due tipi di navigazione più complessi e degni di essere trattati.
Navigazione programmatica
Il primo è 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 causare una navigazione.
Questa operazione verrà gestita dal listener di eventi centralizzato registrato sul listener "navigate" e il listener centralizzato verrà chiamato in modo sincrono.
È pensata come un'aggregazione migliorata di metodi precedenti come location.assign() e simili, oltre ai 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, il chiamante può attendere che la transizione sia "confermata" (l'URL visibile è cambiato ed è disponibile un nuovo NavigationHistoryEntry) o "terminata" (tutte le promesse restituite da intercept({ handler }) sono completate o rifiutate, a causa di un errore o di un'altra navigazione).
Il metodo navigate ha anche un oggetto options, in cui puoi impostare:
state: lo stato della nuova voce della cronologia, come disponibile tramite il metodo.getState()suNavigationHistoryEntry.history: che può essere impostato su"replace"per sostituire la voce della cronologia corrente.info: un oggetto da passare all'evento di navigazione tramitenavigateEvent.info.
In particolare, info potrebbe essere utile, ad esempio, per indicare un'animazione particolare che fa apparire la pagina successiva.
L'alternativa potrebbe essere impostare una variabile globale o includerla come parte dell'hash. Entrambe le opzioni sono un po' goffe.)
In particolare, questo info non verrà riprodotto se un utente causa in seguito la navigazione, ad esempio tramite i pulsanti Indietro e Avanti.
Infatti, in questi casi sarà sempre undefined.
navigation dispone anche di una serie di altri metodi di navigazione, tutti restituiscono un oggetto contenente { committed, finished }.
Ho già menzionato traverseTo() (che accetta un key che indica una voce specifica nella cronologia dell'utente) e navigate().
Include anche back(), forward() e reload().
Questi metodi vengono gestiti, proprio come navigate(), dal listener di eventi "navigate" centralizzato.
Invii di moduli
In secondo luogo, l'invio di HTML <form> tramite POST è un tipo speciale di navigazione e l'API Navigation può intercettarlo.
Sebbene includa un payload aggiuntivo, la navigazione viene comunque gestita centralmente dal listener "navigate".
L'invio del modulo può essere rilevato cercando la proprietà formData in NavigateEvent.
Ecco un esempio che trasforma semplicemente qualsiasi invio di modulo in uno che rimane sulla 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"
},
});
}
});
Che cosa manca?
Nonostante la natura centralizzata del listener di eventi "navigate", la specifica attuale 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 accettabile: il server potrebbe restituire lo stato iniziale corretto, che è il modo più veloce per fornire contenuti agli utenti.
Tuttavia, i siti che utilizzano codice lato client per creare le pagine potrebbero dover creare una funzione aggiuntiva per inizializzare la pagina.
Un'altra scelta di progettazione intenzionale dell'API Navigation è che funziona solo all'interno di un singolo frame, ovvero la pagina di primo livello o un singolo <iframe> specifico.
Ciò ha una serie di implicazioni interessanti che sono ulteriormente documentate nella specifica, ma in pratica ridurrà la confusione degli sviluppatori.
La precedente API History presenta una serie di casi limite confusi, come il supporto dei frame, e la nuova API Navigation gestisce questi casi limite fin dall'inizio.
Infine, non esiste ancora un consenso sulla modifica o il riarrangiamento programmatico dell'elenco delle voci navigate dall'utente. Questa funzionalità è attualmente in fase di discussione, ma una possibilità potrebbe essere quella di consentire solo le eliminazioni: voci storiche o "tutte le voci future". Quest'ultimo consentirebbe uno stato temporaneo. Ad esempio, in qualità di sviluppatore, potrei:
- porre una domanda all'utente passando a un nuovo URL o stato
- consentire all'utente di completare il lavoro (o tornare indietro)
- rimuovere una voce della cronologia al completamento di un'attività
Questa soluzione potrebbe essere perfetta per modali o interstitial temporanei: il nuovo URL è qualcosa che un utente può abbandonare con il gesto Indietro, ma non può tornare accidentalmente avanti per aprirlo di nuovo (perché la voce è stata rimossa). Ciò 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 l'API History classica sembri semplice, non è ben definita e presenta un gran numero di problemi relativi a casi limite e al modo in cui è stata implementata in modo diverso nei vari browser. Ci auguriamo che tu voglia fornirci un feedback sulla nuova API Navigation.
Riferimenti
- WICG/navigation-api
- Mozilla Standards Position
- Intent To Prototype
- Revisione del TAG
- Voce di Chromestatus
Ringraziamenti
Grazie a Thomas Steiner, Domenic Denicola e Nate Chapin per aver esaminato questo post.