Как я могу обновить window.location.hash, не перепрыгивая документ?
У меня есть скользящая панель на моем сайте.
Когда анимация закончилась, я установил хеш так
function() {
window.location.hash = id;
}
(это обратный вызов, и id
назначен ранее).
Это хорошо работает, чтобы позволить пользователю добавить закладку на панель, а также для работы без версии JavaScript.
Однако, когда я обновляю хеш, браузер переходит к месту. Я предполагаю, что это ожидаемое поведение.
У меня вопрос: как я могу предотвратить это? Т.е. как я могу изменить хеш окна, но браузер не прокручивает до элемента, если хеш существует? Что-то подобное event.preventDefault()
Такие вещи?
Я использую jQuery 1.4 и плагин scrollTo.
Большое спасибо!
Обновить
Вот код, который меняет панель.
$('#something a').click(function(event) {
event.preventDefault();
var link = $(this);
var id = link[0].hash;
$('#slider').scrollTo(id, 800, {
onAfter: function() {
link.parents('li').siblings().removeClass('active');
link.parent().addClass('active');
window.location.hash = id;
}
});
});
9 ответов
Существует обходной путь с использованием API истории в современных браузерах с резервным вариантом на старых:
if(history.pushState) {
history.pushState(null, null, '#myhash');
}
else {
location.hash = '#myhash';
}
Кредит идет к Леа Веру
Проблема в том, что вы устанавливаете window.location.hash для атрибута ID элемента. Ожидается, что браузер будет переходить к этому элементу независимо от того, используете ли вы "protectDefault()" или нет.
Одним из способов обойти это является добавление к хешу произвольного значения, например:
window.location.hash = 'panel-' + id.replace('#', '');
Затем все, что вам нужно сделать, это проверить хэш с префиксом при загрузке страницы. В качестве дополнительного бонуса вы можете даже плавно прокрутить его, так как теперь вы контролируете значение хэша...
$(function(){
var h = window.location.hash.replace('panel-', '');
if (h) {
$('#slider').scrollTo(h, 800);
}
});
Если вам нужно, чтобы это работало постоянно (а не только при начальной загрузке страницы), вы можете использовать функцию для отслеживания изменений в значении хеш-кода и быстрого перехода к нужному элементу:
var foundHash;
setInterval(function() {
var h = window.location.hash.replace('panel-', '');
if (h && h !== foundHash) {
$('#slider').scrollTo(h, 800);
foundHash = h;
}
}, 100);
Дешевое и неприятное решение.. Используйте # уродливый! стиль.
Чтобы установить это:
window.location.hash = '#!' + id;
Чтобы прочитать это:
id = window.location.hash.replace(/^#!/, '');
Так как он не совпадает с привязкой или идентификатором на странице, он не будет прыгать.
Почему бы вам не получить текущую позицию прокрутки, поместить ее в переменную, назначить хэш и вернуть прокрутку страницы туда, где она была:
var yScroll=document.body.scrollTop;
window.location.hash = id;
document.body.scrollTop=yScroll;
это должно работать
Я использовал комбинацию решения Attila Fulop (Lea Verou) для современных браузеров и решения Gavin Brock для старых браузеров следующим образом:
if (history.pushState) {
// IE10, Firefox, Chrome, etc.
window.history.pushState(null, null, '#' + id);
} else {
// IE9, IE8, etc
window.location.hash = '#!' + id;
}
Как заметил Гэвин Брок, для получения идентификатора вам нужно будет обработать строку (которая в этом случае может иметь или не иметь "!") Следующим образом:
id = window.location.hash.replace(/^#!?/, '');
До этого я пробовал решение, похожее на предложенное пользователем 706270, но оно не работало с Internet Explorer: поскольку его движок Javascript не очень быстрый, вы можете заметить увеличение и уменьшение прокрутки, что приводит к неприятному визуальному эффекту.
Это решение сработало для меня
// store the currently selected tab in the hash value
if(history.pushState) {
window.history.pushState(null, null, '#' + id);
}
else {
window.location.hash = id;
}
// on load of the page: switch to the currently selected tab
var hash = window.location.hash;
$('#myTab a[href="' + hash + '"]').tab('show');
И мой полный код JS
$('#myTab a').click(function(e) {
e.preventDefault();
$(this).tab('show');
});
// store the currently selected tab in the hash value
$("ul.nav-tabs > li > a").on("shown.bs.tab", function(e) {
var id = $(e.target).attr("href").substr(1);
if(history.pushState) {
window.history.pushState(null, null, '#' + id);
}
else {
window.location.hash = id;
}
// window.location.hash = '#!' + id;
});
// on load of the page: switch to the currently selected tab
var hash = window.location.hash;
// console.log(hash);
$('#myTab a[href="' + hash + '"]').tab('show');
Это решение сработало для меня.
Проблема с настройкой location.hash
является то, что страница перейдет к этому идентификатору, если он найден на странице.
Проблема с window.history.pushState
является то, что он добавляет запись в историю для каждой вкладки, которую пользователь нажимает. Затем, когда пользователь нажимает back
Кнопка, они идут на предыдущую вкладку. (это может или не может быть то, что вы хотите. это было не то, что я хотел).
Для меня, replaceState
был лучшим вариантом в том, что он заменяет только текущую историю, поэтому, когда пользователь нажимает back
Кнопка, они идут на предыдущую страницу.
$('#tab-selector').tabs({
activate: function(e, ui) {
window.history.replaceState(null, null, ui.newPanel.selector);
}
});
Ознакомьтесь с документацией по истории API на MDN.
Я не уверен, что вы можете изменить исходный элемент, но как насчет переключения с использования идентификатора attr на что-то еще, например, на data-id? Затем просто прочитайте значение data-id для вашего хеш-значения, и оно не будет прыгать.
При использовании фреймворка laravel у меня возникли некоторые проблемы с использованием функции route->back(), поскольку она стерла мой хэш. Чтобы сохранить мой хэш, я создал простую функцию:
$(function() {
if (localStorage.getItem("hash") ){
location.hash = localStorage.getItem("hash");
}
});
и я установил это в моей другой функции JS следующим образом:
localStorage.setItem("hash", myvalue);
Вы можете назвать ваши значения локального хранилища так, как вам нравится; шахта имени hash
,
Поэтому, если хэш установлен на PAGE1, а затем вы переходите к PAGE2; хеш будет воссоздан на PAGE1, когда вы нажмете Back на PAGE2.