Como verificar se o usuário pode voltar ao histórico do navegador ou não

151

Quero usar o JavaScript para ver se há histórico ou não, quero dizer, se o botão Voltar está disponível no navegador ou não.

Ryan
fonte
1
relacionada stackoverflow.com/questions/19417084/...
Adrien Seja

Respostas:

119

Resposta curta: você não pode.

Tecnicamente, existe uma maneira precisa, que seria verificar a propriedade:

history.previous

No entanto, não vai funcionar. O problema é que, na maioria dos navegadores, isso é considerado uma violação de segurança e geralmente apenas retorna indefinido .

history.length

É uma propriedade que outras pessoas sugeriram ...
No entanto , o comprimento não funciona completamente porque não indica onde você está na história. Além disso, nem sempre começa no mesmo número. Um navegador não configurado para ter uma página de destino, por exemplo, inicia em 0, enquanto outro navegador que usa uma página de destino inicia em 1.

texto alternativo

Na maioria das vezes, é adicionado um link que chama:

history.back();

ou

 history.go(-1);

e espera-se que, se você não puder voltar, clicar no link não faça nada.

McAden
fonte
Esta é uma boa informação, mas não resolve o problema. Seria elaborar algum código que realmente funcione em qualquer navegador. Talvez um código que verifique primeiro o navegador que você está usando.
Santiago Bendavid
5
O que estou dizendo é que não há uma resposta definitiva. Você está dizendo os prós e os contras de cada abordagem, mas não como obter um script que verifique qual navegador você está usando e execute condicionalmente um ou outro trecho de código.
Santiago Bendavid 17/08/19
Posso saber o que você quer dizer com 'O problema com isso é que, na maioria dos navegadores, isso é considerado uma violação de segurança' Outro usuário em outro segmento também apontou que a capacidade de obter o histórico do navegador do cliente está violando a segurança, mas não explica por que é que. Alguém pode dar um exemplo de quais são as ameaças à segurança?
Kevin Chandra
Um site não deve saber o histórico de um usuário, o que pode incluir informações pessoais indiretas. Um site pode usar rastreamento / cookies para saber o que o usuário está fazendo no próprio site, mas não deve, por exemplo, descobrir qual banco eu uso, em qual escola meus filhos frequentam, etc. os navegadores não permitirão o acesso a essa propriedade
McAden 16/03
84

Há outra maneira de verificar - verifique o referenciador. A primeira página geralmente terá um referenciador vazio ...

if (document.referrer == "") {
    window.close()
} else {
    history.back()
}
Ron Reiter
fonte
2
O referenciador pode estar oculto por motivos de privacidade.
Kornel
11
O referenciador está sempre vazio quando uma página não foi carregada por um link, mas inserindo o URL na barra de endereços ou carregando um marcador. Porém, essas páginas podem ter um histórico, quando a guia / janela do navegador carregou outra página antes!
ygoe 19/09/12
1
Mas é uma solução aplicável para a navegação através do website multipage
Dan
36
Não funciona se uma janela foi aberta com target = "_ blank" para forçar uma nova janela. O botão voltar no navegador não funcionará, mas haverá um documento
Referrerer
3
Isso não funcionará se você estiver vindo de uma página segura (HTTPS) para uma página não segura (HTTP), pois isso removerá o referenciador.
Kevin Fronteiras
54

Meu código permite que o navegador volte uma página e, se isso falhar, ele carrega um URL de fallback. Ele também detecta alterações de hashtags.

