2011-11-03 10 views
17

tl; dr - Safari su iOS 5 sta memorizzando nella cache così difficile, sta interrompendo il mio sito.Problemi con Page Cache in iOS 5 Safari durante la navigazione indietro/scarica evento non attivato

Sono alle prese con il modo in cui il browser Safari in iOS 5 si occupa della cache backward, che chiamano "PageCache". Il modo in cui è descritto here spiega il comportamento molto bene.

Molto semplicemente, la pagina Cache rende in modo che quando si lascia una pagina che “mettere in pausa” e quando torni ci premere “Play”.

Questo sta causando problemi in tutto il mio sito. Quando si utilizza il pulsante Indietro, la maggior parte degli altri browser mostrerà la pagina nello stato in cui è stata caricata. Non Safari su iOS 5, ti mostra la pagina che hai lasciato l'ultima volta. Un semplice esempio potrebbe essere la disattivazione di un pulsante di invio. Se utilizzo Javascript per disabilitare un pulsante di invio, quindi invio un modulo, quando si fa clic sul pulsante Invia si disabiliterà comunque. Questo è stato un problema in altri browser, inclusa la versione desktop di Safari, ma è stato risolto impostando il gestore di eventi onload su una funzione vuota. Credo che questo dica al browser di invalidare la cache perché qualcosa di importante potrebbe essere successo in quella funzione. Questo hack non sembra funzionare per Safari su iOS 5.

Di seguito è riportato il problema ridotto all'essenziale. Quando carichi test.html vedrai il testo "Testo originale". Quando fai clic sul link, il testo cambierà in "Testo cambiato - inoltro alla pagina successiva", quindi in 3 secondi ti verrà inoltrato a test2.html. Tutto va bene fino a questo punto in tutti i browser. In tutti gli altri browser, quando fai clic sul pulsante Indietro, il testo che vedrai sarà "Testo originale", ma su Safari per iOS 5 vedrai "Testo cambiato - inoltro alla pagina successiva".

Qualche suggerimento su come affrontare questo?

Questo è un semplice esempio

test.html

<script> 
function changeText() { 
    el = document.getElementById("text"); 
    el.innerHTML = "Changed text - forwarding to next page"; 
    setTimeout("forward()",3000);  
} 
function forward() { 
    document.location.href = "test2.html"; 
} 
</script> 
<div id="text">Original Text</div> 
<a href="Javascript:changeText()">Click Here</a> 
<script> 
window.onunload = function(){}; 
</script> 

Test2.html

<div>Click back button</div> 

Questo è un secondo esempio mediante un alberino modulo. Questo è un semplice esempio di come funziona la mia app. Quando si torna a formtest2.asp, si dovrebbe vedere il valore del modulo pubblicato e il testo div deve essere originale.

FormTest.asp

<form method="post" action="formtest2.asp"> 
    Test: <input type="text" name="test"/> 
    <input type="submit" value="Submit"/> 
</form> 

formtest2.asp

<script> 
function changeText() { 
    el = document.getElementById("text"); 
    el.innerHTML = "Changed text - forwarding to next page"; 
    setTimeout("forward()",3000);  
} 
function forward() { 
    document.location.href = "test2.html"; 
} 
</script> 

<% 
Dim test 
test = Request("test") 
Response.Write("Test value: " & test & "<br />") 
%> 

<div id="text">Original Text</div> 
<a href="Javascript:changeText()">Click Here</a> 
<script> 
window.onunload = function(){}; 
</script> 

Test2.html

<div>Click back button</div> 
+0

Ancora un po 'di informazioni su questo. Sembra che tutti i browser che ho testato (Firefox, IE, Safari Desktop) stiano sparpagando pagine e scarichino, in questo ordine. Safari su iOS 5 spara solo su pagehide. – Clarke

+0

Quando si apre una nuova scheda, l'evento di scarico non viene attivato, solo pagehide. Quando si apre una nuova scheda, ci si aspetta di essere in grado di tornare a una vecchia scheda e vedere la pagina proprio come l'avevate lasciata. Il problema è che quando navighiamo da una pagina all'altra nella stessa scheda/finestra, l'evento di scarico dovrebbe essere attivato per w3c ma non lo è. http://www.w3.org/TR/DOM-Level-2-Events/events.html. "L'evento di scaricamento si verifica quando l'implementazione DOM rimuove un documento da una finestra o frame.Questo evento è valido per gli elementi BODY e FRAMESET." – Clarke

+0

