Criei um aplicativo da Web que utiliza os métodos history
pushState
e replaceState
para navegar pelas páginas e também atualizar o histórico.
O script em si funciona quase perfeitamente; ele carrega as páginas corretamente e gera erros de página quando eles precisam ser lançados. No entanto, notei um problema estranho no qual pushState
enviará várias entradas duplicadas (e substituirá as entradas anteriores) ao histórico.
Por exemplo, digamos que eu faça o seguinte (em ordem):
Carregue o index.php (o histórico será: Index)
Navegue até profile.php (o histórico será: Profile, Index)
Navegue para search.php (o histórico será: Pesquisa, Pesquisa, Índice)
Navegue para dashboard.php
Finalmente, é isso que vai aparecer na minha história (na ordem do mais recente ao mais antigo):
Painel de
controle Índice de pesquisa de
painel
O problema é que, quando um usuário clica nos botões de avançar ou voltar, ele será redirecionado para a página incorreta ou precisará clicar várias vezes para voltar uma vez. Isso, e não fará sentido se eles verificarem sua história.
Isto é o que eu tenho até agora:
var Traveller = function(){
this._initialised = false;
this._pageData = null;
this._pageRequest = null;
this._history = [];
this._currentPath = null;
this.abort = function(){
if(this._pageRequest){
this._pageRequest.abort();
}
};
// initialise traveller (call replaceState on load instead of pushState)
return this.init();
};
/*1*/Traveller.prototype.init = function(){
// get full pathname and request the relevant page to load up
this._initialLoadPath = (window.location.pathname + window.location.search);
this.send(this._initialLoadPath);
};
/*2*/Traveller.prototype.send = function(path){
this._currentPath = path.replace(/^\/+|\/+$/g, "");
// abort any running requests to prevent multiple
// pages from being loaded into the DOM
this.abort();
return this._pageRequest = _ajax({
url: path,
dataType: "json",
success: function(response){
// render the page to the dom using the json data returned
// (this part has been skipped in the render method as it
// doesn't involve manipulating the history object at all
window.Traveller.render(response);
}
});
};
/*3*/Traveller.prototype.render = function(data){
this._pageData = data;
this.updateHistory();
};
/*4*/Traveller.prototype.updateHistory = function(){
/* example _pageData would be:
{
"page": {
"title": "This is a title",
"styles": [ "stylea.css", "styleb.css" ],
"scripts": [ "scripta.js", "scriptb.js" ]
}
}
*/
var state = this._pageData;
if(!this._initialised){
window.history.replaceState(state, state.title, "/" + this._currentPath);
this._initialised = true;
} else {
window.history.pushState(state, state.title, "/" + this._currentPath);
}
document.title = state.title;
};
Traveller.prototype.redirect = function(href){
this.send(href);
};
// initialise traveller
window.Traveller = new Traveller();
document.addEventListener("click", function(event){
if(event.target.tagName === "a"){
var link = event.target;
if(link.target !== "_blank" && link.href !== "#"){
event.preventDefault();
// example link would be /profile.php
window.Traveller.redirect(link.href);
}
}
});
Toda a ajuda é apreciada,
Saúde.
fonte
updateHistory
função. Agora,updateHistory
pode ser chamado duas vezes, primeiro, quando você está inicializando o Traveler (window.Traveller = new Traveller();
,constructor
->init
->send
->render
->updateHistory
), e também aredirect
partir doclick
eventListener. Eu não testei, apenas adivinhação, então adicioná-lo como um comentário e não uma resposta.Respostas:
Você tem um manipulador onpopstate ?
Se sim, verifique também se você não está empurrando para o histórico. O fato de algumas entradas serem removidas / substituídas na lista de histórico pode ser um grande sinal. De fato, veja esta resposta SO :
Certa vez, tive exatamente o mesmo problema que você descreve, mas foi realmente causado por eu voltar e avançar para tentar entender o bug, o que acabaria por acionar o manipulador popState. A partir desse manipulador, ele chamaria history.push. Então, no final, eu também tinha algumas entradas duplicadas e algumas ausentes, sem nenhuma explicação lógica.
Eu removi a chamada para history.push, substituí-a por history.replace depois de verificar algumas condições e depois funcionou como um encanto :)
EDITAR -> DICA
Se você não conseguir localizar qual código está chamando history.pushState:
Tente substituir as funções history.pushState e replaceState pelo seguinte código:
Então, sempre que os pontos de interrupção forem acionados, observe a pilha de chamadas.
No console, se você deseja impedir um pushState, basta digitar
allowPush = false;
ouallowReplace = false;
antes de continuar. Dessa forma, você não perderá nenhum history.pushState e poderá subir e encontrar o código que o chama :)fonte