Cómo verificar si el usuario puede volver al historial del navegador o no

Respuestas:

119

Respuesta corta: no puedes.

Técnicamente hay una forma precisa, que sería verificar la propiedad:

history.previous

Sin embargo, no funcionará. El problema con esto es que en la mayoría de los navegadores esto se considera una violación de seguridad y generalmente solo regresa indefinido .

history.length

Es una propiedad que otros han sugerido ...
Sin embargo , la longitud no funciona por completo, ya que no indica donde en la historia que eres. Además, no siempre comienza en el mismo número. Un navegador que no está configurado para tener una página de destino, por ejemplo, comienza en 0, mientras que otro navegador que usa una página de inicio comenzará en 1.

texto alternativo

La mayoría de las veces se agrega un enlace que llama:

history.back();

o

 history.go(-1);

y solo se espera que si no puedes regresar, hacer clic en el enlace no haga nada.

McAden
fuente
Esta es una buena información, pero no resuelve el problema. Sería elaborar un código que realmente funcione en cualquier navegador. Quizás un código que primero verifica el navegador que está utilizando.
Santiago Bendavid
55
Lo que digo es que no hay una respuesta definitiva. Está diciendo los pros y los contras de cada enfoque, pero no cómo obtener un script que verifique qué navegador está utilizando y ejecute condicionalmente uno u otro código.
Santiago Bendavid
¿Puedo decir qué quiere decir con 'El problema con esto es que en la mayoría de los navegadores esto se considera una violación de seguridad? Otro usuario en otro hilo también señaló que ser capaz de obtener el historial del navegador del cliente está violando la seguridad, pero no explica porqué es eso. ¿Alguien puede dar un ejemplo de cuáles son las amenazas de seguridad?
Kevin Chandra
Un sitio web no debería poder conocer el historial de un usuario que podría incluir información personal indirecta. Un sitio puede usar rastreo / cookies para saber qué está haciendo el usuario en el sitio en sí, pero no se les debe permitir, por ejemplo, averiguar qué banco uso, a qué escuela asisten mis hijos, etc. Por lo tanto, los navegadores no permitirán el acceso a esa propiedad
McAden
84

Hay otra forma de verificar: verificar el referente. La primera página generalmente tendrá un referente vacío ...

if (document.referrer == "") {
    window.close()
} else {
    history.back()
}
Ron Reiter
fuente
2
La referencia se puede ocultar por razones de privacidad.
Kornel
11
El referente siempre está vacío cuando una página no se cargó mediante un enlace, sino al ingresar la URL en la barra de direcciones o al cargar un marcador. Sin embargo, tales páginas pueden tener un historial, cuando la pestaña / ventana del navegador había cargado otra página antes.
Ygoe
1
Pero es una solución aplicable para la navegación a través del sitio web multipágina
Dan
36
No funciona si se abrió una ventana con target = "_ blank" para forzar una nueva ventana. El botón de retroceso en el navegador no funcionará, pero habrá un documento.referrer
Mike_K
3
Esto no funcionará si viene de una página segura (HTTPS) a una página insegura (HTTP), ya que eso eliminará el referente.
Kevin Borders
54

Mi código permite que el navegador retroceda una página, y si eso falla, carga una URL de reserva. También detecta cambios en los hashtags.

Cuando el botón Atrás no estaba disponible, la URL de reserva se cargará después de 500 ms, por lo que el navegador tiene tiempo suficiente para cargar la página anterior. Si carga la URL de reserva inmediatamente después window.history.go(-1);, el navegador usará la URL de reserva, porque el script js aún no se detuvo.

