Podemos usar window.location.replace
para evitar o histórico e direcionar âncoras na página sem recarregamentos, mas não em iframes?
O problema é uma violação do CSP (política de segurança de conteúdo), cujos estados script-src 'unsafe-inline'
devem estar ativados. Exceto que eu não tenho um CSP definido, e mesmo se eu definir um e permitir que script-src 'unsafe-inline'
ele ainda dê o mesmo erro de violação. Mesmo resultado em ie11 / chrome / ff.
Iframe no mesmo domínio (no mesmo diretório).
- Alveje o iframe no console e use
window.location.replace('/samepage.html#onpage_anchor')
no console. - funciona. Ele tem como alvo a âncora da página sem recarregar a página e sem histórico.
- Coloque o mesmo código embutido nos links âncora e ele funciona.
- Use o mesmo código no script externo, obtenha o erro de violação da csp. Isso funciona bem se não estiver em um iframe.
Tentei criar um CSP para permitir a ação, mas nem mesmo as políticas de segurança de conteúdo mais permissivas possíveis o permitiriam.
Edit: então eu montei exemplos no plunker que permite vários arquivos para que eu pudesse usar hrefs adequados que fazem referência às páginas pai / filho.
Notas sobre os exemplos de plunker:
O problema não é reproduzido nesses exemplos. O script funciona perfeitamente, mesmo no iframe. No entanto, o mesmo código não funciona no meu servidor local ou quando eu o executo ao vivo em um VPS.
Suspeito que a violação do CSP não seja acionada no plunker, porque ele apresenta o conteúdo ao navegador por meio de uma espécie de camada de abstração de algum tipo.
A primeira vez que você clica nos links de acordeão no pai, isso causa uma atualização. Isso ocorre porque o modo como a página é carregada inicialmente não faz referência a index.html. Os cliques subsequentes funcionam conforme o esperado, sem recarregamentos de página. Não é um problema no iframe porque faz referência inicialmente a child.html
Estes são bons exemplos para mostrar o código sem exigir alterações para fazê-lo funcionar (como na necessidade de alterar os hrefs para fazê-los funcionar nos snippets de fluxo de pilha, mencionados abaixo). Também é bom, pois mostra o javascript funcionando como deveria. Mas isso não mostra o problema realmente. Você ainda precisará carregá-lo em seu editor e executá-lo em um servidor local ou em um ambiente de hospedagem ao vivo para ver o problema real.
Exemplos de Plunker
Com roteiro: Sem histórico
Sem roteiro: Com histórico
Exemplo de código simplificado
Acordeão simples com uma entrada. Suficiente para reproduzir o problema.
Clicar em abrir / fechar expandirá / reduzirá o acordeão, sem a necessidade de JS. O JS deve fazer exatamente a mesma coisa, mas sem histórico. Funciona bem, mas não em um iframe.
Notas do fragmento de código:
Você pode executar o trecho para ter uma idéia do que estou descrevendo, mas na verdade não demonstra o problema.
O snippet não se comporta da mesma maneira que em um navegador real, o javascript não funciona.
O trecho mostra o código, mas deve ser executado em um iframe para ver o problema. Execute-o fora de um iframe para ver a diferença e como deve funcionar.
- Por causa de como os links funcionam com o JS (substituindo o URL inteiro), eles devem ser assim,
href="https://stackoverflow.com/thispage.html#ac1"
e nãohref="#ac1"
como aparecem no snippet (não é possível segmentar a página html real no snippet). Portanto, se você tentar fazer isso no seu editor (por favor, faça), lembre-se de alterar os links para este formatothis_document.html#anchor
para que eles ainda sejam as mesmas âncoras de página, mas o page.html está incluído no link.
O script
$(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);
});
Isso é muito simples:
1. A função acAnch pega o href
atributo e o insere window.location.replace()
.
2. Ouça os cliques nas âncoras no acordeão para executar a função acAnch.
Então, todo o script faz é executado window.location.replace('/this_same_page.html#on_page_anchor')
Se você colocar isso no console, ele funcionará, sem violação do CSP. Mas executá-lo a partir de script externo não funciona.
Inline nos links funciona bem:
onclick="event.preventDefault();window.location.replace('/thispage.html#acc0');"
onclick="event.preventDefault();window.location.replace('/thispage.html#acc1');"
Colocar isso nos respectivos links funciona perfeitamente , mas eu realmente prefiro não usar scripts embutidos como esse. Deve haver uma maneira de fazer isso com um script externo.
Tentei executar o javascript no pai, em vez de no iframe (com modificações para selecionar os links dentro do filho, é claro). O mesmo resultado de erro do CSP.
Por que estou fazendo isto?
Bem, o site é muito mais complexo que o exemplo. Âncoras em iframes funcionam bem, mas adicionam histórico. Se você executar o código acima sem o javascript (ou apenas executar o trecho), abra e feche o acordeão algumas vezes e use o botão Voltar, ele voltará aos estados de fechamento aberto.
Eu não me importaria com o histórico, mas se ele estiver em um iframe, quando você sair da página pai e voltar a ela, o histórico no iframe será quebrado. Voltar não volta mais aos estados de acordeão, mas continua recarregando o iframe. Inicialmente, as âncoras não causam recarregamentos de iframe, mas apenas passam pelo histórico de estado de acordeão, o que funciona bem, até você sair da página e voltar. O back não passa mais pelos estados de acordeão, mas apenas por uma pilha de iframe idênticos recarregados. É um comportamento muito hostil ao usuário.
Não preciso usar location.replace se houver outro método que funcione. No entanto, tentei muitas outras abordagens e descobri que os métodos que podem atingir o mesmo resultado geralmente resultam no mesmo erro.
O objetivo é simplesmente ativar os links de âncora na página sem recarregar e sem histórico dentro de um iframe.
O script embutido funciona. Podemos fazê-lo funcionar em um arquivo .js externo?
<a href="#ac0" class="ac-close">Close</a>
deve funcionar.