Quando o botão Voltar não estava disponível, o URL de fallback será carregado após 500 ms, para que o navegador tenha tempo suficiente para carregar a página anterior. Carregar o URL de fallback logo em seguida window.history.go(-1);faria com que o navegador usasse o URL de fallback, porque o script js ainda não parava.

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
fonte
6
Eu acho que isso realmente preenche o cerne da questão, o porquê de uma pessoa se importar e o que realmente pode ser feito sobre ela de maneira confiável e consistente.
Chris Marisic
1
Isso funcionou até que eu peguei o URL onde o botão Voltar reside e colei em uma nova guia no chrome. Clicar no botão voltar resultou no envio para uma guia vazia. :(
karlingen
2
Esse é o comportamento padrão do Chrome. Você "visitou" a página chrome://newtabe, portanto, pode voltar no histórico.
precisa saber é o seguinte
Cuidado com isso, porque com uma conexão de rede lenta, você acessa o URL de fallback regularmente.
cameck 23/03
14

Aqui está como eu fiz isso.

Eu usei o evento 'beforeunload' para definir um booleano. Em seguida, defino um tempo limite para observar se o 'beforeload' foi acionado.

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 nos principais navegadores (FF, Chrome, IE11 testados até agora).

Toni Feistauer
fonte
1
Esta é de longe a melhor resposta para a pergunta. Você pode facilmente substituir window.location.href = fallbackcom window.close()e funciona também.
Vitani
13

Há um trecho que eu uso nos meus projetos:

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: Eu uso o History.js para gerenciar o histórico do navegador.


Por que comparar history.length ao número 2?

Porque a página inicial do Chrome é contada como o primeiro item no histórico do navegador.


Existem poucas possibilidades history.lengthe comportamento do usuário:

  • O usuário abre uma nova guia vazia no navegador e, em seguida, executa uma página. history.length = 2e queremos desativar back()nesse caso, porque o usuário irá para a guia vazia.
  • O usuário abre a página em uma nova guia clicando em um link em algum lugar antes. history.length = 1e novamente queremos desativar o back()método.
  • E, finalmente, o usuário chega à página atual após recarregar algumas páginas . history.length > 2e agora back()pode ser ativado.

Nota: eu omito o caso quando o usuário chega à página atual depois de clicar no link do site externo sem target="_blank".

Nota 2: document.referrer está vazia quando você abre o site digitando seu endereço e também quando o site usa ajax para carregar subpáginas, então descontinuei a verificação desse valor no primeiro caso.

gregmatys
fonte
Essa abordagem funcionou muito bem para mim. Na verdade, eu armazeno links estáticos de fallback back para minhas páginas que eu uso no fallback.
Greg Blass
Mas, se você voltar, o history.length não vai mudar .. Então, ele não funciona corretamente
Ciprian Mocanu
Você está certo, infelizmente. Eu uso esse trecho apenas com a estrutura "um passo atrás" ...
gregmatys
12

isso parece fazer o truque:

function goBackOrClose() {  

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

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

}

Chame history.back () e depois window.close (). Se o navegador puder voltar ao histórico, não poderá acessar a próxima declaração. Se não conseguir voltar, fechará a janela.

No entanto, observe que se a página foi acessada digitando um URL, o Firefox não permitirá que o script feche a janela.

xtrahelp.com
fonte
3
Descobri isso não funciona a menos que eu usar um setTimeout com um atraso de algumas centenas de milissegundos ou assim antes de tentar executar a próxima instrução, caso contrário ele vai correr de qualquer maneira depois de executar history.back ()
Ken Fehling
Eu não experimentei isso pessoalmente, qual navegador foi?
Xtrahelp.com
Eu tinha trabalhado bem com a função setTimeout na resposta abaixo. ex: setTimeout (function () {window.close ()}, 400);
217148 gilchris
2
window.close()é considerado um risco de segurança por muitos navegadores modernos. Alguns simplesmente não deixam você fazer isso.
Rudi Kershaw
você pode fazer qualquer coisa depois de window.history.back (); window.close (); é apenas um exemplo
hariszaman 27/01
10

Tenha cuidado window.history.lengthporque inclui também entradas parawindow.history.forward()

Talvez você tenha window.history.lengthmais de uma entrada, mas nenhuma entrada de histórico. Isso significa que nada acontece se você dispararwindow.history.back()

Blitzlord
fonte
9

Você não pode verificar diretamente se o botão Voltar é utilizável. Você pode ver history.length>0, mas isso será válido se houver páginas à frente da página atual também. Você só pode ter certeza de que o botão Voltar não pode ser usado quando history.length===0.

Se isso não for suficiente, basta ligar history.back()e, se sua página ainda for carregada depois, o botão Voltar não estará disponível! Claro que isso significa que, se o botão Voltar estiver disponível, você acabou de navegar para fora da página. Você não tem permissão para cancelar a navegação onunload. Portanto, tudo o que você pode fazer para impedir que as coisas realmente ocorram é retornar algo onbeforeunload, o que resultará em um grande e irritante aviso. Não vale a pena.

De fato, normalmente é uma péssima idéia fazer algo com a história. A navegação no histórico é para o navegador chrome, não para páginas da web. Adicionar links de retorno geralmente causa mais confusão do usuário do que vale a pena.

bobince
fonte
2
em relação ao comprimento - nem mesmo em todos os navegadores. Alguns navegadores contam a página atual como um item do histórico e começam em 1. Você precisaria incluir a detecção do navegador.
McAden 27/08/10
Na verdade, eu pensei que era sempre 1! O 0foi um brainfart, pensei navegadores sempre responder com 1ou mais. Acontece que o Opera e o IE pensam o contrário - uma boa captura.
quer
1
"A navegação no histórico é para o navegador Chrome, não para páginas da Web" - Concordo
Brian
5

history.lengthé inútil, pois não mostra se o usuário pode voltar no histórico. Também diferentes navegadores usam valores iniciais 0 ou 1 - isso depende do navegador.

A solução de trabalho é usar $(window).on('beforeunload'event, mas não tenho certeza se funcionará se a página for carregada via ajax e usar pushState para alterar o histórico da janela.

Então, eu usei a próxima solução:

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
fonte
Funciona para mim assim: function goBackOrTo (targetUrl) {var currentUrl = window.location.href; window.history.go (-1); setTimeout (function () {// se o local não foi alterado em 800 ms, não há histórico de volta se (currentUrl === window.location.href) {// redirecione para a raiz do site window.location.href = targetUrl; }}, 800); }
alfonx 27/02
2

Eu vim com a seguinte abordagem. Ele utiliza o evento onbeforeunload para detectar se o navegador começa a sair da página ou não. Caso contrário, ele será redirecionado apenas para o fallback.

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); 
}

Você pode chamar esta função usando goBack("fallback.example.org").

Pascal Raszyk
fonte
1
Eu gosto mais disso, apenas mudei windows.onbeforeunloadpara ouvinte de eventos window.addEventListener("beforeunload", function (event) { useFallback = false; });para que não sobrescreva window.onbeforeunload.
MiChAeLoKGB 18/07
2

Com base na resposta aqui e aqui . Penso que a resposta mais conclusiva é apenas verificar se esta é uma nova página em uma nova guia.

Se o histórico da página for mais de um, podemos voltar à página anterior à página atual. Caso contrário, a guia é uma guia recém-aberta e precisamos criar uma nova guia.

Diferentemente, para as respostas vinculadas, não estamos verificando uma, referrerpois uma nova guia ainda terá um referenciador.

if(1 < history.length) {
    history.back();
}
else {
    window.close();
}
atw
fonte
1
Obrigado. Você salvou o meu dia :).
Bijay Yadav
1

Existe outra solução quase perfeita, extraída de outra resposta do 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();
}

Alguém relatou que não funciona ao usar, target="_blank"mas parece funcionar para mim no Chrome.

Yonn Trimoreau
fonte
0

o navegador tem o botão voltar e avançar. Eu venho uma solução sobre esta questão. mas Isso afetará a ação de encaminhamento do navegador e causará erros em alguns navegadores.

Funciona assim: se o navegador abrir um novo URL, que nunca foi aberto, o history.length aumentará.

para que você possa alterar o hash como

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

Para obter um URL nunca mostrado, o history.length terá o tamanho real.

  var realHistoryLength = history.length - 1

mas nem sempre funciona bem e não sei por que, especialmente quando o URL automático salta rapidamente.

honchy gan
fonte
0

Eu estava tentando encontrar uma solução e isso é o melhor que pude obter (mas funciona muito bem e é a solução mais fácil que encontrei aqui).

No meu caso, eu queria voltar ao histórico com um botão Voltar, mas se a primeira página aberta pelo usuário fosse uma subpágina do meu aplicativo, ele retornaria à página principal.

A solução foi que, assim que o aplicativo foi carregado, substituí o estado do histórico:

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

Dessa forma, eu só preciso verificar history.state.rootantes de voltar. Se for verdade, substituo um histórico:

if(history.state && history.state.root)
    history.replaceState( {root: true}, '', '/')
else
    history.back() 
Maxwell sc
fonte
Eu não acho que haja outro bom caso de uso. Talvez não seja uma boa ideia Se você quiser verificar o histórico fora do seu aplicativo.
Maxwell sc
-1
var fallbackUrl = "home.php";
if(history.back() === undefined)
    window.location.href = fallbackUrl;
Rejeesh Prarath
fonte
isso parece super fácil ?! é testado nos vários navegadores?
23416 benzkji
no Chrome history.back()é undefinedapenas na página da guia vazia
gregmatys
-2

Solução

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

Explicação

window.location.pathnamefornecerá o URI atual. Por exemplo https://domain/question/1234/i-have-a-problem, dará /question/1234/i-have-a-problem. Veja a documentação sobre window.location para mais informações.

Em seguida, a chamada para split()nos fornecerá todos os fragmentos desse URI. portanto, se usarmos nosso URI anterior, teremos algo parecido ["", "question", "1234", "i-have-a-problem"]. Consulte a documentação sobre String.prototype.split () para obter mais informações.

A chamada para filter()está aqui para filtrar a sequência vazia gerada pela barra invertida. Basicamente, ele retornará apenas o URI do fragmento que tenha um comprimento maior que 1 (sequência não vazia). Então teríamos algo parecido ["question", "1234", "i-have-a-question"]. Isso poderia ter sido escrito assim:

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

Consulte a documentação sobre Array.prototype.filter () e a atribuição Destructuring para obter mais informações.

Agora, se o usuário tentar voltar enquanto estiver ligado https://domain/, não acionaremos a instrução if e, portanto, não acionaremos o window.history.back()método para que o usuário permaneça em nosso site. Esse URL será equivalente ao []comprimento 0e 0 > 0é falso. Portanto, falhando silenciosamente. Obviamente, você pode registrar algo ou executar outra ação, se desejar.

'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...');
  }
}

