(Nota: según los comentarios de Sharky, he incluido un código para detectar espacios en blanco)
Entonces, he visto estas preguntas con frecuencia en SO, y recientemente me he encontrado con el problema de controlar la funcionalidad del botón de retroceso. Después de unos días de buscar la mejor solución para mi aplicación (Single-Page with Hash Navigation), he encontrado un sistema simple, sin navegador, sin biblioteca para detectar el botón de retroceso.
La mayoría de las personas recomiendan usar:
window.onhashchange = function() {
//blah blah blah
}
Sin embargo, esta función también se llamará cuando un usuario use un elemento in-page que cambie el hash de ubicación. No es la mejor experiencia de usuario cuando su usuario hace clic y la página va hacia atrás o hacia adelante.
Para darle un resumen general de mi sistema, estoy completando una matriz con hashes anteriores a medida que mi usuario se mueve a través de la interfaz. Se parece a esto:
function updateHistory(curr) {
window.location.lasthash.push(window.location.hash);
window.location.hash = curr;
}
Muy claro. Hago esto para garantizar la compatibilidad entre navegadores, así como la compatibilidad con navegadores antiguos. Simplemente pase el nuevo hash a la función, y lo almacenará para usted y luego cambiará el hash (que luego se coloca en el historial del navegador).
También utilizo un botón de retroceso en la página que mueve al usuario entre páginas usando la lasthash
matriz. Se parece a esto:
function goBack() {
window.location.hash = window.location.lasthash[window.location.lasthash.length-1];
//blah blah blah
window.location.lasthash.pop();
}
Entonces esto moverá al usuario de regreso al último hash y eliminará ese último hash de la matriz (no tengo botón de avance en este momento).
Entonces. ¿Cómo detecto si un usuario ha utilizado mi botón de retroceso en la página o el botón del navegador?
Al principio miré window.onbeforeunload
, pero fue en vano, eso solo se llama si el usuario va a cambiar de página. Esto no sucede en una aplicación de una sola página que utiliza navegación hash.
Entonces, después de un poco más de excavación, vi recomendaciones para tratar de establecer una variable de bandera. El problema con esto en mi caso es que trataría de configurarlo, pero como todo es asíncrono, no siempre se establecerá a tiempo para la instrucción if en el cambio de hash. .onMouseDown
no siempre se llamaba al hacer clic, y agregarlo a un onclick nunca lo activaría lo suficientemente rápido.
Esto es cuando comencé a mirar la diferencia entre document
, y window
. Mi solución final fue establecer el indicador usando document.onmouseover
y deshabilitarlo usando document.onmouseleave
.
Lo que sucede es que mientras el mouse del usuario está dentro del área del documento (léase: la página representada, pero excluyendo el marco del navegador), mi valor booleano se establece en true
. Tan pronto como el mouse abandona el área del documento, el booleano cambia a false
.
De esta manera, puedo cambiar mi window.onhashchange
a:
window.onhashchange = function() {
if (window.innerDocClick) {
window.innerDocClick = false;
} else {
if (window.location.hash != '#undefined') {
goBack();
} else {
history.pushState("", document.title, window.location.pathname);
location.reload();
}
}
}
Notarás el cheque para #undefined
. Esto se debe a que si no hay un historial disponible en mi matriz, regresa undefined
. Lo uso para preguntarle al usuario si quiere irse usando un window.onbeforeunload
evento.
En resumen, y para las personas que no necesariamente usan un botón de retroceso en la página o una matriz para almacenar el historial:
document.onmouseover = function() {
//User's mouse is inside the page.
window.innerDocClick = true;
}
document.onmouseleave = function() {
//User's mouse has left the page.
window.innerDocClick = false;
}
window.onhashchange = function() {
if (window.innerDocClick) {
//Your own in-page mechanism triggered the hash change
} else {
//Browser back button was clicked
}
}
Y ahí lo tienes. Una forma simple de tres partes para detectar el uso del botón de retroceso frente a los elementos en la página con respecto a la navegación hash.
EDITAR:
Para asegurarse de que el usuario no use la tecla de retroceso para activar el evento de retroceso, también puede incluir lo siguiente (Gracias a @thetoolman en esta pregunta ):
$(function(){
/*
* this swallows backspace keys on any non-input element.
* stops backspace -> back
*/
var rx = /INPUT|SELECT|TEXTAREA/i;
$(document).bind("keydown keypress", function(e){
if( e.which == 8 ){ // 8 == backspace
if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
e.preventDefault();
}
}
});
});