Qualsiasi soluzione che usi location.reload() fallisce perché per questa funzione, Safari su ios 5 eseguirà solo un GET, non un POST come tutti gli altri browser. – Clarke

risposta

1

Devo incontrare lo stesso problema.
Su iOS4, quando navighi homepage.html a 2.html, quindi torna a homepage.html, il js non verrà chiamato. quando navighi homepage.html a 2.html, da 2.html continui andando a 3.html, e poi di nuovo da 3 a 2 alla homepage, il JS sarà chiamato chiamato! Sì, è terribile!
Ma su iOS5 MobileSafari, è sempre non può essere chiamato :(Forse questo è un bug della cache su iOS5. Ho testato su iOS 5.0.0 e 5.0.1, ha ottenuto lo stesso risultato.

Ma quando si implementa la onUnload event sull'elemento body, è possibile correggere il problema di backforward su MobileSafari precedente: Ho semplicemente modificato lo <body> in <body onUnload=""> in homepage.html, quindi dalla home page a 2.html, quando si torna alla home page, verrà chiamato javascript nella home page Funziona su FF, Desktop Safari, Mobile Safari (iOS4)

Quindi, come possiamo fare su iOS5? Purtroppo non ho trovato una soluzione. Ma la mia webapp viene eseguito in un client nativo, ho risolto questo con l'aggiunta di una chiamata reload() da origini:

 
     if (isOS5_) 
     { 
      [webView stringByEvaluatingJavaScriptFromString:@"location.reload();"]; 
     } 

quando webViewDidFinishLoad:

+0

Ho provato ad aggiungere un ricarico sulla pagina quando si naviga di nuovo ad esso, ma questo provoca problemi nelle pagine che si aspettano un post di modulo. Il reload carica semplicemente l'URI senza pubblicare i dati del modulo. – Clarke

1

sul mio sito mobile, ho risolto il problema con questo piccolo codice JS:

if ((/iphone|ipad.*os 5/i).test(navigator.appVersion)) { 
    window.onload=function() { 
     localStorage.setItem("href",location.href); 
    }; 
    window.onpopstate=function() { 
     var a=localStorage.getItem("href"), 
      b=location.href; 
     if (b!==a&&b.indexOf((a+"#"))===-1) { 
      document.body.style.display="none"; 
      location.reload(); 
     } 
    }; 
} 

Scenario:

Cliccando sul link “Pagina2” da “Pagina1”: Una volta cliccato “Page1” si avvicina d, "Pagina2" è caricato e genera il carico e molti altri eventi.

[Pagina 1] -> clicca il link -> [Pagina 2] -> onload -> onpopstate -> ...

A questo punto, se si fa clic sul pulsante Indietro del browser, “Pagina2” ottiene chiuso e "Pagina1" viene caricato e genera il carico e molti altri eventi.

[Pagina 2] -> fare clic sul pulsante Indietro -> [Pagina 1] -> onload -> onpopstate -> ...

Facendo clic sul pulsante indietro nel IOS5 rende la chiusura appare “Page1” e “Pagina2” ma la pagina non viene caricata, la scala del viewport viene corrotta e l'unico evento attivato è onpopstate.

[Pagina2] -> fare clic sul pulsante Indietro -> [Pagina1] -> onpopstate.

la correzione:

Le opere fisse attorno agli eventi onload, onpopstate e l'oggetto localStorage.

onload è il primo evento gestito dallo script e al suo interno memorizza lo attuale location.href su localStorage.

Se non ci sono errori, in onpopstate l'attuale location.href e lo href memorizzati devono essere gli stessi e lo script non dovrebbe fare nulla.

Utilizzando Safari su IOS5 la pagina non viene caricata e l'evento onload non viene attivato, quindi location.href e l'href memorizzato sono diversi nell'evento onpopstate.

In questo caso è sufficiente nascondere la pagina corrente (per un altro errore nel viewport relativo a this) e ricaricare la pagina con l'oggetto posizione.

+0

Grazie per l'input, anche se non funzionerà per me. Dato che questo funziona per te, potresti voler aggiungere ipod all'istruzione if. Dovevo farlo perché un iPod Touch è quello che uso per i test e ho dovuto aggiungerlo per farlo funzionare. Questa soluzione funziona bene per le pagine di contenuto dinamico, ma si interrompe quando si torna a una pagina in attesa di invio di un modulo. Location.reload() carica solo quell'URI e non pubblica i valori del modulo originale. Questo è dove il mio esempio html sopra è incompleto. – Clarke

26

Stavo anche cercando una risposta allo stesso problema. Tornando in iOS 5 non si esegue alcun javascript e si esce dalla pagina nello stato precedente in cui era quando si è usciti o sono stati reindirizzati.

Provare lo strano trucco "onunload" trovato in "Is there a cross-browser onload event when clicking the back button?" ha funzionato solo per iOS 4, non per iOS 5 che non chiama l'evento come previsto. Nickolay ha sottolineato nuove funzioni sul web-kit chiamate "pageshow" e "pagehide" che sono molto più affidabili rispetto all'esempio di Giuseppe.

  1. è necessario il trucco da questo articolo: "Is there a cross-browser onload event when clicking the back button?" per questo al lavoro in iOS 4.
  2. Usa questo script che utilizza il nuovo evento per controllare in modo sicuro se la pagina è stata caricata dalla cache e forzare un ricaricare (evitando URL controlli e storage locale e comprendono anche gli iPod) per iOS 5:

    <body onunload=""> 
    ... 
    <script type="text/javascript"> 
    if ((/iphone|ipod|ipad.*os 5/gi).test(navigator.appVersion)) { 
        window.onpageshow = function(evt) { 
        // If persisted then it is in the page cache, force a reload of the page. 
        if (evt.persisted) { 
         document.body.style.display = "none"; 
         location.reload(); 
        } 
        }; 
    } 
    </script> 
    
+0

Alla fine, questa soluzione è la stessa di quella in cui fare una ricarica non risolve il mio problema. Di seguito, "Questa soluzione funziona bene per le pagine di contenuto dinamico, ma si interrompe quando si torna a una pagina che si aspetta l'invio di un modulo.Il location.reload() carica solo quell'URI e non registra i valori del modulo originale." – Clarke

+1

@Clarke: è necessario scrivere i parametri POST che si desidera ri-POST al codice utilizzando il codice lato server (proprio come si scrive la variabile "test"). Iniettare elementi di input nascosti sotto l'elemento form per tutte le variabili che si desidera POST di nuovo. Quindi, utilizzando lo stesso codice di base sopra, invece di eseguire una ricarica, basta inviare un modulo. – BrutalDev

+0

Sembrava una buona soluzione, ma nella realtà non lo è. A volte questo evento spara a volte no. Non riesco nemmeno a spiegare come ripetere il problema, provare ad aprire la pagina 1 poi pagina 2, quindi fare clic su Indietro, l'evento si attiva, quindi ripetere un paio di volte. – Rantiev

0

Dopo aver trovato il modo per evitare uno del problema (s) che tutti sembrano avere su questo, io mi dura 'mi piacerebbe condividere :)

Dopo aver letto alcuni argomenti correlati sull'argomento, principalmente sullo stack overflow "soggetti più caldi", gestendo la "Page Cache" (http://www.webkit.org/blog/427/webkit-page-cache-i-the-basics/ e http://www.webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/), controllando l'evento "scarica" ​​(developer.apple.com/library/IOS /ipad/#documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html)/"pageshow" non ha nulla a che fare con la breve "apparizione di pagina" nel suo stato precedente (non nella pagina precedente. Stato INIZIALE, ma solo nella pagina come è stato lasciato) mentre l'utente ritorna all'app/o sblocca il suo dispositivo/o torna all'app dopo averlo abbandonato.

Sembra (per me, almeno), che questa "pagina difetto visibile" è stato risolto quando ho fatto l'aggiornamento per IOS6, come 5 minuti fa; D

ero quindi in grado di utilizzare il mio webapp in Safari mobile come di consueto, e dopo averlo aggiunto alla schermata iniziale, il comportamento in caso di "cambio di app" o "riavvio", con o senza cache cancellata, è lo stesso del suo primo avvio: vedi una pagina BLANK e poi il tuo contenuto (che potrebbe essere la pagina corrispondente all'url che sono stati salvati nella schermata principale, o qualsiasi altro contenuto caricato utilizzando localStorage ad esempio [il mio caso (..)]).

Per gli eventi che sono riuscito a rilevare, né sui dispositivi IOS4 IOS5 sono riuscito a eliminare quel "problema di persistenza visiva". Immagino che sia a causa del modo in cui "Page Cache" funziona, ma ora sto usando IOS6 su iPad, dato che il glitch non c'è più, suppongo che il team di Safari debba aver migliorato il modo in cui gestiscono le applicazioni web "homescreen" (..)

Problemi correlati