On - window.location.hash - Изменить?

558

Я использую Ajax и хэш для навигации.

Есть ли способ проверить, window.location.hashизменились ли так?

http://example.com/blah # 123 to http://example.com/blah # 456

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

Но если у меня есть навигация на основе #hash, она не работает, когда я нажимаю кнопку «Назад» в браузере (поэтому я перехожу с бла # 456 на бла # 123).

Он отображается внутри поля адреса, но я не могу поймать его с помощью JavaScript.

MilMike
источник
6
Оформить заказ на этот плагин jquery: github.com/cowboy/jquery-hashchange
Хави,
9
History.js поддерживает функцию управления состоянием HTML5 (поэтому вам больше не нужно использовать хэши!) И изящно понижает ее до браузеров HTML4 с помощью хэш-хангов. Он поддерживает jQuery, MooTools и Prototype из коробки.
Балуптон
@balupton, на самом деле нам все еще нужно использовать хэши, чтобы предоставить пользователю обратную связь о том, что «новая страница» была вставлена ​​в его историю, если вы не используете изменение URL в качестве обратной связи.
Pacerier
1
[Hasher] github.com/millermedeiros/hasher
Вишну Рат
хм ... я думаю, тебе нужен рыжий jQuery
RaisingAgent

Ответы:

617

Единственный способ действительно сделать это (и как «настоящая история» делает это), это установить интервал, который продолжает проверять текущий хеш, и сравнивать его с тем, что было раньше, мы делаем это и позволяем подписчикам подписываться на измененный событие, которое мы запускаем, если хэш изменяется .. его не идеально, но браузеры действительно не поддерживают это событие изначально.


Обновите, чтобы сохранить этот ответ свежим:

Если вы используете jQuery (который сегодня должен быть несколько основополагающим для большинства), то хорошим решением будет использование абстракции, которую дает вам jQuery, используя свою систему событий для прослушивания событий hashchange в объекте window.

$(window).on('hashchange', function() {
  //.. work ..
});

Здесь хорошо то, что вы можете писать код, который даже не должен беспокоиться о поддержке хеширования, однако вам НЕОБХОДИМО сделать некоторую магию в виде несколько менее известной функции jQuery специальных событий jQuery .

С помощью этой функции вы, по сути, получаете возможность запускать некоторый установочный код для любого события, когда кто-то впервые пытается использовать событие каким-либо образом (например, привязку к событию).

В этом коде настройки вы можете проверить поддержку встроенного браузера, а если браузер не реализует его изначально, вы можете настроить один таймер для запроса изменений и вызвать событие jQuery.

Это полностью освобождает ваш код от необходимости понимать эту проблему поддержки, реализация специального события такого рода тривиальна (чтобы получить простую 98% рабочую версию), но зачем это делать, когда кто-то уже это сделал .

meandmycode
источник
7
IE8 делает. Больше впереди
Сергей Ильинский
28
Последняя сборка Firefox (3.6 альфа) также теперь поддерживает встроенное событие изменения хеша: developer.mozilla.org/en/DOM/window.onhashchange Конечно, стоит проверить это событие, но обратите внимание, что IE8 сообщит вам о событии существует, когда он работает в режиме сжатия IE7 .. к сожалению, событие не запускается .. вам нужно проверить событие и что браузер, похоже, не IE7 .. вздох (или попытка вызвать событие с помощью метода IE fireEvent).
meandmycode
8
На момент написания WebKit также запускает hashchangeсобытие, в то время как Safari (стабильный) еще нет.
jholster
51
Просто чтобы добавить еще одно обновление, hashchangeсобытие теперь широко поддерживается: caniuse.com/#search=hash
Paystey
19
Я единственный, кто думает, что нежелательные ответы jQuery - боль?
Люк
290

