Як я можу оновити window.location.hash, не стрибуючи документ?


163

У мене на своєму веб-сайті встановлена ​​розсувна панель.

Закінчивши анімацію, я встановив хеш так

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;

            }
    });
});

2
Я припускаю, що ви пробували event.preventDefault():)
Марко

@Marko Я не знаю, де його розмістити!
алекс

Чи можете ви опублікувати решту свого коду?
Марко

@Marko Ivanovski Не думаю, що це актуально, але я побачу, що я можу зробити.
alex

3
@Gareth Я не думаю, що там є місце, тому що це відбувається, як тільки я оновлюю хеш.
alex

Відповіді:


261

Існує рішення щодо використання API історії в сучасних браузерах із резервними копіями на старих:

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

Кредит йде на Леа Веру


Це краща відповідь, на мій погляд.
Грег Аннандейл

10
Зауважте, що pushState має побічний (з відступом) ефект додавання стану до стеку історії браузера. Іншими словами, коли користувач натискає кнопку "назад", нічого не відбудеться, якщо ви також не додасте слухача події з попідстатом.
Девід Кук

32
@DavidCook - Ми також могли б використати history.replaceState(що для змін хешу може мати більше сенсу), щоб уникнути необхідності popstateслухача подій.
Джек

Це працювало для мене. Мені подобається ефект зміни історії. Хочу додати застереження, що це не призведе до hashchangeподії. З цим мені довелося обійтись.
Йордан

увага! це не призведе до hashchangeподії
santiago arizti

52

Проблема полягає в тому, що ви встановлюєте window.location.hash для атрибута ID елемента. Очікувана поведінка браузера переходити до цього елемента, незалежно від того, ви "запобігаєтеDefault ()" чи ні.

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

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

2
Це єдине рішення, яке насправді відповідає на питання - дозволити хешування без стрибків
amosmos

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

1
гарне рішення, але послаблює рішення ОП, оскільки воно заперечує використання розділів закладок
Самус

27

Дешеве і неприємне рішення .. Використовуйте потворне #! стиль.

Щоб встановити його:

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

Щоб прочитати:

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

Оскільки він не збігається з якором або ідентифікатором на сторінці, він не перескочить.


3
Мені довелося зберегти сумісність з IE 7 та деякими мобільними версіями сайту. Це рішення було для мене найчистішим. Як правило, я буду весь на основі pushState рішень.
Ерік Гудвін

1
встановлення хеша на:, window.location.hash = '#/' + id;а потім замінивши його на: window.location.hash.replace(/^#\//, '#');трохи projects/#/tab1
покращить

13

Чому ви не отримуєте поточну позицію прокрутки, помістіть її в змінну, потім призначте хеш і покладіть сторінку прокрутки назад туди, де вона була:

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

це має працювати


1
хм, це працювало для мене деякий час, але десь за останні кілька місяців це перестало працювати над firefox ....
матч

10

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


2

Це рішення спрацювало на мене.

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

Проблема window.history.pushStateполягає в тому, що він додає запис до історії для кожної вкладки, яку натискає користувач. Потім, коли користувач натискає backкнопку, вони переходять до попередньої вкладки. (це може бути, а може і не бути тим, що ви хочете. Це було не те, чого я хотів).

Для мене replaceStateкращим варіантом було те, що він замінює лише поточну історію, тож коли користувач натискає backкнопку, вони переходять на попередню сторінку.

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

Перегляньте документи API API на MDN.


1

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


1

Це рішення спрацювало на мене

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

0

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

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

і я встановив його у своїй іншій функції JS, як це:

localStorage.setItem("hash", myvalue);

Ви можете називати свої місцеві значення пам’яті будь-яким способом; шахта ім hash.

Отже, якщо хеш встановлено на PAGE1 і ви переходите до PAGE2; хеш буде відтворено на PAGE1, коли ви натиснете кнопку Назад на PAGE2.

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