Modifica l'URL nel browser senza caricare la nuova pagina utilizzando JavaScript


297

Come potrei avere un'azione JavaScript che potrebbe avere degli effetti sulla pagina corrente ma che cambierebbe anche l'URL nel browser, quindi se l'utente preme ricaricare o aggiungere un segnalibro, verrà usato il nuovo URL?

Sarebbe anche bello se il pulsante Indietro ricaricasse l'URL originale.

Sto cercando di registrare lo stato JavaScript nell'URL.


1
Sarebbe così bello Naturalmente sarebbe limitato alle modifiche dello stesso dominio. Ma un certo controllo sul lato client del percorso (e non solo dell'hash) è un passo logico ora che i ricarichi di pagina sono una sorta di "ultima risorsa" per molte app.
Harpo,

1
Una "sorta di" buon uso di pushState:for(i=1;i<50;i++){var txt="..................................................";txt=txt.slice(0,i)+"HTML5"+txt.slice(i,txt.length);history.pushState({}, "html5", txt);}
Derek 朕 會 功夫

esempio di questo effetto in azione: dujour.com
Ben

2
Esempio di questo effetto: facebook.com (quando si aprono le immagini nella lightbox)

questa è una buona domanda tuttavia, è una situazione triste in quanto se questa domanda fosse stata posta in questo modo oggi, sarebbe stata sottovalutata e passata avanti dal "questo non è il tipo di sito in cui si induce la gente a scrivere tutto il codice per te".
Rugiada

Risposte:


118

Con HTML 5, utilizzare la history.pushStatefunzione . Come esempio:

<script type="text/javascript">
var stateObj = { foo: "bar" };
function change_my_url()
{
   history.pushState(stateObj, "page 2", "bar.html");
}
var link = document.getElementById('click');
link.addEventListener('click', change_my_url, false);
</script>

e un href:

<a href="#" id='click'>Click to change url to bar.html</a>

Se si desidera modificare l'URL senza aggiungere una voce all'elenco dei pulsanti indietro, utilizzare history.replaceStateinvece.


Hai ragione, l'ultima volta che ho provato Chrome. Ho appena provato con Firefox 3.6 sul mio Ubuntu, non ha funzionato. Immagino che dovremo aspettare fino a quando HTML5 non sarà completamente supportato in FF
clu3 il

15
Il codice di esempio viene tagliato e incollato da developer.mozilla.org/en/DOM/Manipulating_the_browser_history . Il che in realtà disturba spiegare cosa significano foo e bar in questo caso.
mikemaccana,

2
Il foo e la barra non significano nulla, è un oggetto stato arbitrariamente definito che puoi recuperare in seguito.
Paul Dixon,

3
@Paul: sì, l'articolo sopra fornisce queste informazioni.
mikemaccana,

2
AS di pubblicare questo commento funziona su Firefox Chrome e Safari. Nessuna fortuna con Safari mobile su iPad o iPhone :(
Sid

187

Se vuoi che funzioni nei browser che non supportano history.pushStatee history.popStateancora, il modo "vecchio" è quello di impostare l'identificatore di frammento, che non causerà il ricaricamento della pagina.

L'idea di base è impostare la window.location.hashproprietà su un valore che contenga le informazioni sullo stato necessarie, quindi utilizzare l' evento window.onhashchange o per browser meno recenti che non supportano onhashchange(IE <8, Firefox <3.6), controllare periodicamente su controlla se l'hash è cambiato (usando setIntervalad esempio) e aggiorna la pagina. Dovrai anche controllare il valore di hash al caricamento della pagina per impostare il contenuto iniziale.

Se stai usando jQuery c'è un plugin hashchange che utilizzerà qualunque metodo supportato dal browser. Sono sicuro che ci sono plugin anche per altre librerie.

Una cosa da fare attenzione è quella di scontrarsi con gli ID sulla pagina, perché il browser scorrerà su qualsiasi elemento con un ID corrispondente.


2
I motori di ricerca non ignorano questi collegamenti interni (hash)? Nel mio scenario voglio che anche gli spider raccolgano questi link.
Drew Noakes,

3
@Drew, per quanto ne so, non c'è modo per i motori di ricerca di trattare una parte di una pagina come un risultato separato.
Matthew Crumley,

8
Esiste ora una proposta per fare in modo che i motori di ricerca visualizzino gli hash: googlewebmastercentral.blogspot.com/2009/10/…
LKM

5
Invece di utilizzare setIntervalper ispezionare, è document.location.hashpossibile utilizzare l' hashchangeevento, poiché è molto più adottato. Controlla qui per quali browser supportano ogni standard . Il mio approccio attuale è usare push / popState sui browser che lo supportano. Sugli altri ho impostato l'hash e guardo solo i hashchangebrowser di supporto. Questo lascia IE <= 7 senza supporto cronologico, ma con permalink utile. Ma chi se ne frega della storia di IE <= 7?
Irae Carvalho,

2
@gabeDel Sì, anche se non credo che Analytics registri l'hash, quindi avrebbe lo stesso URL. Un modo migliore sarebbe chiamare manualmente _trackPageviewcon l'URL "reale" della nuova pagina.
Matthew Crumley,

37

window.location.href contiene l'URL corrente. Puoi leggere da esso, puoi aggiungerlo e puoi sostituirlo, il che può causare un ricaricamento della pagina.

Se, come sembra, vuoi registrare lo stato javascript nell'URL in modo che possa essere aggiunto ai segnalibri, senza ricaricare la pagina, aggiungilo all'URL corrente dopo un # e fai in modo che un frammento di javascript attivato dall'evento onload analizzi l'attuale URL per vedere se contiene lo stato salvato.

Se usi un? invece di un #, forzerai un ricaricamento della pagina, ma dal momento che analizzerai lo stato salvato al caricamento questo potrebbe non essere effettivamente un problema; e questo farà funzionare correttamente anche i pulsanti avanti e indietro.


2
registrare lo stato javascript nell'URL è esattamente quello che sto cercando di fare
Steven Noble,

21

Sospetto fortemente che ciò non sia possibile, perché sarebbe un incredibile problema di sicurezza. Ad esempio, potrei creare una pagina che assomiglia a una pagina di accesso alla banca e rendere l'URL nella barra degli indirizzi proprio come la vera banca !

Forse se spieghi perché vuoi farlo, la gente potrebbe essere in grado di suggerire approcci alternativi ...

[Modifica nel 2011: da quando ho scritto questa risposta nel 2008, sono venute alla luce ulteriori informazioni su una tecnica HTML5 che consente di modificare l'URL purché provenga dalla stessa origine]


6
Non è un grosso problema se le modifiche non ricaricate fossero limitate al percorso, alla stringa di query e al frammento, ovvero non all'autorità (dominio e simili).
Ollie Saunders,

2
youtube.com/user/SilkyDKwan#p/u/2/gTfqaGYVfMg è un esempio che è possibile, prova a cambiare video :)
Spidfire

Puoi solo cambiare location.hash (tutto dopo il #), come osserva Matthew Chumley nella risposta accettata.
Paul Dixon,

2
Usi Facebook? Facebook modifica l'URL senza ricaricare, utilizzando history.pushState().
Derek 朕 會 功夫

Paul Dixon, dovresti notare la posta in arrivo di Facebook, quando fai clic sui nomi sul lato sinistro, solo l'URL viene modificato e la nuova chat viene caricata nella finestra di chat, la pagina non viene aggiornata. inoltre ci sono molti più siti su WebGL che fanno lo stesso
Dheeraj Thedijje,

8

Le impostazioni di sicurezza del browser impediscono alle persone di modificare direttamente l'URL visualizzato. Potresti immaginare le vulnerabilità di phishing che potrebbero causare.

L'unico modo affidabile per cambiare l'URL senza cambiare pagina è usare un link interno o un hash. ad es .: http://site.com/page.html diventa http://site.com/page.html#item1 . Questa tecnica viene spesso utilizzata in hijax (AJAX + conserva la cronologia).

Nel fare ciò, spesso userò solo i collegamenti per le azioni con l'hash come href, quindi aggiungerò eventi di clic con jquery che utilizzano l'hash richiesto per determinare e delegare l'azione.

Spero che ti metta sulla strada giusta.


Siamo spiacenti ma la tua risposta non è vera. Sì, puoi modificare l'URL.
Derek 朕 會 功夫

1
Sì, è possibile utilizzare l'API della cronologia html5 ma non è cross-browser, sebbene sia possibile utilizzare un poly-fill che eseguirà il fallback negli hash url.
Jethro Larson,

8

jQuery ha un ottimo plugin per cambiare l'URL del browser, chiamato jQuery-pusher .

JavaScript pushStatee jQuery potrebbero essere usati insieme, come:

history.pushState(null, null, $(this).attr('href'));

Esempio:

$('a').click(function (event) {

  // Prevent default click action
  event.preventDefault();     

  // Detect if pushState is available
  if(history.pushState) {
    history.pushState(null, null, $(this).attr('href'));
  }
  return false;
});

Utilizzando solo JavaScript history.pushState() , che modifica il referrer, che viene utilizzato nell'intestazione HTTP per gli oggetti XMLHttpRequest creati dopo aver modificato lo stato.

Esempio:

window.history.pushState("object", "Your New Title", "/new-url");

Il metodo pushState ():

pushState()accetta tre parametri: un oggetto stato, un titolo (che è attualmente ignorato) e (facoltativamente) un URL. Esaminiamo ciascuno di questi tre parametri in modo più dettagliato:

  1. oggetto state - L'oggetto state è un oggetto JavaScript associato alla nuova voce della cronologia creata da pushState(). Ogni volta che l'utente passa al nuovo stato, viene generato un evento popstate e la proprietà state dell'evento contiene una copia dell'oggetto stato della voce della cronologia.

    L'oggetto state può essere tutto ciò che può essere serializzato. Poiché Firefox salva gli oggetti di stato sul disco dell'utente in modo che possano essere ripristinati dopo che l'utente ha riavviato il browser, imponiamo un limite di dimensioni di 640k caratteri sulla rappresentazione serializzata di un oggetto di stato. Se si passa un oggetto stato la cui rappresentazione serializzata è più grande di questa pushState(), il metodo genererà un'eccezione. Se hai bisogno di più spazio di questo, sei incoraggiato a utilizzare sessionStorage e / o localStorage.

  2. titolo - Firefox attualmente ignora questo parametro, sebbene possa utilizzarlo in futuro. Passare la stringa vuota qui dovrebbe essere sicuro contro future modifiche al metodo. In alternativa, potresti passare un breve titolo per lo stato in cui ti stai trasferendo.

  3. URL : l' URL della nuova voce della cronologia è dato da questo parametro. Si noti che il browser non tenterà di caricare questo URL dopo una chiamata pushState(), ma potrebbe tentare di caricare l'URL in un secondo momento, ad esempio dopo che l'utente riavvia il browser. Il nuovo URL non deve essere assoluto; se è relativo, viene risolto rispetto all'URL corrente. Il nuovo URL deve avere la stessa origine dell'URL corrente; in caso contrario, pushState()verrà generata un'eccezione. Questo parametro è facoltativo; se non è specificato, è impostato sull'URL corrente del documento.



3

La galleria fotografica di Facebook lo fa usando un #hash nell'URL. Ecco alcuni URL di esempio:

Prima di fare clic su "Avanti":

/photo.php?fbid=496429237507&set=a.218088072507.133423.681812507&pid=5887027&id=681812507

Dopo aver fatto clic su "Avanti":

/photo.php?fbid=496429237507&set=a.218088072507.133423.681812507&pid=5887027&id=681812507#!/photo.php?fbid=496435457507&set=a.218088072507.133423.681812507&pid=5887085&id=681812507

Nota l'hash-bang (#!) Immediatamente seguito dal nuovo URL.



2

Ciò che funziona per me è: history.replaceState()funzione che è la seguente:

history.replaceState(data,"Title of page"[,'url-of-the-page']);

Questo non ricaricherà la pagina, puoi usarlo con l'evento di javascript


1

Mi chiedevo se fosse possibile fintanto che il percorso principale nella pagina è lo stesso, solo qualcosa di nuovo viene aggiunto ad esso.

Quindi diciamo che l'utente è nella pagina: http://domain.com/site/page.html quindi il browser può lasciarmi fare location.append = new.html e la pagina diventa: http://domain.com/site/page.htmlnew.htmle il browser non la modifica.

O semplicemente consenti alla persona di cambiare il parametro get, quindi andiamo location.get = me=1&page=1.

Quindi la pagina originale diventa http://domain.com/site/page.html?me=1&page=1e non si aggiorna.

Il problema con # è che i dati non vengono memorizzati nella cache (almeno non credo) quando viene modificato l'hash. Quindi è come ogni volta che viene caricata una nuova pagina, mentre i pulsanti avanti e indietro in un non Ajax pagina sono in grado di memorizzare nella cache i dati e non perdere tempo a ricaricare i dati.

Da quello che ho visto, la storia di Yahoo carica già tutti i dati contemporaneamente. Sembra che non stia facendo alcuna richiesta Ajax. Pertanto, quando a divviene utilizzato per gestire un metodo diverso nel tempo, i dati non vengono archiviati per ogni stato della cronologia.


1

il mio codice è:

//change address bar
function setLocation(curLoc){
    try {
        history.pushState(null, null, curLoc);
        return false;
    } catch(e) {}
        location.hash = '#' + curLoc;
}

e azione:

setLocation('http://example.com/your-url-here');

ed esempio

$(document).ready(function(){
    $('nav li a').on('click', function(){
        if($(this).hasClass('active')) {

        } else {
            setLocation($(this).attr('href'));
        }
            return false;
    });
});

È tutto :)


1

Una risposta più semplice che presento,

window.history.pushState(null, null, "/abc")

questo verrà aggiunto /abcdopo il nome di dominio nell'URL del browser. Basta copiare questo codice e incollarlo nella console del browser e vedere l'URL che cambia in " https://stackoverflow.com/abc "


0

Ho avuto successo con:

location.hash="myValue";

Si aggiunge solo #myValueall'URL corrente. Se è necessario attivare un evento nella pagina Carica, è possibile utilizzare lo stesso location.hashper verificare il valore pertinente. Basta ricordare di rimuovere il #dal valore restituito da location.hashes

var articleId = window.location.hash.replace("#","");
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.