He creado una aplicación web que utiliza los métodos history
pushState
y replaceState
para navegar por las páginas y actualizar el historial.
El guión en sí funciona casi a la perfección; cargará las páginas correctamente y arrojará los errores de la página cuando sea necesario lanzarlos. Sin embargo, he notado un extraño problema en el pushState
que empujará múltiples entradas duplicadas (y reemplazará las entradas anteriores) al historial.
Por ejemplo, digamos que hago lo siguiente (en orden):
Cargue index.php (el historial será: Índice)
Navegue a profile.php (el historial será: Perfil, Índice)
Navegue a search.php (el historial será: Buscar, Buscar, Índice)
Navega hasta dashboard.php
Entonces, finalmente, esto es lo que surgirá en mi historia (en orden de más reciente a más antiguo):
Tablero Tablero
Tablero
Tablero Índice de
búsqueda
El problema con esto es que cuando un usuario hace clic en los botones de avance o retroceso, será redirigido a la página incorrecta o tendrá que hacer clic varias veces para regresar una vez. Eso, y no tendrá sentido si van y revisan su historial.
Esto es lo que tengo hasta ahora:
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 la ayuda es apreciada,
salud.
fuente
updateHistory
función. Ahora, esupdateHistory
posible que se te llame dos veces, primero, cuando estás inicializando Traveler (window.Traveller = new Traveller();
,constructor
->init
->send
->render
->updateHistory
), y luego tambiénredirect
desdeclick
eventListener. No lo he probado, solo adivinanzas, así que lo agregué como un comentario y no como una respuesta.Respuestas:
¿Tienes un controlador onpopstate ?
En caso afirmativo, compruebe allí también si no está presionando hacia el historial. Que algunas entradas se eliminen / reemplacen en la lista del historial podría ser una gran señal. De hecho, vea esta respuesta SO :
Una vez tuve exactamente el mismo problema que usted describe, pero en realidad fue causado por ir y venir para tratar de entender el error, que eventualmente desencadenaría el controlador popState. Desde ese controlador, entonces llamaría history.push. Así que al final, también tenía algunas entradas duplicadas y algunas faltantes, sin ninguna explicación lógica.
Eliminé la llamada a history.push, la reemplacé por history.replace después de verificar algunas condiciones, y después de que funcionó de maravilla :)
EDITAR -> CONSEJO
Si no puede localizar qué código está llamando a history.pushState:
Intente sobrescribiendo las funciones history.pushState y replaceState con el siguiente código:
Luego, cada vez que se disparen los puntos de interrupción, eche un vistazo a la pila de llamadas.
En la consola, si desea evitar un pushState, simplemente ingrese
allowPush = false;
oallowReplace = false;
antes de reanudar. De esta manera, no te perderás ningún history.pushState, y puedes subir y encontrar el código que lo llama :)fuente