HTML5 определяет hashchangeсобытие . Это событие теперь поддерживается всеми современными браузерами . Поддержка была добавлена ​​в следующих версиях браузера:

  • Internet Explorer 8
  • Firefox 3.6
  • Chrome 5
  • Safari 5
  • Опера 10,6
миль
источник
20
Обновление: FF 5, Safari 5 и Chrome 12 поддерживают это событие с июня 2011 года.
james.garriss
2
Вот страница CanIUse для хэширования . Вот hashchange на причудливый режим . Поддержка IE глючит в отношении чувствительности к регистру.
Тобу
3
@ каждому, не нужно постоянно добавлять ответ в разделе комментариев - для этого и нужна кнопка «Изменить». :)
Майкл Мартин-Смукер
15
использование:window.onhashchange = function() { doYourStuff(); }
Крис
4
MDN документация события hashchange .
Dabowheel
52

Обратите внимание, что в случае Internet Explorer 7 и Internet Explorer 9 ifстатут даст значение true (для «onhashchange» в окнах), но window.onhashchangeникогда не сработает, поэтому лучше хранить хэш и проверять его через каждые 100 миллисекунд, независимо от того, изменился он или нет для всех версий Internet Explorer.

    if (("onhashchange" in window) && !($.browser.msie)) {
         window.onhashchange = function () {
              alert(window.location.hash);
         }
         // Or $(window).bind( 'hashchange',function(e) {
         //       alert(window.location.hash);
         //   });
    }
    else {
        var prevHash = window.location.hash;
        window.setInterval(function () {
           if (window.location.hash != prevHash) {
              prevHash = window.location.hash;
              alert(window.location.hash);
           }
        }, 100);
    }

РЕДАКТИРОВАТЬ - Начиная с jQuery 1.9, $.browser.msieне поддерживается. Источник: http://api.jquery.com/jquery.browser/

Хан Салахуддин
источник
14

Есть много хитростей, чтобы иметь дело с историей и window.location.hash в браузерах IE:

  • Как было сказано в оригинальном вопросе, если вы перейдете со страницы a.html # b на a.html # c, а затем нажмете кнопку «Назад», браузер не узнает, что страница изменилась. Позвольте мне сказать это на примере: window.location.href будет «a.html # c», независимо от того, находитесь ли вы в a.html # b или a.html # c.

  • На самом деле, a.html # b и a.html # c хранятся в истории только в том случае, если элементы <a name="#b"> и <a name="#c"> ранее существовали на странице.

  • Однако если вы поместите iframe на страницу, перейдите от a.html # b к a.html # c в этом iframe, а затем нажмите кнопку «Назад», если iframe.contentWindow.document.location.href изменится, как и ожидалось.

  • Если вы используете «document.domain = что - то » в своем коде, то вы не сможете получить доступ к iframe.contentWindow.document.open () '(и многие Менеджеры по истории делают это)

Я знаю, что это не реальный ответ, но, возможно, заметки IE-History кому-то пригодятся.

Серхио Чинос
источник
11

Бен Алман имеет отличный плагин jQuery для решения этой проблемы: http://benalman.com/projects/jquery-hashchange-plugin/

Если вы не используете jQuery, это может быть интересной ссылкой для анализа.

CJ.
источник
Плагин Ben Alman, похоже, больше не поддерживается. Хотя есть несколько вилок.
Mnebuerquo
9

Вы можете легко реализовать наблюдатель (метод watch) для свойства hash объекта window.location.

Firefox имеет свою собственную реализацию для наблюдения за изменениями объекта , но если вы используете какую-то другую реализацию (например, « Наблюдайте за изменениями свойств объекта в JavaScript» ) - для других браузеров, это сделает свое дело.

Код будет выглядеть так:

window.location.watch(
    'hash',
    function(id,oldVal,newVal){
        console.log("the window's hash value has changed from "+oldval+" to "+newVal);
    }
);

Тогда вы можете проверить это:

var myHashLink = "home";
window.location = window.location + "#" + myHashLink;

