Como faço para impedir que uma página da Web role para o topo quando clica em um link que aciona JavaScript?

135

Quando tenho um link conectado com um evento jQuery ou JavaScript, como:

<a href="#">My Link</a>

Como evito que a página role para o topo? Quando removo o atributo href da âncora, a página não rola para o topo, mas o link não parece clicável.

Aquiles
fonte

Respostas:

197

Você precisa impedir que a ação padrão do evento de clique (ou seja, navegando até o destino do link) ocorra.

Existem duas maneiras de fazer isso.

Opção 1: event.preventDefault()

Chame o .preventDefault()método do objeto de evento passado para seu manipulador. Se você estiver usando o jQuery para vincular seus manipuladores, esse evento será uma instância jQuery.Evente será a versão do jQuery .preventDefault(). Se você estiver usando addEventListenerpara vincular seus manipuladores, será uma Evente a versão bruta do DOM .preventDefault(). De qualquer maneira, fará o que você precisa.

Exemplos:

$('#ma_link').click(function($e) {
    $e.preventDefault();
    doSomething();
});

document.getElementById('#ma_link').addEventListener('click', function (e) {
    e.preventDefault();
    doSomething();
})

Opção 2: return false;

No jQuery :

Retornar false de um manipulador de eventos chamará automaticamente event.stopPropagation () e event.preventDefault ()

Portanto, com o jQuery, você pode usar essa abordagem como alternativa para evitar o comportamento padrão do link:

$('#ma_link').click(function(e) {
     doSomething();
     return false;
});

Se você estiver usando eventos DOM brutos, isso também funcionará em navegadores modernos, pois a especificação do HTML 5 determina esse comportamento. No entanto, as versões mais antigas da especificação não eram necessárias; portanto, se você precisar de compatibilidade máxima com navegadores mais antigos, ligue .preventDefault()explicitamente. Consulte event.preventDefault () vs. return false (sem jQuery) para obter os detalhes da especificação.

Paolo Bergantino
fonte
9
Postado uma solução (3 anos de atraso) que não necessita de anexar um manipulador de clique: stackoverflow.com/a/11246131/216941
Matt Crinklaw-Vogt
Nesse caso, Achilles está fazendo isso porque deseja que o link apareça como clicável, para o qual ele não precisa usar href = "#". Veja minha resposta para mais informações.
achecopar
164

Você pode definir seu href como em #!vez de#

Por exemplo,

<a href="#!">Link</a>

não fará nenhuma rolagem quando clicado.

Cuidado! Isso ainda adicionará uma entrada ao histórico do navegador quando clicada, o que significa que, após clicar no seu link, o botão Voltar do usuário não os levará para a página em que estavam anteriormente. Por esse motivo, provavelmente é melhor usar a .preventDefault()abordagem ou usar as duas em combinação.

Aqui está um violino ilustrando isso (basta percorrer o navegador até obter uma barra de rolagem):
http://jsfiddle.net/9dEG7/


Para os nerds de especificações - por que isso funciona:

Esse comportamento é especificado na especificação HTML5 na seção Navegando para um identificador de fragmento . A razão pela qual um link com um href de "#"faz com que o documento role para o topo é que esse comportamento é especificado explicitamente como a maneira de lidar com um identificador de fragmento vazio:

2. Se fragidfor a sequência vazia, a parte indicada do documento será a parte superior do documento.

O uso de um href de "#!"funciona simplesmente porque evita essa regra. Não há nada mágico sobre o ponto de exclamação - ele só faz um identificador de fragmento conveniente porque é visivelmente diferente a um fragid típico e improvável que alguma vez igualar a idou namede um elemento em sua página. De fato, poderíamos colocar quase tudo depois do hash; os únicos fragmentos que não serão suficientes são a string vazia, a palavra 'top' ou as strings que correspondem nameou idatributos de elementos na página.

Mais exatamente, precisamos apenas de um identificador de fragmento que nos leve à etapa 8 do algoritmo a seguir para determinar a parte indicada do documento a partir do fragmento:

  1. Aplique o algoritmo do analisador de URLs à URL e deixe fragid o componente de fragmento da URL analisada resultante.

  2. Se fragidfor a sequência vazia, a parte indicada do documento será a parte superior do documento; pare o algoritmo aqui.

  3. Seja fragid byteso resultado da decodificação percentual fragid.

  4. Seja decoded fragido resultado da aplicação do algoritmo de decodificador UTF-8 a fragid bytes. Se o decodificador UTF-8 emitir um erro, descontinue o decodificador e pule para a etapa rotulada no decoded fragid.

  5. Se houver um elemento no DOM que tenha um ID exatamente igual a decoded fragid, o primeiro elemento desse tipo em ordem de árvore será a parte indicada do documento; pare o algoritmo aqui.

  6. Sem fragmento decodificado : se houver um elemento a no DOM que possua um atributo de nome cujo valor seja exatamente igual a fragid( nãodecoded fragid ), o primeiro elemento desse tipo em ordem de árvore será a parte indicada do documento; pare o algoritmo aqui.

  7. Se fragid for uma correspondência que não diferencia maiúsculas de minúsculas ASCII para a sequência top, a parte indicada do documento é a parte superior do documento; pare o algoritmo aqui.

  8. Caso contrário, não há parte indicada do documento.

Desde que atingimos a etapa 8 e não haja parte indicada do documento , a seguinte regra entra em jogo:

Se não houver parte indicada ... então o agente do usuário não deve fazer nada.

é por isso que o navegador não rola.

Matt Crinklaw-Vogt
fonte
4
Não importa se você colocar '!' ou qualquer outro valor, desde que o ID não faça parte do DOM.
Gopinath
3
Depois de ser um defensor desse método, fiz um 180 e desaconselho. Cuidado: links como esse ainda mudarão o URL da página, resultando em uma entrada extra no histórico do navegador e fazendo com que o botão "voltar" remova simplesmente o fragmento do URL em vez de fazer o que o usuário espera. Portanto, essa solução por si só, embora responda à pergunta feita, normalmente não é uma alternativa desejável ao uso preventDefault()em um manipulador de cliques - infelizmente.
Mark Amery
1
Por que não usar href = "javascript :;" em vez de? Tanto quanto sei, isso não mudará o histórico do navegador. Postado sobre isso na minha resposta.
achecopar
30

Uma abordagem fácil é aproveitar esse código:

<a href="javascript:void(0);">Link Title</a>

Essa abordagem não força a atualização da página; portanto, a barra de rolagem permanece no lugar. Além disso, permite alterar programaticamente o evento onclick e manipular a ligação de eventos do lado do cliente usando o jQuery.

Por esses motivos, a solução acima é melhor que:

<a href="javascript:myClickHandler();">Link Title</a>
<a href="#" onclick="myClickHandler(); return false;">Link Title</a>

onde a última solução evitará o problema de salto de rolagem se e somente se o método myClickHandler não falhar.

mais grato
fonte
12

Retornar falso do código que você está chamando funcionará e, em várias circunstâncias, é o método preferido, mas você também pode fazer isso.

<a href="javascript:;">Link Title</a>

Quando se trata de SEO, depende realmente do uso do seu link. Se você realmente vai usá-lo para criar um link para outro conteúdo, eu concordo que o ideal é que você queira algo significativo aqui, mas se estiver usando o link para fins de funcionalidade, talvez o Stack Overflow faça para a barra de ferramentas de postagem (negrito, itálico, hiperlink , etc), então provavelmente não importa.

reitor
fonte
9

Você deve mudar o

<a href="#">My Link</a>

para

<a href="javascript:;">My Link</a>

Dessa forma, quando o link for clicado, a página não será exibida no topo. Isso é mais limpo do que usar href = "#" e impedir a execução do evento padrão.

Tenho boas razões para isso na primeira resposta a esta pergunta , como a return false;não será executada se a função chamada gerar um erro ou você pode adicionar a return false;uma doSomething()função e depois esquecer de usarreturn doSomething();

achecopar
fonte
7

Tente o seguinte:

<a href="#" onclick="return false;">My Link</a>
mikeluby
fonte
4

Se você pode simplesmente mudar o hrefvalor, você deve usar:

<a href="javascript:void(0);">Link Title</a>

Outra solução interessante que acabei de encontrar é usar o jQuery para impedir que a ação do clique ocorra e fazer com que a página role, mas apenas para href="#"links.

<script type="text/javascript">
    /* Stop page jumping when links are pressed */
    $('a[href="#"]').live("click", function(e) {
         return false; // prevent default click action from happening!
         e.preventDefault(); // same thing as above
    });
</script>
Dazbradbury
fonte
Certamente o return falsedeve ser depois da preventDefault()linha, caso contrário você nunca chegará a esta segunda linha?
23416 hobailey
3

Link para algo mais sensato do que o topo da página em primeiro lugar. Em seguida, cancele o evento padrão.

Veja a regra 2 do aprimoramento progressivo pragmático .

Quentin
fonte
Isso também torna o site mais amigável para SEO.
24410 Frankie
2

Além disso, você pode usar event.preventDefault dentro do atributo onclick .

<a href="#" onclick="event.preventDefault(); doSmth();">doSmth</a>

Não é necessário gravar o evento exstra click.

efirat
fonte
0

Você pode simplesmente escrever assim também: -

<a href="#!" onclick="function()">Delete User</a>
user2436792
fonte
0

Ao chamar a função, siga-a pelo return false exemplo:

<input  type="submit" value="Add" onclick="addNewPayment();return false;">
buddhi weerasinghe
fonte
0

Crie uma página que contenha dois links - um na parte superior e outro na parte inferior. Ao clicar no link superior, a página precisa rolar para baixo até a parte inferior da página onde o link inferior está presente. Ao clicar no link inferior, a página precisa rolar até o topo da página.

Damini
fonte
0
<a onclick="yourfunction()">

isso vai funcionar bem. não há necessidade de adicionar href = "#"

Varaj Vignesh
fonte
0

Você pode querer verificar seu CSS. No exemplo aqui: https://css-tricks.com/the-checkbox-hack/,position: absolute; top: -9999px;. Isso é particularmente ridículo no Chrome, pois onclick="whatever"ainda salta para a posição absoluta do elemento clicado.

Removendo position: absolute; top: -9999px;, para display: none;pode ajudar.

Scott Phillips
fonte
0

Para o Bootstrap 3 para recolhimento, se você não especificar o destino dos dados na âncora e confiar no href para determinar o destino, o evento será impedido. Se você usar o destino de dados, precisará impedir o evento.

<button type="button" class="btn btn-default" data-toggle="collapse" data-target="#demo">Collapse This</button>

<div id="demo" class="collapse"> 
<p>Lorem ipsum dolor sit amet</p>
</div>
doug
fonte