Як зупинити прокручування веб-сторінки до вершини, коли натискається посилання, що запускає JavaScript?


135

Коли у мене є посилання, яке з'єднане з подією jQuery або JavaScript, наприклад:

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

Як запобігти прокрученню сторінки до вершини? Коли я видаляю атрибут href з якоря, сторінка не прокручується вгору, але посилання не може бути натиснутою.

Відповіді:


197

Потрібно запобігти появі дії за замовчуванням для події клацання (тобто навігації до цілі посилання).

Є два способи зробити це.

Варіант 1: event.preventDefault()

Викличте .preventDefault()метод об'єкта події, переданий вашому обробнику. Якщо ви використовуєте jQuery для зв'язування ваших обробників, ця подія буде екземпляром, jQuery.Eventі це буде версія jQuery .preventDefault(). Якщо ви використовуєте addEventListenerдля зв'язування ваших обробників, це буде Eventі необроблена версія DOM .preventDefault(). У будь-якому випадку ви зробите те, що вам потрібно.

Приклади:

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

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

Варіант 2: return false;

У jQuery :

Повернення помилки з обробника подій автоматично викличе event.stopPropagation () та event.preventDefault ()

Отже, за допомогою jQuery ви можете альтернативно використовувати такий підхід, щоб запобігти поведінці посилання за замовчуванням:

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

Якщо ви використовуєте необроблені події DOM, це також буде працювати в сучасних браузерах, оскільки специфікація HTML 5 диктує таку поведінку. Однак у старих версіях специфікації цього не було, тому, якщо вам потрібна максимальна сумісність зі старими браузерами, вам слід .preventDefault()чітко зателефонувати . Див. Event.preventDefault () vs. return false (немає jQuery) для деталей специфікації.


9
Додано рішення (3 роки пізніше) , який не вимагає підключення обробника клацання: stackoverflow.com/a/11246131/216941
Matt Crinklaw-Vogt

У цьому випадку Ахілл просто робить це, тому що він хоче, щоб посилання виглядало як натискає, для чого йому взагалі не потрібно використовувати href = "#". Дивіться мою відповідь для отримання додаткової інформації.
achecopar

164

Ви можете встановити href #!замість#

Наприклад,

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

при натисканні не буде прокручуватися.

Остерігайся! Це все одно додасть запис до історії веб-переглядача при натисканні, тобто після натискання на ваше посилання кнопка повернення користувача не перенесе їх на сторінку, на якій він був раніше. З цієї причини, ймовірно, краще використовувати.preventDefault() підхід або використовувати обидва в поєднанні.

Ось Fiddle, що ілюструє це (просто скрутіть веб-переглядач доти, доки ви не отримаєте смугу прокрутки):
http://jsfiddle.net/9dEG7/


Для спеціалістів - чому це працює:

Така поведінка визначена у специфікації HTML5 у розділі Навігація до ідентифікатора фрагмента . Причина того, що посилання з href "#"викликає прокручування документа до вершини, полягає в тому, що ця поведінка прямо вказана як спосіб обробки порожнього фрагмента ідентифікатора:

2. Якщо fragidпорожній рядок, то зазначена частина документа - це верхня частина документа

Використання href "#!"замість цього працює просто тому, що він уникає цього правила. Там нічого магічного знак оклику - це тільки робить зручний ідентифікатор фрагмента , оскільки він помітно відрізняється від типового fragid і навряд чи коли - небудь відповідати idабо nameелементу на сторінці. Дійсно, ми могли поставити майже все, що завгодно хеш; єдині фрагменти, яких не вистачить - це порожня рядок, слово 'top' або рядки, які відповідають nameабо idатрибутам елементів на сторінці.

Точніше, нам просто потрібен ідентифікатор фрагмента, який призведе до того, що ми перейдемо до кроку 8 у наступному алгоритмі визначення зазначеної частини документа з фрагмента:

  1. Застосуйте алгоритм розбору URL-адрес до URL-адреси, і нехай fragid буде складовою фрагмента отриманого розбору URL-адреси.

  2. Якщо fragidпорожній рядок, то зазначена частина документа - це верхня частина документа; зупиніть алгоритм тут.

  3. Нехай fragid bytesбуде результат відсоткового декодування fragid.

  4. Нехай decoded fragidбуде результатом застосування алгоритму декодера UTF-8 до fragid bytes. Якщо декодер UTF-8 видає помилку декодера, перервіть декодер і замість цього перейдіть до позначеного кроку no decoded fragid.

  5. Якщо в DOM є елемент, у якого ідентифікатор точно рівний decoded fragid, то першим таким елементом у порядку дерева є зазначена частина документа; зупиніть алгоритм тут.

  6. Немає розшифрованої суворості : якщо в DOM є елемент, який має атрибут імені, значення якого точно дорівнює fragid( неdecoded fragid ), то першим таким елементом у порядку дерева є зазначена частина документа; зупиніть алгоритм тут.

  7. Якщо fragid - це ASCII нечутливий регістр відповідності для рядка top, то зазначена частина документа - це верхня частина документа; зупиніть алгоритм тут.

  8. Інакше частина документа не вказана.

