variable por pasar formulario example enviar ejemplos ejemplo data carga asincrona javascript ajax cross-browser browser-history

javascript - por - Llamada interceptada al botón Atrás en mi aplicación AJAX: ¡No quiero que haga nada!



enviar formulario por ajax javascript (9)

Tengo una aplicación AJAX. Un usuario hace clic en un botón y la visualización de la página cambia. Hacen clic en el botón Atrás, esperando pasar al estado original, pero en su lugar, van a la página anterior en su navegador.

¿Cómo puedo interceptar y volver a asignar el evento del botón Atrás? He investigado en bibliotecas como RSH (que no pude ponerme a trabajar ...), y he escuchado que usar la etiqueta hash de alguna manera ayuda, pero no puedo encontrarle sentido.

¡Gracias!


Ah, el botón Atrás. Puede imaginar que "atrás" desencadena un evento de JavaScript que simplemente puede cancelar de la siguiente manera:

document.onHistoryGo = function() { return false; }

No es así. Simplemente no hay tal evento.

Si realmente tiene una aplicación web (en lugar de solo un sitio web con algunas características de ajaxy) es razonable hacerse cargo del botón Atrás (con fragmentos en la URL, como usted menciona). Gmail hace esto. Estoy hablando de cuando tu aplicación web está en una sola página, todo auto contenido.

La técnica es simple: cuando el usuario realiza una acción que modifica las cosas, redirige a la misma URL en la que ya está, pero con un fragmento de hash diferente. P.ej

window.location.hash = "#deleted_something"; ... window.location.hash = "#did_something_else";

Si el estado general de su aplicación web es manejable, este es un gran lugar para usar un hash. Digamos que tiene una lista de correos electrónicos, tal vez concatenaría todas sus identificaciones y estados leídos / no leídos, y tomaría un hash MD5, usándolo como su identificador de fragmento.

Este tipo de redirección (solo hash) no intenta obtener nada del servidor, pero sí inserta un espacio en la lista de historial del navegador. Por lo tanto, en el ejemplo anterior, el usuario da "la vuelta" y ahora muestra #deleted_something en la barra de direcciones. Volvieron a responder y todavía están en su página, pero sin hash. Luego volvieron y en realidad regresan, de donde vengan.

Ahora la parte más difícil es que tu JavaScript detecte cuando el usuario responda (para que puedas revertir el estado). Todo lo que debes hacer es mirar la ubicación de la ventana y ver cuándo cambia. Con sondeo. (Lo sé, asco, sondeo. Bueno, no hay nada mejor en el navegador cruzado en este momento). No podrá saber si avanzaron o retrocedieron, por lo que tendrá que ser creativo con sus identificadores hash. (Tal vez un hash concatenado con un número de secuencia ...)

Esta es la esencia del código. (Esta es también la forma en que funciona el complemento jQuery History).

var hash = window.location.hash; setInterval(function(){ if (window.location.hash != hash) { hash = window.location.hash; alert("User went back or forward to application state represented by " + hash); } }, 100);


Debido a problemas de privacidad, es imposible desactivar el botón Atrás o examinar el historial del usuario, pero es posible crear nuevas entradas en este historial sin cambiar las páginas. Cada vez que su aplicación AJAX cambie de estado, actualice top.location con un nuevo fragmento de URI .

top.location = "#new-application-state";

Esto creará una nueva entrada en la pila del historial del navegador. Varias bibliotecas AJAX ya manejan todos los detalles aburridos, como Really Simple History .


En mi situación, quería evitar que el botón Atrás envíe al usuario a la última página y, en su lugar, realice una acción diferente. Usando el evento hashchange , he encontrado una solución que funcionó para mí. Este script asume que la página en la que lo está usando no usa un hash, como en mi caso:

var hashChangedCount = -2; $(window).on("hashchange", function () { hashChangedCount++; if (top.location.hash == "#main" && hashChangedCount > 0) { console.log("Ah ah ah! You didn''t say the magic word!"); } top.location.hash = ''#main''; }); top.location.hash = "#";

El problema que estaba teniendo con algunas de las otras respuestas es que el evento de cambio no se hashchange . Dependiendo de su situación, esto también puede funcionar para usted.


Es muy fácil deshabilitar el botón ATRÁS del navegador , como el código JQuery a continuación:

// History API if( window.history && window.history.pushState ){ history.pushState( "nohb", null, "" ); $(window).on( "popstate", function(event){ if( !event.originalEvent.state ){ history.pushState( "nohb", null, "" ); return; } }); }

Puedes verlo funcionando y más ejemplos aquí dotnsf y aquí thecssninja

Gracias !


Para dar una respuesta actualizada a una pregunta antigua (pero popular):

HTML5 introdujo los métodos history.pushState() e history.replaceState() , que le permiten agregar y modificar entradas de historial, respectivamente. Estos métodos funcionan junto con el evento window.onpopstate .

El uso de history.pushState() cambia el referente que se utiliza en el encabezado HTTP para los objetos XMLHttpRequest creados después de cambiar el estado. La referencia será la URL del documento cuya ventana es this en el momento de la creación del objeto XMLHttpRequest .

Fuente: Manipulación del historial del navegador de Mozilla Developer Network.


Realmente aprecio la explicación dada en la respuesta de Darkporter , pero creo que se puede mejorar usando un evento " hashchange " . Como explicó darkporter, debes asegurarte de que todos tus botones cambien el valor de window.location.hash.

  • Una forma es usar elementos <button> y luego adjuntarles eventos que luego configuren window.location.hash = "#!somehashstring"; .
  • Otra forma de hacerlo es usar enlaces para sus botones, como <a href="#!somehashstring">Button 1</a> . El hash se actualiza automáticamente cuando se hace clic en estos enlaces.

La razón por la que tengo un signo de admiración después del signo hash es para satisfacer el paradigma "hashbang" de Google ( lea más al respecto ), que es útil si quiere que los motores de búsqueda lo indexen. Su hashstring normalmente será pares de nombre / valor como #!color=blue&shape=triangle o una lista como #!/blue/triangle - lo que tenga sentido para su aplicación web.

Entonces solo necesita agregar este bit de código que se activará cada vez que el valor de hash cambie (incluso cuando se golpea el botón de retroceso ). No parece necesario un ciclo de votación.

window.addEventListener("hashchange", function(){ console.log("Hash changed to", window.location.hash); // .... Do your thing here... });

No he probado nada más que Chrome 36, pero de acuerdo con caniuse.com , debería estar disponible en IE8 +, FF21 +, Chrome21 + y en la mayoría de los demás navegadores, excepto Opera Mini.


Trabajé en una forma de anular el comportamiento normal de la historia y crear eventos distintivos de botones forward back y forward , usando la API de historial de HTML5 (no funcionará en IE 9). Esto es muy raro, pero efectivo si quieres interceptar los eventos del botón Atrás y Adelante y manejarlos como quieras. Esto podría ser útil en una serie de escenarios, por ejemplo, si estuviera visualizando una ventana de escritorio remoto y necesitara reproducir los clics del botón hacia atrás y hacia adelante en la máquina remota.

Lo siguiente anularía el comportamiento del botón hacia atrás y hacia adelante:

var myHistoryOverride = new HistoryButtonOverride(function() { console.log("Back Button Pressed"); return true; }, function() { console.log("Forward Button Pressed"); return true; });

Si devolvió false en cualquiera de esas funciones de devolución de llamada, permitiría que el navegador proceda con una operación normal de retroceso / retroceso y abandone su página.

Aquí está el script completo requerido:

function HistoryButtonOverride(BackButtonPressed, ForwardButtonPressed) { var Reset = function () { if (history.state == null) return; if (history.state.customHistoryStage == 1) history.forward(); else if (history.state.customHistoryStage == 3) history.back(); } var BuildURLWithHash = function () { // The URLs of our 3 history states must have hash strings in them so that back and forward events never cause a page reload. return location.origin + location.pathname + location.search + (location.hash && location.hash.length > 1 ? location.hash : "#"); } if (history.state == null) { // This is the first page load. Inject new history states to help identify back/forward button presses. var initialHistoryLength = history.length; history.replaceState({ customHistoryStage: 1, initialHistoryLength: initialHistoryLength }, "", BuildURLWithHash()); history.pushState({ customHistoryStage: 2, initialHistoryLength: initialHistoryLength }, "", BuildURLWithHash()); history.pushState({ customHistoryStage: 3, initialHistoryLength: initialHistoryLength }, "", BuildURLWithHash()); history.back(); } else if (history.state.customHistoryStage == 1) history.forward(); else if (history.state.customHistoryStage == 3) history.back(); $(window).bind("popstate", function () { // Called when history navigation occurs. if (history.state == null) return; if (history.state.customHistoryStage == 1) { if (typeof BackButtonPressed == "function" && BackButtonPressed()) { Reset(); return; } if (history.state.initialHistoryLength > 1) history.back(); // There is back-history to go to. else history.forward(); // No back-history to go to, so undo the back operation. } else if (history.state.customHistoryStage == 3) { if (typeof ForwardButtonPressed == "function" && ForwardButtonPressed()) { Reset(); return; } if (history.length > history.state.initialHistoryLength + 2) history.forward(); // There is forward-history to go to. else history.back(); // No forward-history to go to, so undo the forward operation. } }); };

Esto funciona por un concepto simple. Cuando se carga nuestra página, creamos 3 estados de historial distintos (numerados 1, 2 y 3) y navegamos el navegador para indicar el número 2. Debido a que el estado 2 está en el medio, el próximo evento de navegación de historial nos colocará en el estado 1 o 3, y a partir de esto podemos determinar en qué dirección presionó el usuario. Y así, hemos interceptado un evento de botón hacia adelante o hacia atrás. Luego lo manejamos como queramos y volvemos al estado número 2 para que podamos capturar el próximo evento de navegación de la historia.

Obviamente, deberá abstenerse de utilizar los métodos history.replaceState e history.pushState mientras utiliza el script HistoryButtonOverride, de lo contrario lo romperá.


Usando jQuery, hice una solución simple:

$(window).bind(''hashchange'', function() { top.location = ''#main''; // Eventually alert the user describing what happened });

Hasta ahora, solo se ha probado en Google Chrome.

Esto resolvió el problema para mi aplicación web, que también está muy basada en AJAX.

Es quizás un poco hack''ish, pero lo llamaría hacking elegante ;-) Cuando tratas de navegar hacia atrás, aparece una parte hash en el URI, que es técnicamente lo que trata de navegar hacia atrás.

Intercepta ambos haciendo clic en el botón del navegador y el botón del mouse. Y no puede forzarlo al revés haciendo clic varias veces por segundo, que es un problema que ocurriría en soluciones basadas en setTimeout o setInterval.


Yo hago algo como esto. Mantengo una matriz con estados de aplicaciones anteriores.

Iniciado como:

var backstack = [];

Luego escucho los cambios en el hash de ubicación, y cuando cambia hago esto:

if (backstack.length > 1 && backstack[backstack.length - 2] == newHash) { // Back button was probably pressed backstack.pop(); } else backstack.push(newHash);

De esta manera, tengo una forma un tanto simple de hacer un seguimiento del historial del usuario. Ahora si quiero implementar un botón Atrás en la aplicación (no en el botón del navegador), simplemente lo hago:

window.location.hash = backstack.pop();