Как я могу обновить window.location.hash без перескакивания документа?

У меня есть скользящая панель, настроенная на моем сайте.

Когда он закончил анимацию, я задал хэш так:

function() {
   window.location.hash = id;
}

(это обратный вызов, а id назначается ранее).

Это хорошо работает, чтобы пользователь мог добавлять закладки в панель, а также для версии, не поддерживающей JavaScript.

Однако, когда я обновляю хэш, браузер переходит к местоположению. Я предполагаю, что это ожидаемое поведение.

Мой вопрос: как я могу это предотвратить? То есть как я могу изменить хеш окна, но не, чтобы браузер просматривал элемент, если хеш существует? Какой-то тип event.preventDefault()?

Я использую jQuery 1.4 и scrollTo plugin.

Большое спасибо!

Update

Вот код, который изменяет панель.

$('#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;

            }
    });
});

Ответ 1

Существует обходной путь с использованием API истории в современных браузерах с резервным копированием старых:

if(history.pushState) {
    history.pushState(null, null, '#myhash');
}
else {
    location.hash = '#myhash';
}

Кредит отправляется Lea Verou

Ответ 2

Проблема заключается в том, что вы устанавливаете window.location.hash атрибут идентификатора элемента. Это ожидаемое поведение браузера для перехода к этому элементу, независимо от того, является ли вы "preventDefault()" или нет.

Один из способов обойти это - префикс хэша с произвольным значением:

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

Ответ 3

Дешевое и неприятное решение. Используйте уродливые #! стиль.

Чтобы установить его:

window.location.hash = '#!' + id;

Чтобы прочитать это:

id = window.location.hash.replace(/^#!/, '');

Так как он не соответствует, а привязка или идентификатор на странице, он не будет прыгать.

Ответ 4

Почему бы вам не получить текущую позицию прокрутки, поместить ее в переменную, а затем назначить хеш и поместить прокрутку страницы туда, где она была:

var yScroll=document.body.scrollTop;
window.location.hash = id;
document.body.scrollTop=yScroll;

это должно работать

Ответ 5

Я использовал комбинацию решения 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 не очень быстрый, вы можете заметить увеличение и уменьшение прокрутки, что приводит к неприятным визуальный эффект.

Ответ 6

Я не уверен, что вы можете изменить исходный элемент, но как переключиться с использования id attr на что-то еще, например, на идентификатор данных? Затем просто прочитайте значение id-данных для вашего хеш-значения, и оно не будет прыгать.

Ответ 7

Это решение сработало для меня.

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

Проблема с window.history.pushState заключается в том, что он добавляет запись в историю для каждой вкладки, которую нажимает пользователь. Затем, когда пользователь нажимает кнопку " back, он переходит на предыдущую вкладку. (это может или не может быть то, что вы хотите. это было не то, что я хотел).

Для меня более replaceState является replaceState, replaceState он заменяет только текущую историю, поэтому, когда пользователь нажимает кнопку " back, он переходит на предыдущую страницу.

$('#tab-selector').tabs({
  activate: function(e, ui) {
    window.history.replaceState(null, null, ui.newPanel.selector);
  }
});

Ознакомьтесь с документацией по истории API на MDN.

Ответ 8

При использовании laravel Framework у меня были некоторые проблемы с использованием функции route-> back(), так как она стерла мой хэш. Чтобы сохранить мой хэш, я создал простую функцию:

$(function() {   
    if (localStorage.getItem("hash")    ){
     location.hash = localStorage.getItem("hash");
    }
}); 

и я установил это в моей другой функции JS следующим образом:

localStorage.setItem("hash", myvalue);

Вы можете назвать ваши значения локального хранилища так, как вам нравится; мой по имени hash.

Поэтому, если хэш установлен на PAGE1, а затем вы переходите к PAGE2; хеш будет воссоздан на PAGE1, когда вы нажмете Back на PAGE2.

Ответ 9

Это решение сработало для меня

// 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');

Ответ 10

[H] Как я могу изменить хеш окна, но браузер не прокручивает до элемента, если хеш существует?

Чтобы изменить хеш и не использовать прокрутку браузера, используйте scrollRestorationMode. У него есть два значения:

"auto" - пользовательский агент отвечает за восстановление позиции прокрутки при навигации. (дефолт)
"manual" - страница отвечает за восстановление позиции прокрутки.

Установите значение "manual" в вашем скрипте перед обновлением истории:

history.scrollRestoration = 'manual';
document.history.pushState({}, null, '#slider');

Я использую jQuery 1.4 и плагин scrollTo.

Попробуйте использовать scroll-behavior вместо значения smooth для более плавного хода.