function historyBackWFallback(fallbackUrl) {
    fallbackUrl = fallbackUrl || '/';
    var prevPage = window.location.href;

    window.history.go(-1);

    setTimeout(function(){ 
        if (window.location.href == prevPage) {
            window.location.href = fallbackUrl; 
        }
    }, 500);
}
redelschaap
fuente
66
Creo que esto realmente es el corazón de la pregunta, por qué le importa a una persona y qué se puede hacer al respecto de manera confiable y consistente.
Chris Marisic
1
Esto funcionó hasta que tomé la url donde reside el botón de retroceso y la pegué en una nueva pestaña en Chrome. Al hacer clic en el botón Atrás, se envió a una pestaña vacía. :(
karlingen
2
Ese es el comportamiento predeterminado de Chrome. Usted "visitó" la página chrome://newtaby, por lo tanto, puede retroceder en el historial.
redelschaap
Tenga cuidado con esto porque con una conexión de red lenta, llegará a la URL de reserva con bastante frecuencia.
cameck
14

Así es como lo hice.

He utilizado el evento 'beforeunload' para establecer un valor lógico. Luego establecí un tiempo de espera para ver si se disparaba el 'beforeunload'.

var $window = $(window),
    $trigger = $('.select_your_link'),
    fallback = 'your_fallback_url';
    hasHistory = false;

$window.on('beforeunload', function(){
    hasHistory = true;
});

$trigger.on('click', function(){

    window.history.go(-1);

    setTimeout(function(){
        if (!hasHistory){
            window.location.href = fallback;
        }
    }, 200);

    return false;
});

Parece funcionar en los principales navegadores (probado hasta ahora FF, Chrome, IE11).

Toni Feistauer
fuente
1
Esta es, de lejos, la mejor respuesta a la pregunta. Puede reemplazar fácilmente window.location.href = fallbackcon window.close()y también funciona.
Vitani
13

Hay un fragmento que uso en mis proyectos:

function back(url) {
    if (history.length > 2) {
        // if history is not empty, go back:
        window.History.back();
    } else if (url) {
        // go to specified fallback url:
        window.History.replaceState(null, null, url);
    } else {
        // go home:
        window.History.replaceState(null, null, '/');
    }
}

FYI: Yo uso History.js para administrar el historial del navegador.


¿Por qué comparar history.length con el número 2?

Porque la página de inicio de Chrome se cuenta como el primer elemento en el historial del navegador.


Hay pocas posibilidades history.lengthy comportamiento del usuario:

  • El usuario abre una nueva pestaña vacía en el navegador y luego ejecuta una página. history.length = 2y queremos deshabilitar back()en este caso, porque el usuario irá a la pestaña vacía.
  • El usuario abre la página en una nueva pestaña haciendo clic en un enlace en algún lugar antes. history.length = 1y nuevamente queremos deshabilitar el back()método.
  • Y finalmente, el usuario llega a la página actual después de volver a cargar algunas páginas . history.length > 2y ahora back()se puede habilitar.

Nota: omito el caso cuando el usuario aterriza en la página actual después de hacer clic en el enlace del sitio web externo sin target="_blank".

Nota 2: document.referrer está vacío cuando abre el sitio web escribiendo su dirección y también cuando el sitio web utiliza ajax para cargar subpáginas, por lo que dejé de verificar este valor en el primer caso.

Gregmatys
fuente
Este enfoque funcionó muy bien para mí. De hecho, almaceno enlaces de respaldo estáticos para mis páginas que uso en el respaldo.
Greg Blass
Pero, si regresas, la historia. La longitud no cambiará ... Entonces, no funciona correctamente
Ciprian Mocanu
Tienes razón, desafortunadamente. Solo uso este fragmento con la estructura de "un paso atrás" ...
gregmatys
12

Esto parece hacer el truco:

function goBackOrClose() {  

    window.history.back();
    window.close(); 

    //or if you are not interested in closing the window, do something else here
    //e.g. 
    theBrowserCantGoBack();

}

Llame history.back () y luego window.close (). Si el navegador puede retroceder en el historial, no podrá acceder a la siguiente declaración. Si no puede regresar, cerrará la ventana.

Sin embargo, tenga en cuenta que si se ha llegado a la página escribiendo una URL, Firefox no permitirá que el script cierre la ventana.

xtrahelp.com
fuente
3
He descubierto que esto no funciona a menos que use un setTimeout con un retraso de unos cientos de milisegundos más o menos antes de intentar ejecutar la siguiente declaración, de lo contrario, se ejecutará de todos modos después de ejecutar history.back ()
Ken Fehling
No he experimentado eso personalmente, ¿qué navegador era?
xtrahelp.com
Había trabajado bien con la función setTimeout en la respuesta a continuación. ej .: setTimeout (function () {window.close ()}, 400);
Gilchris
2
window.close()es considerado un riesgo de seguridad por muchos navegadores modernos. Algunos simplemente no te dejan hacerlo.
Rudi Kershaw
puede hacer cualquier cosa después de window.history.back (); ventana.close (); es solo un ejemplo
hariszaman
10

Tenga cuidado window.history.lengthporque incluye también entradas parawindow.history.forward()

Por lo tanto, es posible que tenga window.history.lengthmás de 1 entradas, pero no entradas de historial. Esto significa que no pasa nada si disparaswindow.history.back()

Blitzlord
fuente
9

No puede verificar directamente si el botón Atrás es utilizable. Puede mirar history.length>0, pero eso será válido si hay páginas delante de la página actual también. Solo puede estar seguro de que el botón Atrás no se puede usar cuando history.length===0.

Si eso no es lo suficientemente bueno, todo lo que puede hacer es llamar history.back()y, si su página aún se carga después, ¡el botón de retroceso no está disponible! Por supuesto, eso significa que si el botón Atrás está disponible, acaba de salir de la página. No se le permite cancelar la navegación onunload, por lo que todo lo que puede hacer para evitar que la parte posterior realmente ocurra es devolver algo onbeforeunload, lo que resultará en un gran mensaje molesto. Que no vale la pena.

De hecho, normalmente es una muy mala idea hacer algo con la historia. La navegación del historial es para el navegador Chrome, no para las páginas web. Agregar enlaces de "retroceso" generalmente causa más confusión al usuario de lo que vale.

bobince
fuente
2
con respecto a la longitud, ni siquiera en todos los navegadores. Algunos navegadores cuentan la página actual como un elemento del historial y comienzan en 1. Debería incluir la detección del navegador.
McAden
En realidad pensé que siempre fue así 1. El 0era un Brainfart, pensé navegadores siempre responderían con 1o más. Resulta que Opera e IE piensan lo contrario, buena captura.
bobince
1
"La navegación del historial es para el navegador Chrome, no para las páginas web" - De acuerdo
Brian
5

history.lengthes inútil ya que no muestra si el usuario puede volver al historial. Además, diferentes navegadores usan valores iniciales 0 o 1; depende del navegador.

La solución de trabajo es usar el $(window).on('beforeunload'evento, pero no estoy seguro de que funcionará si la página se carga a través de ajax y usa pushState para cambiar el historial de la ventana.

Así que he usado la siguiente solución:

var currentUrl = window.location.href;
window.history.back();
setTimeout(function(){
    // if location was not changed in 100 ms, then there is no history back
    if(currentUrl === window.location.href){
        // redirect to site root
        window.location.href = '/';
    }
}, 100);
Gromo
fuente
Funciona para mí así: function goBackOrTo (targetUrl) {var currentUrl = window.location.href; window.history.go (-1); setTimeout (function () {// si la ubicación no se cambió en 800 ms, entonces no hay historial de regreso if (currentUrl === window.location.href) {// redirige a la raíz del sitio window.location.href = targetUrl; }}, 800); }
alfonx
2

Se me ocurrió el siguiente enfoque. Utiliza el evento onbeforeunload para detectar si el navegador comienza a abandonar la página o no. Si no lo hace en un período de tiempo determinado, simplemente se redirigirá a la reserva.

var goBack = function goBack(fallback){
    var useFallback = true;

    window.addEventListener("beforeunload", function(){
      useFallback = false;
    });

    window.history.back();

    setTimeout(function(){
        if (useFallback){ window.location.href = fallback; }
    }, 100); 
}

Puede llamar a esta función usando goBack("fallback.example.org").

Pascal Raszyk
fuente
1
Esto me gusta más, simplemente cambié windows.onbeforeunloada detector de eventos window.addEventListener("beforeunload", function (event) { useFallback = false; });para que no sobrescriba window.onbeforeunload.
MiChAeLoKGB
2

Sobre la base de la respuesta aquí y aquí . Creo que la respuesta más concluyente es verificar si se trata de una página nueva en una pestaña nueva.

Si el historial de la página es más de uno, entonces podemos volver a la página anterior a la página actual. De lo contrario, la pestaña es una pestaña recién abierta y necesitamos crear una nueva pestaña.

De manera diferente, a las respuestas vinculadas, no estamos verificando una, referrerya que una nueva pestaña todavía tendrá un referente.

if(1 < history.length) {
    history.back();
}
else {
    window.close();
}
atw
fuente
1
Gracias. Salvaste mi día:).
Bijay Yadav el
1

Hay otra solución casi perfecta, tomada de otra respuesta SO :

if( (1 < history.length) && document.referrer ) {
    history.back();
}
else {
    // If you can't go back in history, you could perhaps close the window ?
    window.close();
}

Alguien informó que no funciona cuando se usa, target="_blank"pero parece funcionar para mí en Chrome.

Yonn Trimoreau
fuente
0

el navegador tiene botón de retroceso y avance. Se me ocurre una solución a esta pregunta. pero afectará la acción de avance del navegador y causará errores con algunos navegadores.

Funciona así: si el navegador abre una nueva url, que nunca se ha abierto, la longitud de la historia crecerá.

para que puedas cambiar hash como

  location.href = '#__transfer__' + new Date().getTime() 

para obtener una URL nunca mostrada, entonces history.length obtendrá la longitud verdadera.

  var realHistoryLength = history.length - 1

pero, no siempre funciona bien, y no sé por qué, especialmente cuando el url automático salta rápidamente.

honchy gan
fuente
0

Estaba tratando de encontrar una solución y esto es lo mejor que pude obtener (pero funciona muy bien y es la solución más fácil que he encontrado incluso aquí).

En mi caso, quería volver al historial con un botón de retroceso, pero si la primera página que el usuario abrió era una subpágina de mi aplicación, volvería a la página principal.

La solución fue que, tan pronto como se cargó la aplicación, acabo de reemplazar el estado del historial:

history.replaceState( {root: true}, '', window.location.pathname + window.location.hash)

De esta manera, solo necesito verificar history.state.rootantes de volver. Si es cierto, hago un reemplazo de historial en su lugar:

if(history.state && history.state.root)
    history.replaceState( {root: true}, '', '/')
else
    history.back() 
Maxwell sc
fuente
No creo que haya otro buen caso de uso. Tal vez no sea una buena idea si desea consultar el historial fuera de su aplicación.
Maxwell sc
-1
var fallbackUrl = "home.php";
if(history.back() === undefined)
    window.location.href = fallbackUrl;
Rejeesh Prarath
fuente
esto se ve super fácil? ¿Está probado en los distintos navegadores?
benzkji
en Chrome solo history.back()está undefineden la página de pestaña vacía
gregmatys
-2

Solución

'use strict';
function previousPage() {
  if (window.location.pathname.split('/').filter(({ length }) => length > 0).length > 0) {
    window.history.back();
  }
}

Explicación

window.location.pathnamele dará el URI actual. Por ejemplo https://domain/question/1234/i-have-a-problemdará /question/1234/i-have-a-problem. Consulte la documentación sobre window.location para obtener más información.

Luego, la llamada a split()nos dará todos los fragmentos de ese URI. así que si tomamos nuestro URI anterior, tendremos algo así ["", "question", "1234", "i-have-a-problem"]. Consulte la documentación sobre String.prototype.split () para obtener más información.

La llamada a filter()está aquí para filtrar la cadena vacía generada por la barra diagonal inversa. Básicamente, solo devolverá el URI del fragmento que tenga una longitud mayor que 1 (cadena no vacía). Entonces tendríamos algo así ["question", "1234", "i-have-a-question"]. Esto podría haberse escrito así:

'use strict';
window.location.pathname.split('/').filter(function(fragment) {
  return fragment.length > 0;
});

Consulte la documentación sobre Array.prototype.filter () y la asignación Destructuring para obtener más información.

Ahora, si el usuario intenta regresar mientras está encendido https://domain/, no activaremos la instrucción if, y no activaremos el window.history.back()método para que el usuario permanezca en nuestro sitio web. Esta URL será equivalente a la []que tiene una longitud de 0, y 0 > 0es falsa. Por lo tanto, silenciosamente fallando. Por supuesto, puede registrar algo o tener otra acción si lo desea.

'use strict';
function previousPage() {
  if (window.location.pathname.split('/').filter(({ length }) => length > 0).length > 0) {
    window.history.back();
  } else {
    alert('You cannot go back any further...');
  }
}

Limitaciones

Por supuesto, esta solución no funcionará si el navegador no es compatible con la API de historial . Consulte la documentación para obtener más información antes de usar esta solución.

Amin NAIRI
fuente
-5

No estoy seguro de si esto funciona y no está completamente probado, pero intente esto:

<script type="text/javascript">

    function goBack() {
        history.back();
    }

    if (history.length > 0) { //if there is a history...
        document.getElementsByTagName('button')[].onclick="goBack()"; //assign function "goBack()" to all buttons onClick
    } else {
        die();
    }
</script>

Y en algún lugar en HTML:

<button value="Button1"> //These buttons have no action
<button value="Button2">

EDITAR:

Lo que también puede hacer es investigar qué navegadores admiten la función de retroceso (creo que todos lo hacen) y usar el objeto de detección de navegador JavaScript estándar que se encuentra y se describe a fondo en esta página . Luego puede tener 2 páginas diferentes: una para los "buenos navegadores" compatibles con el botón de retroceso y otra para los "malos navegadores" que les dice que actualicen su navegador

Latze
fuente
2
history.backEs una función. Desea verificar si history.length > 0entonces si es volver conhistory.back()
pixl coder
3
También []en una NodeList no tiene sentido, y no puede asignar una cadena a un controlador de eventos.
bobince
-8

Verifique si window.history.lengthes igual a 0.

Cristian Sanchez
fuente
66
No es una buena manera, ya que history.length no te dice dónde estás en la historia ...
Ron Reiter
@Ron Reiter: Sí, creo que la respuesta principal y otros comentarios a esta pregunta ya lo habían establecido hace más de un año ...
Cristian Sanchez