Limitações

Obviamente, essa solução não funcionará se o navegador não suportar a API do histórico . Verifique a documentação para saber mais sobre isso antes de usar esta solução.

Amin NAIRI
fonte
-5

Não tenho certeza se isso funciona e é completamente não testado, mas tente o seguinte:

<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>

E em algum lugar no HTML:

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

EDITAR:

O que você também pode fazer é pesquisar quais navegadores suportam a função back (acho que todos funcionam) e usar o objeto de detecção de navegador JavaScript padrão encontrado e descrito detalhadamente nesta página . Em seguida, você pode ter 2 páginas diferentes: uma para os "bons navegadores" compatível com o botão Voltar e outra para os "navegadores ruins", solicitando a atualização do navegador.

Latze
fonte
2
history.backé uma função. Você deseja verificar se, history.length > 0então, se voltar comhistory.back()
pixl coder
3
Também []em um NodeList não faz sentido, e você não pode atribuir uma string a um manipulador de eventos.
quer
-8

Verifique se window.history.lengthé igual a 0.

Cristian Sanchez
fonte
6
Não é um bom caminho, uma vez history.length não lhe diz onde você está na história ...
Ron Reiter
@Ron Reiter: Sim, eu acho que a resposta de topo e outros comentários para esta questão já tinha estabelecido que mais de um ano atrás ...
Cristian Sanchez