Поки ми переходимо до кроку 8 і немає зазначеної частини документа , наступне правило вступає в дію:

Якщо немає зазначеної частини ..., тоді користувальницький агент не повинен нічого робити.

тому браузер не прокручує.


4
Не має значення, якщо ви кладете "!" або будь-яке інше значення, якщо ідентифікатор не є частиною DOM.
Гопінат

3
Після того як я був прихильником цього методу, я з тих пір зробив 180 і раджу проти цього. Остерігайтеся: такі посилання все одно змінять URL-адресу сторінки, що призведе до додаткового запису в історії веб-переглядача і призведе до того, що кнопка "назад" просто видалить фрагмент з URL-адреси, а не зробить те, що очікує користувач. Таким чином, це рішення самостійно, відповідаючи на запитання, як правило, не є бажаною альтернативою для використання preventDefault()в обробці кліків - досить сумно.
Марк Амері

1
Чому б не використовувати href = "javascript:;" натомість? Наскільки я знаю, це не змінить історію браузера. Опублікував про це на мою відповідь.
achecopar

30

Простий підхід полягає в використанні цього коду:

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

Цей підхід не змушує оновити сторінку, тому смуга прокрутки залишається на місці. Крім того, це дозволяє програматично змінювати подію onclick та обробляти прив'язку подій на стороні клієнта за допомогою jQuery.

З цих причин вищезазначене рішення краще, ніж:

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

де останнє рішення дозволить уникнути проблеми прокрутки прокрутки, якщо і лише якщо метод myClickHandler не вийде з ладу.


12

Повернення помилки з коду, який ви телефонуєте, буде спрацьовувати, і в ряді обставин є кращим методом, але ви також можете це зробити

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

Що стосується SEO, то це дійсно залежить від того, для чого буде використовуватися ваше посилання. Якщо ви дійсно використовуєте його для посилання на якийсь інший контент, то я б погодився в ідеалі, ви хочете щось значуще тут, але якщо ви використовуєте посилання в цілях функціональності, можливо, як Stack Overflow робить для панелі інструментів повідомлення (жирний, курсив, гіперпосилання тощо), мабуть, це не має значення.


9

Ви повинні змінити

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

до

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

Таким чином, при натисканні на посилання сторінка не прокручується доверху. Це чистіше, ніж використовувати href = "#", а потім запобігти запуску події за замовчуванням.

У мене є вагомі причини для цього на перший відповідь на це питання , як і return false;не виконуватиметься , якщо викликається, видає помилку, або ви можете додати return false;до doSomething()функції , а потім забути використанняreturn doSomething();



4

Якщо ви можете просто змінити hrefзначення, вам слід скористатися:

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

Ще одне акуратне рішення, яке я щойно придумав, - це використовувати jQuery, щоб запобігти появі дії кліку та викликати прокрутку сторінки, але лише для href="#"посилань.

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

Напевно return falseмає бути після preventDefault()рядка, інакше ви ніколи не потрапите на цей другий рядок?
hobailey


2

Крім того, ви можете використовувати event.preventDefault в атрибуті onclick .

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

Не потрібно писати події екстра натискання.


0

Ви також можете просто написати так:

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


0

Створіть сторінку, яка містить два посилання - одне вгорі та одне внизу. Натиснувши верхнє посилання, сторінка повинна прокручуватися донизу сторінки, де є нижня посилання. Натиснувши нижнє посилання, сторінка повинна прокручуватися вгору до верхньої частини сторінки.



0

Ви можете перевірити свій CSS. У прикладі тут: https://css-tricks.com/the-checkbox-hack/ є position: absolute; top: -9999px;. Це особливо гуфі в Chrome, якonclick="whatever" все ще стрибає в абсолютне положення клацнутого елемента.

Видалення position: absolute; top: -9999px;, бо display: none;може допомогти.


0

Для Bootstrap 3 для краху, якщо ви не вкажете ціль даних на якорі і не покладетеся на href для визначення цілі, подія буде запобіжена. Якщо ви користуєтеся цільовими даними, вам потрібно буде запобігти самій події.

<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>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.