И, конечно, это вызовет функцию наблюдателя.

gion_13
источник
Лучше использовать: window.location.href вместо window.location.
Codebeat
3
Он смотрит window.location.hash, а не window.location.
не определено
1
@BrianMortenson: в соответствии с документами ( developer.mozilla.org/en-US/docs/JavaScript/Reference/… ) вы должны обратиться watchк объекту, которому принадлежит изменяемое свойство, и вы хотите его наблюдать.
gion_13
@ gion_13 Да, именно на это я и пытался указать. Под «Он» я имел в виду вас, и это было направлено на комментарий Эрвинуса. Я должен был быть более ясным. Спасибо за ваш уточняющий комментарий.
не определено
7

Я использовал это в приложении реагирования, чтобы URL отображал различные параметры в зависимости от того, какой вид был у пользователя.

Я смотрел параметр хеша с помощью

window.addEventListener('hashchange', doSomethingWithChangeFunction());

затем

doSomethingWithChangeFunction () { 
    // Get new hash value
    let urlParam = window.location.hash;
    // Do something with new hash value
};

Работал лакомством, работает с кнопками браузера вперед и назад, а также в истории браузера.

Sprose
источник
1
в вашем addEventListenerзвонке вы должны удалить ()изdoSomethingWithChangeFunction
Jason S
Можете ли вы указать причину удаления ()? Я знаю, что это будет работать с любым из них, и меньший код в большинстве случаев является лучшим вариантом, но это кажется придирчивым, если нет веских оснований для этого?
Спрос
6
? это не должно работать с (). addEventListenerФункция требует, чтобы передать в функцию. doSomethingWithChangeFunctionэто функция. doSomethingWithChangeFunction()Возвращаемое значение этой функции, которая в данном случае не является функцией.
Джейсон С
6

Достойную реализацию можно найти по адресу http://code.google.com/p/reallysimplehistory/ . Единственная (но также) проблема и ошибка, которые у него есть: в Internet Explorer изменение хэша местоположения вручную сбросит весь стек истории (это проблема браузера, и она не может быть решена).

Обратите внимание, что Internet Explorer 8 поддерживает событие hashchange, и, поскольку оно становится частью HTML5, вы можете ожидать, что другие браузеры наверстают упущенное.

Сергей Ильинский
источник
1

Другой замечательной реализацией является jQuery History, которая будет использовать собственное событие onhashchange, если оно поддерживается браузером, если нет, то будет использовать iframe или интервал для браузера соответствующим образом, чтобы обеспечить успешную эмуляцию всех ожидаемых функций. Он также предоставляет хороший интерфейс для привязки к определенным состояниям.

Стоит также отметить еще один проект - jQuery Ajaxy, который в значительной степени является расширением для истории jQuery для добавления ajax к миксу. Как, например, когда вы начинаете использовать ajax с хешами, это становится довольно сложно !

balupton
источник
1
var page_url = 'http://www.yoursite.com/'; // full path leading up to hash;
var current_url_w_hash = page_url + window.location.hash; // now you might have something like: http://www.yoursite.com/#123

function TrackHash() {
    if (document.location != page_url + current_url_w_hash) {
        window.location = document.location;
    }
    return false;
}
var RunTabs = setInterval(TrackHash, 200);

Вот и все ... теперь, каждый раз, когда вы нажимаете кнопки «назад» или «вперед», страница будет перезагружаться в соответствии с новым значением хеш-функции.

Бэтмен
источник
не используйте
пробные
1

Я использовал path.js для маршрутизации на стороне клиента. Я нашел его довольно лаконичным и легким (он также был опубликован в NPM) и использует навигацию на основе хеша.

path.js NPM

path.js GitHub

Том
источник
0

Я использовал плагин jQuery, HUtil , и написал поверх него интерфейс, похожий на историю YUI .

Проверьте это один раз. Если вам нужна помощь, я могу помочь.

moha297
источник