Jak zatrzymać przewijanie strony internetowej do góry po kliknięciu linku, który uruchamia JavaScript?


135

Kiedy mam łącze, które jest połączone ze zdarzeniem jQuery lub JavaScript, takim jak:

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

Jak zapobiec przewijaniu strony do góry? Kiedy usuwam atrybut href z kotwicy, strona nie przewija się do góry, ale link nie wydaje się być klikalny.

Odpowiedzi:


197

Musisz zapobiec domyślnej akcji zdarzenia kliknięcia (tj. Przejściu do celu łącza).

Można to zrobić na dwa sposoby.

Opcja 1: event.preventDefault()

Wywołaj .preventDefault()metodę obiektu zdarzenia przekazanego do modułu obsługi. Jeśli używasz jQuery do wiązania programów obsługi, to zdarzenie będzie instancją jQuery.Eventi będzie to wersja jQuery .preventDefault(). Jeśli używasz addEventListenerdo wiązania swoich Eventprogramów obsługi, będzie to i surowa wersja DOM .preventDefault(). Tak czy inaczej, zrobisz to, czego potrzebujesz.

Przykłady:

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

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

Opcja 2: return false;

W jQuery :

Zwrócenie wartości false z modułu obsługi zdarzeń spowoduje automatyczne wywołanie event.stopPropagation () i event.preventDefault ()

Tak więc w jQuery możesz alternatywnie użyć tego podejścia, aby zapobiec domyślnemu zachowaniu linków:

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

Jeśli używasz surowych zdarzeń DOM, zadziała to również w nowoczesnych przeglądarkach, ponieważ specyfikacja HTML 5 narzuca takie zachowanie. Jednak starsze wersje specyfikacji tego nie robiły, więc jeśli potrzebujesz maksymalnej kompatybilności ze starszymi przeglądarkami, powinieneś wywołać .preventDefault()jawnie. Aby uzyskać szczegółowe informacje, zobacz event.preventDefault () vs. return false (no jQuery) .


9
Opublikowałem rozwiązanie (opóźnione o 3 lata), które nie wymaga dołączania
modułu

W tym przypadku Achilles robi to tylko dlatego, że chce, aby odsyłacz był widoczny jako klikalny, do czego wcale nie musi używać href = "#". Zobacz moją odpowiedź, aby uzyskać więcej informacji.
achecopar

164

Możesz ustawić href na #!zamiast#

Na przykład,

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

nie będzie przewijać po kliknięciu.

Strzec się! Spowoduje to dodanie wpisu do historii przeglądarki po kliknięciu, co oznacza, że ​​po kliknięciu linku przycisk Wstecz użytkownika nie przeniesie go do strony, na której był poprzednio. Z tego powodu prawdopodobnie lepiej jest zastosować to .preventDefault()podejście lub użyć obu w połączeniu.

Oto Fiddle ilustrujący to (po prostu ściśnij przeglądarkę, aż pojawi się pasek przewijania):
http://jsfiddle.net/9dEG7/


Dla speców - dlaczego to działa:

To zachowanie jest określone w specyfikacji HTML5 w sekcji Przechodzenie do identyfikatora fragmentu. Powodem, dla którego odsyłacz z href "#"powoduje przewijanie dokumentu do góry, jest to, że to zachowanie jest jawnie określone jako sposób obsługi pustego identyfikatora fragmentu:

2. Jeśli fragidjest to pusty ciąg, to wskazana część dokumentu jest górną częścią dokumentu

"#!"Zamiast tego użycie atrybutu href of działa po prostu dlatego, że pozwala uniknąć tej reguły. Nie ma nic magicznego wykrzyknikiem - to właśnie sprawia, że dogodnym identyfikator fragmentu, bo to zauważalnie różni się od typowego fragid i mało prawdopodobne, aby kiedykolwiek dopasować idlub nameelementu na swojej stronie. Rzeczywiście, po haszowaniu mogliśmy umieścić prawie wszystko; jedyne fragmenty, które nie są wystarczające, to pusty łańcuch, słowo „top” lub ciągi pasujące do namelubid do elementów strony atrybuty.

Dokładniej, potrzebujemy tylko identyfikatora fragmentu, który spowoduje przejście do kroku 8 w następującym algorytmie do określania wskazanej części dokumentu z fragid:

  1. Zastosuj algorytm parsera URL do adresu URL i niech fragid będzie składnikiem fragmentu wynikowego przeanalizowanego adresu URL.

  2. Jeśli fragidjest pustym ciągiem, to wskazana część dokumentu jest górną częścią dokumentu; zatrzymaj algorytm tutaj.

  3. Niech fragid bytesbędzie wynikiem dekodowania procentowego fragid.

  4. Niech decoded fragidbędzie wynikiem zastosowania algorytmu dekodera UTF-8 do fragid bytes. Jeżeli dekoder UTF-8 emituje błąd dekodera, należy przerwać dekoder i zamiast tego przejść do oznaczonego etapu no decoded fragid.

  5. Jeśli w DOM jest element o identyfikatorze równym dokładnie decoded fragidto pierwszym takim elementem w kolejności drzewa jest wskazana część dokumentu; zatrzymaj algorytm tutaj.

  6. No decoded fragid : Jeśli w DOM jest element, który ma atrybut name, którego wartość jest dokładnie równa fragid( niedecoded fragid ), to pierwszym takim elementem w kolejności drzewa jest wskazana część dokumentu; zatrzymaj algorytm tutaj.

  7. Jeśli fragid jest dopasowaniem ciągu znaków ASCII bez rozróżniania wielkości liter top, to wskazana część dokumentu jest górną częścią dokumentu; zatrzymaj algorytm tutaj.

  8. W przeciwnym razie nie ma wskazanej części dokumentu.

