Possiamo usare window.location.replace
per evitare la cronologia e per indirizzare gli ancoraggi nella pagina senza ricaricare la pagina, ma non negli iframe?
Il problema è una violazione CSP (content security policy), che afferma che script-src 'unsafe-inline'
deve essere abilitato. Tranne per il fatto che non ho definito un CSP, e anche se ne definisco uno e lo autorizzo, script-src 'unsafe-inline'
si ottiene sempre lo stesso errore di violazione. Stesso risultato in ie11 / chrome / ff.
Iframe sullo stesso dominio (nella stessa directory).
- Scegli come target l'iframe nella console e utilizzalo
window.location.replace('/samepage.html#onpage_anchor')
nella console. - Funziona. Prende di mira l'ancoraggio sulla pagina senza ricaricare la pagina e senza cronologia.
- Inserisci lo stesso codice in linea sui collegamenti di ancoraggio e funziona.
- Usa lo stesso codice in uno script esterno, ottieni l' errore di violazione csp. Funziona bene se non in un iframe.
Ho provato a creare un CSP per consentire l'azione, ma nemmeno le politiche di sicurezza dei contenuti più permissive possibili lo permetterebbero.
Modifica: così ho messo insieme degli esempi su plunker che consente più file in modo da poter utilizzare href appropriati che fanno riferimento alle pagine padre / figlio.
Note sugli esempi di plunker:
Il problema non è riprodotto in questi esempi. La sceneggiatura funziona perfettamente, anche nell'iframe. Tuttavia, lo stesso codice non funziona sul mio server locale o quando lo eseguo dal vivo su un VPS.
Sospetto che la violazione del CSP non venga attivata sul plunker perché il plunker presenta il contenuto al browser tramite una sorta di livello di astrazione di qualche tipo.
La prima volta che si fa clic sui collegamenti a fisarmonica nel genitore, viene eseguito un aggiornamento. Questo perché il modo in cui la pagina inizialmente la carica non fa riferimento a index.html. I clic successivi funzionano come previsto senza ricaricare la pagina. Non è un problema nell'iframe perché inizialmente fa riferimento a child.html
Questi sono buoni esempi per mostrare il codice senza richiedere modifiche per farlo funzionare (come nella necessità di cambiare gli href per farli funzionare negli snippet di stackover, menzionati di seguito). È anche buono in quanto mostra che JavaScript funziona come dovrebbe. Ma non mostra il problema reale. Dovrai comunque caricarlo nel tuo editor ed eseguirlo su un server locale o in un ambiente di hosting live per vedere il vero problema.
Esempi di Plunker
Con sceneggiatura: senza storia
Senza sceneggiatura: con storia
Esempio di codice semplificato
Fisarmonica semplice con una voce. Sufficiente per riprodurre il problema.
Facendo clic su apri / chiudi si espanderà / comprimerà la fisarmonica, non è richiesto alcun JS. Il JS dovrebbe fare esattamente la stessa cosa ma senza storia. Funziona bene, ma non in un iframe.
Note sullo snippet di codice:
Puoi eseguire lo snippet per avere un'idea di ciò che sto descrivendo, ma in realtà non dimostra il problema.
Lo snippet non si comporta come in un browser reale, il javascript non funziona.
Lo snippet mostra il codice, ma dovrebbe essere eseguito in un iframe per vedere il problema. Eseguilo all'esterno di un iframe per vedere la differenza e come dovrebbe funzionare.
- A causa del modo in cui i collegamenti funzionano con JS (sostituendo l'intero URL), in realtà devono essere così
href="https://stackoverflow.com/thispage.html#ac1"
piuttosto chehref="#ac1"
come appaiono nello snippet (non possono scegliere come target la pagina html effettiva nello snippet). Quindi se provi questo nel tuo editor (per favore), ricordati di cambiare i collegamenti in questo formato inthis_document.html#anchor
modo che siano ancora gli stessi ancoraggi di pagina, ma page.html è incluso nel collegamento.
Il copione
$(document).ready(function() {
// anchor links without history
$.acAnch = function(event) {
event.preventDefault();
var anchLnk = $(event.target);
var anchTrgt = anchLnk.attr('href');
window.location.replace(anchTrgt);
}
// listen for anchor clicks
$('.accordion').on('click', 'a', $.acAnch);
});
Questo è molto semplice:
1. La funzione acAnch accetta l' href
attributo e lo rilascia window.location.replace()
.
2. Ascolta i clic sugli ancoraggi all'interno della fisarmonica per eseguire la funzione acAnch.
Quindi viene eseguito tutto lo script window.location.replace('/this_same_page.html#on_page_anchor')
Se lo metti nella console funziona, nessuna violazione CSP. Ma eseguirlo da script esterni non funziona.
In linea sui collegamenti funziona bene:
onclick="event.preventDefault();window.location.replace('/thispage.html#acc0');"
onclick="event.preventDefault();window.location.replace('/thispage.html#acc1');"
Metterlo sui rispettivi collegamenti funziona perfettamente , ma preferisco davvero non usare uno script inline come quello. Ci deve essere un modo per farlo con uno script esterno.
Ho provato a eseguire il javascript sul genitore invece che nell'iframe (con modifiche per selezionare i collegamenti all'interno del figlio ovviamente). Stesso risultato dell'errore CSP.
Perché lo sto facendo?
Bene, il sito è molto più complesso dell'esempio. Le ancore negli iframe funzionano bene ma aggiungono la cronologia. Se esegui il codice sopra senza javascript (o semplicemente esegui lo snippet), apri e chiudi la fisarmonica alcune volte e usi il pulsante Indietro, tornerà indietro negli stati di chiusura aperti.
Non mi dispiacerebbe la cronologia, ma se si trova in un iframe, quando lasci la pagina principale e poi ritorni ad essa, la cronologia nell'iframe viene interrotta. Tornare indietro non attraversa più gli stati della fisarmonica, ma continua a ricaricare l'iframe. Inizialmente le ancore non causano ricariche iframe ma passano attraverso la storia dello stato della fisarmonica, che funziona benissimo, fino a quando non lasci la pagina e torni indietro. Quindi la schiena non passa più attraverso gli stati della fisarmonica, ma passa attraverso una pila di ricariche identiche di iframe. È un comportamento molto ostile da parte dell'utente.
Non ho bisogno di usare location.replace se esiste un altro metodo che funzionerà. Ho provato molti altri approcci, tuttavia, e ho scoperto che i metodi che possono ottenere lo stesso risultato, generano generalmente lo stesso errore.
L'obiettivo è semplicemente attivare i collegamenti di ancoraggio sulla pagina senza ricaricare, e senza cronologia, all'interno di un iframe.
Lo script inline funziona. Possiamo farlo funzionare in un file .js esterno?
<a href="#ac0" class="ac-close">Close</a>
dovrebbe funzionare.