Обновление хэша адресной строки window.location с помощью scrollspy

У меня есть меню со scrollspy (используя twitter boostrap). Я хочу обновить window.location.hash, когда пользователь прокручивает до следующего раздела.

Следующий код работает, когда пользователь прокручивает страницу вниз:

$(window).on('activate.bs.scrollspy', function (e) {
  location.hash = $("a[href^='#']", e.target).attr("href") || location.hash;
});

Однако это не очень хорошо работает, когда пользователь прокручивает вверх.

Причина этого в том, что установка нового location.hash запускает браузер для перехода к соответствующему якорю. Это запускает цепную реакцию, в которой пользователь мгновенно оказывается в верхней части страницы.

Демо в js-fiddle

Теперь, что было бы самым простым способом решить эту проблему?


person d_inevitable    schedule 14.04.2014    source источник


Ответы (3)


Можно изменить состояние URL-адреса с помощью истории HTML5, не заставляя браузер следовать новому состоянию. Поддерживается не всеми браузерами.

Использование history.replaceState() имеет дополнительное преимущество: когда пользователь использует кнопку «Назад» в браузере, он не просто сначала прокручивается вверх.

$(window).on('activate.bs.scrollspy', function (e) {
    history.replaceState({}, "", $("a[href^='#']", e.target).attr("href"));
});

Посмотрите работающую js-скрипту.

person d_inevitable    schedule 15.04.2014

Для обновления более кроссбраузерного хэша вы можете использовать этот JS:

$(window).on('activate.bs.scrollspy', function(e) {
  var $hash, $node;
  $hash = $("a[href^='#']", e.target).attr("href").replace(/^#/, '');
  $node = $('#' + $hash);
  if ($node.length) {
    $node.attr('id', '');
  }
  document.location.hash = $hash;
  if ($node.length) {
    return $node.attr('id', $hash);
  }
});

Он временно удаляет искомый хэш, затем добавляет его через window.location, а затем восстанавливает рассматриваемый хэш. К сожалению, я не знаю точного диапазона совместимости для этого решения, но IE9 точно поддерживается и, возможно, все более старые версии в IE (я не забочусь о старых браузерах в своих проектах, поэтому я не тестировал это решение).

person jmarceli    schedule 09.01.2015
comment
Я бы улучшил это, используя location.replace, чтобы вы не засоряли историю пользователей этим. - person Nemo64; 22.09.2015
comment
Насколько я знаю, location.replace перезагрузит страницу, что нежелательно. - person jmarceli; 28.01.2017
comment
Поведение идентично щелчку по ссылке. Но мы можем просто попробовать ;). Просто выполните location.replace('#foo'), и URL-адрес изменится, а страница не перезагрузится. - person Nemo64; 13.02.2017

Я использую это для Bootstrap v4:

$(window).on('activate.bs.scrollspy', function(e) {
    history.replaceState({}, "", $('.nav-item .active').attr("href"));
});
person Someone    schedule 17.01.2018