Dopóki trafimy w krok 8 i nie ma wskazanej części dokumentu , obowiązuje następująca zasada:

Jeśli nie ma wskazanej części ... agent użytkownika nie może nic robić.

dlatego przeglądarka się nie przewija.


4
Nie ma znaczenia, jeśli wstawisz '!' lub jakąkolwiek inną wartość, o ile id nie jest częścią DOM.
Gopinath,

3
Kiedyś byłem zwolennikiem tej metody, od tamtej pory zrobiłem 180 i odradzam. Uwaga: takie linki nadal będą zmieniać adres URL strony, powodując dodatkowy wpis w historii przeglądarki i powodując, że przycisk „wstecz” po prostu usuwa fragment z adresu URL zamiast robić to, czego oczekuje użytkownik. Dlatego to rozwiązanie samo w sobie, odpowiadając na zadane pytanie, zazwyczaj nie jest pożądaną alternatywą dla użycia preventDefault()w module obsługi kliknięć - raczej niestety.
Mark Amery,

1
Dlaczego nie użyć href = "javascript :;" zamiast? O ile wiem, nie zmieni to historii przeglądarki. Napisałem o tym w mojej odpowiedzi.
achecopar

30

Łatwym podejściem jest wykorzystanie tego kodu:

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

Takie podejście nie wymusza odświeżania strony, więc pasek przewijania pozostaje na swoim miejscu. Ponadto umożliwia programową zmianę zdarzenia onclick i obsługę powiązania zdarzeń po stronie klienta przy użyciu jQuery.

Z tych powodów powyższe rozwiązanie jest lepsze niż:

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

gdzie ostatnie rozwiązanie pozwoli uniknąć problemu ze skokiem przewijania wtedy i tylko wtedy, gdy metoda myClickHandler nie zawiedzie.


12

Zwrócenie wartości false z wywoływanego kodu zadziała iw wielu przypadkach jest metodą preferowaną, ale możesz też to zrobić

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

Jeśli chodzi o SEO, to naprawdę zależy od tego, do czego będzie używany Twój link. Jeśli zamierzasz użyć go do utworzenia linku do innej treści, zgodziłbym się, że chciałbyś tutaj czegoś sensownego, ale jeśli używasz linku do celów funkcjonalnych, może tak, jak w przypadku przepełnienia stosu na pasku narzędzi posta (pogrubienie, kursywa, hiperłącze itp.), to prawdopodobnie nie ma to znaczenia.


9

Powinieneś zmienić

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

do

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

W ten sposób po kliknięciu linku strona nie przewinie się do góry. Jest to czystsze niż użycie href = "#", a następnie zapobiega uruchamianiu domyślnego zdarzenia.

Mam ku temu dobre powody w pierwszej odpowiedzi na to pytanie , na przykład return false;nie będzie wykonywany, jeśli wywoływana funkcja zgłasza błąd, lub możesz dodać return false;do doSomething()funkcji i zapomnieć o użyciureturn doSomething();



4

Jeśli możesz po prostu zmienić hrefwartość, użyj:

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

Innym fajnym rozwiązaniem, które właśnie wymyśliłem, jest użycie jQuery do zatrzymania działania kliknięcia i spowodowania przewijania strony, ale tylko w przypadku href="#"linków.

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

Na pewno return falsepowinno być za preventDefault()linią, w przeciwnym razie nigdy nie dojdziesz do drugiej linii?
hobailey


2

Możesz także użyć event.preventDefault wewnątrz atrybutu onclick .

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

Nie ma potrzeby wpisywania zdarzenia kliknięcia exstra.


0

Możesz po prostu napisać tak też: -

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

0

Podczas wywoływania funkcji postępuj zgodnie z return false przykładem:

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

0

Utwórz stronę zawierającą dwa łącza - jedno na górze i jedno na dole. Po kliknięciu górnego linku, strona musi przewinąć się do samego dołu strony, gdzie znajduje się dolny link. Po kliknięciu dolnego linku strona musi przewinąć się do góry strony.


0
<a onclick="yourfunction()">

to będzie działać dobrze. nie ma potrzeby dodawania href = "#"


0

Możesz chcieć sprawdzić swój CSS. W przykładzie tutaj: https://css-tricks.com/the-checkbox-hack/ there position: absolute; top: -9999px;. Jest to szczególnie głupie w Chrome, ponieważonclick="whatever" nadal przeskakuje do bezwzględnej pozycji klikniętego elementu.

Usunięcie position: absolute; top: -9999px;, bo display: none;może pomóc.


0

W przypadku Bootstrap 3 do zwijania, jeśli nie określisz celu danych w kotwicy i nie polegasz na href w celu określenia celu, zdarzenie zostanie zablokowane. Jeśli używasz kierowania na dane, musisz sam zapobiec zdarzeniu.

<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>
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.