w3schools replacestate mdn ejemplo change javascript jquery html5 browser-history html5-history

javascript - replacestate - Ajax con history.pushState y popstate: ¿qué debo hacer cuando la propiedad popstate state es nula?



window history replacestate({} (6)

En realidad me encontré con una necesidad similar hoy y encontré que el código que proporcionaste fue muy útil. Llegué al mismo problema que tú, y creo que todo lo que te falta es empujar tu archivo de índice o página de inicio al historial de la misma manera que lo haces en todas las páginas subsiguientes.

Aquí hay un ejemplo de lo que hice para resolver esto (no estoy seguro de si es la respuesta CORRECTA, ¡pero es simple y funciona!):

var home = ''index.html''; history.pushState({page:home}, null, home);

¡Espero que esto ayude!

Estoy probando la API de historial de HTML5 con ajax de carga de contenido.

Tengo un montón de páginas de prueba conectadas por enlaces relativos. Tengo este JS, que maneja los clics en esos enlaces. Cuando se hace clic en un enlace, el controlador toma su atributo href y lo pasa a ajaxLoadPage (), que carga el contenido de la página solicitada al área de contenido de la página actual. (Mis páginas de PHP están configuradas para devolver una página HTML completa si las solicita normalmente, pero solo una parte del contenido si? Fragment = true se adjunta a la URL de la solicitud).

Luego mi controlador de clic llama history.pushState () para mostrar la URL en la barra de direcciones y agregarla al historial del navegador.

$(document).ready(function(){ var content = $(''#content''); var ajaxLoadPage = function (url) { console.log(''Loading '' + url + '' fragment''); content.load(url + ''?fragment=true''); } // Handle click event of all links with href not starting with http, https or # $(''a'').not(''[href^=http], [href^=https], [href^=#]'').on(''click'', function(e){ e.preventDefault(); var href = $(this).attr(''href''); ajaxLoadPage(href); history.pushState({page:href}, null, href); }); // This mostly works - only problem is when popstate happens and state is null // e.g. when we try to go back to the initial page we loaded normally $(window).bind(''popstate'', function(event){ console.log(''Popstate''); var state = event.originalEvent.state; console.log(state); if (state !== null) { if (state.page !== undefined) { ajaxLoadPage(state.page); } } }); });

Cuando agrega direcciones URL al historial con pushState, también debe incluir un controlador de eventos para que el evento popstate se ocupe de los clics en los botones de retroceso o avance. (Si no hace esto, al hacer clic atrás se muestra la URL que ingresó en el historial en la barra de direcciones, pero la página no está actualizada). Por lo tanto, mi controlador de estado emergente captura la URL guardada en la propiedad del estado de cada entrada que creé. y lo pasa a ajaxLoadPage para cargar el contenido apropiado.

Esto funciona bien para las páginas que mi controlador de clics ha agregado al historial. Pero, ¿qué sucede con las páginas que el navegador agregó al historial cuando las solicité "normalmente"? Digamos que suelo acceder a mi primera página normalmente y luego navego por mi sitio con los clics que realizan esa carga de ajax: si luego intento volver al historial de esa primera página, el último clic muestra la URL de la primera página, pero no No cargues la página en el navegador. ¿Porqué es eso?

Puedo ver que esto tiene algo que ver con la propiedad del estado del último evento de popstate. La propiedad de estado es nula para ese evento, porque solo las entradas agregadas al historial por pushState () o replaceState () pueden darle un valor. Pero mi primera carga de la página fue una solicitud "normal": ¿por qué el navegador no solo retrocede y carga la URL inicial normalmente?


Esta es una pregunta más antigua, pero existe una respuesta mucho más sencilla con el uso de JavaScript nativo para este problema.

Para el estado inicial, no deberías usar history.pushState sino history.replaceState .

Todos los argumentos son los mismos para ambos métodos; la única diferencia es que pushState crea un NUEVO registro histórico y, por lo tanto, es la fuente de su problema. replaceState solo reemplaza el estado de ese registro histórico y se comportará como se esperaba, es decir, volver a la página de inicio inicial.


Me doy cuenta de que esta es una pregunta antigua, pero cuando se trata de administrar un estado fácilmente como este, podría ser mejor tomar el siguiente enfoque:

$(window).on(''popstate'',function(e){ var state = e.originalEvent.state; if(state != null){ if(state.hasOwnProperty(''window'')){ //callback on window window[state.window].call(window,state); } } });

de esta manera, puede especificar una función de devolución de llamada opcional en el objeto de estado cuando se agrega al historial, luego, cuando popstate se popstate , esta función se llamará con el objeto de estado como parámetro.

function pushState(title,url,callback) { var state = { Url : url, Title : title, }; if(window[callback] && typeof window[callback] === ''function'') { state.callback = callback; } history.pushState(state,state.Title,state.Url); }

Fácilmente podría extender esto para satisfacer sus necesidades.


Me encontré con el mismo problema que la pregunta original. Esta línea

var initialPop = !popped && location.href == initialURL;

debe ser cambiado a

var initialPop = !popped;

Esto es suficiente para atrapar el pop inicial. Entonces no es necesario agregar la página original al pushState . es decir, eliminar lo siguiente:

var home = ''index.html''; history.pushState({page:home}, null, home);

El código final basado en las pestañas AJAX (y usando Mootools):

if ( this.supports_history_api() ) { var popped = (''state'' in window.history && window.history.state !== null) , changeTabBack = false; window.addEvent(''myShowTabEvent'', function ( url ) { if ( url && !changingTabBack ) setLocation(url); else changingTabBack = false; //Make sure you do not add to the pushState after clicking the back button }); window.addEventListener("popstate", function(e) { var initialPop = !popped; popped = true; if ( initialPop ) return; var tabLink = $$(''a[href="'' + location.pathname + ''"][data-toggle*=tab]'')[0]; if ( tabLink ) { changingTabBack = true; tabLink.tab(''show''); } }); }


Todavía no entiendo por qué el botón Atrás se comporta de esta manera: pensé que el navegador estaría encantado de retroceder a una entrada creada por una solicitud normal. Quizás cuando inserte otras entradas con pushState el historial deje de comportarse de la manera normal. Pero encontré una manera de hacer que mi código funcione mejor. No siempre puede depender de la propiedad del estado que contiene la URL a la que desea retroceder. Pero retroceder en el historial cambia la URL en la barra de direcciones como cabría esperar, por lo que puede ser más confiable cargar su contenido en función de window.location. Siguiendo este gran ejemplo , he cambiado mi controlador de popstate para que cargue contenido basado en la URL en la barra de direcciones en lugar de buscar una URL en la propiedad estatal.

Una cosa que debes tener en cuenta es que algunos navegadores (como Chrome) activan un evento de estado emergente cuando accedes inicialmente a una página. Cuando esto sucede, es probable que vuelva a cargar el contenido de su página inicial innecesariamente. Así que he agregado algunos bits de código del excelente pjax para ignorar ese pop inicial.

$(document).ready(function(){ // Used to detect initial (useless) popstate. // If history.state exists, pushState() has created the current entry so we can // assume browser isn''t going to fire initial popstate var popped = (''state'' in window.history && window.history.state !== null), initialURL = location.href; var content = $(''#content''); var ajaxLoadPage = function (url) { console.log(''Loading '' + url + '' fragment''); content.load(url + ''?fragment=true''); } // Handle click event of all links with href not starting with http, https or # $(''a'').not(''[href^=http], [href^=https], [href^=#]'').on(''click'', function(e){ e.preventDefault(); var href = $(this).attr(''href''); ajaxLoadPage(href); history.pushState({page:href}, null, href); }); $(window).bind(''popstate'', function(event){ // Ignore inital popstate that some browsers fire on page load var initialPop = !popped && location.href == initialURL; popped = true; if (initialPop) return; console.log(''Popstate''); // By the time popstate has fired, location.pathname has been changed ajaxLoadPage(location.pathname); }); });

Una mejora que podría hacer a este JS es solo adjuntar el controlador de eventos de clic si el navegador admite la API de historial.


Y finalmente dice:

Pensé que el navegador estaría feliz de dar un paso atrás a una entrada que fue creada por una solicitud normal.

He encontrado una explicación del comportamiento de ese navegador extraño here . La explicacion es

debe guardar el estado cuando su sitio se carga la primera vez y después cada vez que cambie de estado

He probado esto - funciona.

Esto significa que no hay necesidad de cargar su contenido en función de window.location .

Espero no engañar.