Как отключить якорный "прыжок" при загрузке страницы?
Я думаю, что это может быть невозможно, постараюсь объяснить как можно лучше. У меня есть страница, содержащая вкладки (с поддержкой jquery), которыми управляют:
Я использую этот код, предоставленный другим пользователем из предыдущего вопроса.
<script type="text/javascript">
$(function() {
$('html, body').animate({scrollTop:0}); // this is my "fix"
var tabContent = $(".tab_content");
var tabs = $("#menu li");
var hash = window.location.hash;
tabContent.not(hash).hide();
if(hash=="") {
$('#tab1').fadeIn();
}
tabs.find('[href=' + hash + ']').parent().addClass('active');
tabs.click(function() {
$(this).addClass('active').siblings().removeClass('active');
tabContent.hide();
var activeTab = $(this).find("a").attr("href");
$(activeTab).fadeIn();
return false;
});
});
</script>
этот код прекрасно работает, когда я захожу на страницу "вкладки" напрямую.
тем не менее, мне нужно сослаться на отдельные вкладки с других страниц - поэтому для этого код получает window.location.hash
затем показывает соответствующую вкладку.
страница не "перепрыгивает" на якорь из-за "return false".
однако это событие вызывается только при событии щелчка. следовательно, если я посещаю мои "вкладки" с любой другой страницы, срабатывает эффект "прыжка". Чтобы бороться с этим, я автоматически прокручиваю до верхней части страницы, но я бы предпочел, чтобы этого не произошло.
Есть ли способ имитировать "возвращать ложь" при загрузке страницы, предотвращая "прыжок" якоря.
надеюсь, это достаточно ясно.
Спасибо
16 ответов
Ваше исправление не работает? Я не уверен, правильно ли я понял вопрос - у вас есть демо-страница? Вы можете попробовать:
if (location.hash) {
setTimeout(function() {
window.scrollTo(0, 0);
}, 1);
}
Редактировать: протестировано и работает в Firefox, IE и Chrome в Windows.
Редактировать 2: переместить setTimeout()
внутри if
блок, реквизит @vsync.
Смотрите мой ответ здесь: Stackru Ответ
Хитрость заключается в том, чтобы просто удалить хештег как можно скорее и сохранить его значение для собственного использования:
Важно, чтобы вы не помещали эту часть кода в функции $() или $(window).load(), как это было бы поздно, и браузер уже перешел на тег.
// store the hash (DON'T put this code inside the $() function, it has to be executed
// right away before the browser can start scrolling!
var target = window.location.hash,
target = target.replace('#', '');
// delete hash so the page won't scroll to it
window.location.hash = "";
// now whenever you are ready do whatever you want
// (in this case I use jQuery to scroll to the tag after the page has loaded)
$(window).on('load', function() {
if (target) {
$('html, body').animate({
scrollTop: $("#" + target).offset().top
}, 700, 'swing', function () {});
}
});
Браузер переходит к
<element id="abc" />
если в адресе есть http://site.com/ hash и элемент с id="abc" виден. Итак, вы просто должны скрыть элемент по умолчанию:<element id="anchor" style="display: none" />
, Если на странице нет видимого элемента с id = hash, браузер не будет прыгать.Создайте скрипт, который проверяет хэш в URL, а затем находит и показывает элемент prrpopriate (который по умолчанию скрыт).
Отключите стандартное поведение "хеш-подобная ссылка", привязав событие onclick к ссылке и укажите
return false;
в результате события onclick.
Когда я реализовал вкладки, я написал что-то вроде этого:
<script>
$(function () {
if (location.hash != "") {
selectPersonalTab(location.hash);
}
else {
selectPersonalTab("#cards");
}
});
function selectPersonalTab(hash) {
$("#personal li").removeClass("active");
$("a[href$=" + hash + "]").closest("li").addClass("active");
$("#personaldata > div").hide();
location.hash = hash;
$(hash).show();
}
$("#personal li a").click(function (e) {
var t = e.target;
if (t.href.indexOf("#") != -1) {
var hash = t.href.substr(t.href.indexOf("#"));
selectPersonalTab(hash);
return false;
}
});
</script>
Есть и другие способы отслеживания того, на какой вкладке вы находитесь; возможно, установив куки, или значение в скрытом поле, и т. д. и т. д.
Я бы сказал, что если вы не хотите, чтобы страница загружалась, вам лучше использовать один из этих вариантов, а не хеш, потому что основная причина использования хеша в предпочтении к ним состоит в том, чтобы разрешить именно то, что вы Вы хотите заблокировать.
Другой момент - страница не будет перемещаться, если ваши хеш-ссылки не совпадают с именами тегов в документе, поэтому, возможно, если вы захотите продолжать использовать хэш, вы можете манипулировать содержимым, чтобы теги назывались по-разному. Если вы используете последовательный префикс, вы все равно сможете использовать Javascript для перехода между ними.
Надеюсь, это поможет.
Я использовал решение dave1010, но оно было немного странным, когда я поместил его в функцию $(). Ready. Итак, я сделал это: (не внутри $(). Готов)
if (location.hash) { // do the test straight away
window.scrollTo(0, 0); // execute it straight away
setTimeout(function() {
window.scrollTo(0, 0); // run it a bit later also for browser compatibility
}, 1);
}
Ни один из ответов не работает достаточно хорошо для меня, я вижу, что страница прыгает на якорь, а затем на вершину для некоторых решений, некоторые ответы не работают вообще, возможно, вещи менялись годами. Надеюсь, моя функция кому-то поможет.
/**
* Prevent automatic scrolling of page to anchor by browser after loading of page.
* Do not call this function in $(...) or $(window).on('load', ...),
* it should be called earlier, as soon as possible.
*/
function preventAnchorScroll() {
var scrollToTop = function () {
$(window).scrollTop(0);
};
if (window.location.hash) {
// handler is executed at most once
$(window).one('scroll', scrollToTop);
}
// make sure to release scroll 1 second after document readiness
// to avoid negative UX
$(function () {
setTimeout(
function () {
$(window).off('scroll', scrollToTop);
},
1000
);
});
}
Исправлен только грязный CSS, чтобы оставаться прокручиваемым каждый раз, когда используется привязка (бесполезно, если вы все еще хотите использовать привязки для переходов прокрутки, очень полезно для глубоких ссылок):
.elementsWithAnchorIds::before {
content: "";
display: block;
height: 9999px;
margin-top: -9999px; //higher thin page height
}
Несмотря на то, что принятый ответ работает хорошо, я обнаружил, что иногда, особенно на страницах, содержащих большие изображения, полоса прокрутки будет быстро перемещаться
window.scrollTo(0, 0);
Что может быть довольно отвлекающим для пользователя.
Решение, на котором я остановился в конце концов, на самом деле довольно простое, и оно заключается в использовании другого идентификатора на цели, чем тот, который использовался в location.hash
Например:
Вот ссылка на какой-то другой странице
<a href="/page/with/tabs#tab2">Some info found in tab2 on tabs page</a>
Так что, конечно, если есть элемент с идентификатором tab2
на странице вкладок окно перейдет к нему при загрузке.
Таким образом, вы можете добавить что-то к идентификатору, чтобы предотвратить это:
<div id="tab2-noScroll">tab2 content</div>
И тогда вы можете добавить "-noScroll"
в location.hash
в JavaScript:
<script type="text/javascript">
$(function() {
var tabContent = $(".tab_content");
var tabs = $("#menu li");
var hash = window.location.hash;
tabContent.not(hash + '-noScroll').hide();
if(hash=="") { //^ here
$('#tab1-noScroll').fadeIn();
}
tabs.find('[href=' + hash + ']').parent().addClass('active');
tabs.click(function() {
$(this).addClass('active').siblings().removeClass('active');
tabContent.hide();
var activeTab = $(this).find("a").attr("href") + '-noScroll';
//^ and here
$(activeTab).fadeIn();
return false;
});
});
</script>
В моем случае из-за использования якорной ссылки для всплывающего окна CSS я использовал этот способ:
Просто сначала сохраните страницу YOffset, а затем установите ScrollTop на это:
$(document).on('click','yourtarget',function(){
var st=window.pageYOffset;
$('html, body').animate({
'scrollTop' : st
});
});
Это будет работать с bootstrap v3
$(document).ready(function() {
if ($('.nav-tabs').length) {
var hash = window.location.hash;
var hashEl = $('ul.nav a[href="' + hash + '"]');
hash && hashEl.tab('show');
$('.nav-tabs a').click(function(e) {
e.preventDefault();
$(this).tab('show');
window.location.hash = this.hash;
});
// Change tab on hashchange
window.addEventListener('hashchange', function() {
var changedHash = window.location.hash;
changedHash && $('ul.nav a[href="' + changedHash + '"]').tab('show');
}, false);
}
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>
<div class="container">
<ul class="nav nav-tabs">
<li class="active"><a data-toggle="tab" href="#home">Home</a></li>
<li><a data-toggle="tab" href="#menu1">Menu 1</a></li>
</ul>
<div class="tab-content">
<div id="home" class="tab-pane fade in active">
<h3>HOME</h3>
<p>Some content.</p>
</div>
<div id="menu1" class="tab-pane fade">
<h3>Menu 1</h3>
<p>Some content in menu 1.</p>
</div>
</div>
</div>
Я думаю, что я нашел способ для вкладок пользовательского интерфейса без изменения функциональности. До сих пор я не нашел никаких проблем.
$( ".tabs" ).tabs();
$( ".tabs" ).not(".noHash").bind("tabsshow", function(event, ui) {
window.location.hash = "tab_"+ui.tab.hash.replace(/#/,"");
return false;
});
var selectedTabHash = window.location.hash.replace(/tab_/,"");
var index = $( ".tabs li a" ).index($(".tabs li a[href='"+selectedTabHash+"']"));
$( ".tabs" ).not(".noHash").tabs('select', index);
Все в рамках готового мероприятия. Он добавляет "tab_" для хеша, но работает как при нажатии, так и при загрузке страницы с хешем.
У меня не было последовательного успеха с этими решениями.
Видимо, из-за того, что переход происходит раньше, чем Javascript => ссылка ( http://forum.jquery.com/topic/preventing-anchor-jump)
Мое решение состоит в том, чтобы разместить все якоря наверху по умолчанию с помощью CSS.
.scroll-target{position:fixed;top:0;left:0;}
Затем используйте jquery для прокрутки до родительского объекта целевого якоря или одноуровневого элемента (возможно, пустого тега em)
<a class="scroll-target" name="section3"></a><em> </em>
Пример jquery для прокрутки, когда URL вводится с помощью хэша
(страница не должна быть уже загружена в окне / вкладке, это касается ссылок из других / внешних источников)
setTimeout(function() {
if (window.location.hash) {
var hash = window.location.hash.substr(1);
var scrollPos = $('.scroll-target[name="'+hash+'"]').siblings('em').offset().top;
$("html, body").animate({ scrollTop: scrollPos }, 1000);
}
}, 1);
Также вы захотите запретить клики привязки по умолчанию на странице, а затем прокрутить их цели.
<a class="scroll-to" href="#section3">section three</a>
и JQuery
$('a.scroll-to').click(function(){
var target = $(this).attr('href').substr(1);
var scrollPos = $('.scroll-target[name="'+target+'"]').siblings('em').offset().top;
$("html, body").animate({ scrollTop: scrollPos }, 1000);
return false;
});
Хорошая вещь в этом методе - это целевые теги привязки, которые остаются структурно рядом с релевантным контентом, хотя их CSS-позиция находится сверху.
Это должно означать, что сканеры поисковых систем не будут иметь проблемы.
Ура, я надеюсь, что это помогает
Серый
У меня не было большого успеха с вышеупомянутым setTimeout
методы в Firefox.
Вместо setTimeout я использовал функцию onload:
window.onload = function () {
if (location.hash) {
window.scrollTo(0, 0);
}
};
Это все еще очень затруднительно, к сожалению.
Решил мою проблему следующим образом:
// navbar height
var navHeigth = $('nav.navbar').height();
// Scroll to anchor function
var scrollToAnchor = function(hash) {
// If got a hash
if (hash) {
// Scroll to the top (prevention for Chrome)
window.scrollTo(0, 0);
// Anchor element
var term = $(hash);
// If element with hash id is defined
if (term) {
// Get top offset, including header height
var scrollto = term.offset().top - navHeigth;
// Capture id value
var id = term.attr('id');
// Capture name value
var name = term.attr('name');
// Remove attributes for FF scroll prevention
term.removeAttr('id').removeAttr('name');
// Scroll to element
$('html, body').animate({scrollTop:scrollto}, 0);
// Returning id and name after .5sec for the next scroll
setTimeout(function() {
term.attr('id', id).attr('name', name);
}, 500);
}
}
};
// if we are opening the page by url
if (location.hash) {
scrollToAnchor(location.hash);
}
// preventing default click on links with an anchor
$('a[href*="#"]').click(function(e) {
e.preventDefault();
// hash value
var hash = this.href.substr(this.href.indexOf("#"));
scrollToAnchor(hash);
});`
Попробуйте сделать это, чтобы предотвратить любые виды вертикальной прокрутки клиента при хешировании (в вашем обработчике событий):
var sct = document.body.scrollTop;
document.location.hash = '#next'; // or other manipulation
document.body.scrollTop = sct;
(перерисовка браузера)
Другой подход
Попробуйте проверить, была ли страница прокручена, и только затем сбросьте позицию:
var scrolled = false;
$(window).scroll(function(){
scrolled = true;
});
if ( window.location.hash && scrolled ) {
$(window).scrollTop( 0 );
}