Заставьте событие hashchange работать во всех браузерах (включая IE7)

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

Первоначальные начальные строки были

var queue = 0;

$('document').ready(function() {
    window.addEventListener("hashchange", hashChange, false);

    // Define window location variables
    var windowHost = window.location.host,
        windowHash = window.location.hash,
        windowPath = window.location.pathname;

Но я изменил их, чтобы сделать addEventListener условным в зависимости от того, присутствует этот метод или нет. Некоторые исследования показали мне, что этот метод недоступен в более старых версиях IE (например, 7 в моем случае). Кроме того, консоль отладки IE7 идентифицировала этот метод как недоступный, так что это довольно ясно. Я переписал строки следующим образом, но код все равно не работает:

var queue = 0;

$('document').ready(function() {
    if(window.addEventListener) {
        window.addEventListener("hashchange", hashChange, false);
    }
    else if (window.attachEvent) {
        window.attachEvent("hashchange", hashchange, false);    
    }
    // Define window location variables
    var windowHost = window.location.host,
        windowHash = window.location.hash,
        windowPath = window.location.pathname;

Полный исходный сценарий можно просмотреть в этом pastebin: http://pastebin.com/Jc9ySvrb.


person Brian    schedule 18.02.2012    source источник


Ответы (2)


  • attachEvent требует, чтобы события начинались с префикса < сильный>on.
  • У вас разные заглавные буквы для метода. Измените hashchange в attachEvent на hashChange, чтобы событие работало в IE8.
  • Используйте предложенную реализацию для поддержки реализации hashchange для IE7 и других старых браузеров.

Я создал кросс-браузерную реализацию, которая добавляет функцию hashchange в браузеры, даже те, которые используют не поддерживает это. Резервный вариант основан на спецификации.

//function hashchange  is assumed to exist. This function will fire on hashchange
if (!('onhashchange' in window)) {
    var oldHref = location.href;
    setInterval(function() {
        var newHref = location.href;
        if (oldHref !== newHref) {
            var _oldHref = oldHref;
            oldHref = newHref;
            hashChange.call(window, {
                'type': 'hashchange',
                'newURL': newHref,
                'oldURL': _oldHref
            });
        }
    }, 100);
} else if (window.addEventListener) {
    window.addEventListener("hashchange", hashChange, false);
}
else if (window.attachEvent) {
    window.attachEvent("onhashchange", hashChange);    
}

Примечание. Этот код полезен для одного события изменения хэша. Если вы хотите добавить несколько обработчиков hashchange, используйте следующий метод.
Он определяет две функции, addHashChange и removeHashChange. Оба метода принимают функцию в качестве аргумента.

(function() {
    if ('onhashchange' in window) {
        if (window.addEventListener) {
            window.addHashChange = function(func, before) {
                window.addEventListener('hashchange', func, before);
            };
            window.removeHashChange = function(func) {
                window.removeEventListener('hashchange', func);
            };
            return;
        } else if (window.attachEvent) {
            window.addHashChange = function(func) {
                window.attachEvent('onhashchange', func);
            };
            window.removeHashChange = function(func) {
                window.detachEvent('onhashchange', func);
            };
            return;
        }
    }
    var hashChangeFuncs = [];
    var oldHref = location.href;
    window.addHashChange = function(func, before) {
        if (typeof func === 'function')
            hashChangeFuncs[before?'unshift':'push'](func);
    };
    window.removeHashChange = function(func) {
        for (var i=hashChangeFuncs.length-1; i>=0; i--)
            if (hashChangeFuncs[i] === func)
                hashChangeFuncs.splice(i, 1);
    };
    setInterval(function() {
        var newHref = location.href;
        if (oldHref !== newHref) {
            var _oldHref = oldHref;
            oldHref = newHref;
            for (var i=0; i<hashChangeFuncs.length; i++) {
                hashChangeFuncs[i].call(window, {
                    'type': 'hashchange',
                    'newURL': newHref,
                    'oldURL': _oldHref
                });
            }
        }
    }, 100);
})();
// Usage, infinitely many times:
addHashChange(function(e){alert(e.newURL||location.href);});
person Rob W    schedule 18.02.2012
comment
Ну, ты определенно заслужил свою репутацию здесь, @RobW - спасибо миллион. Вы только что сэкономили мне часы, я, честно говоря, не знаю, стоит ли проходить через все это setInterval. Похоже на мега головную боль. - person Brian; 18.02.2012
comment
@Brian Довольно легко реализовать. Сохраните значение location.hash в переменной. Запустите setInterval с достаточно маленьким интервалом, скажем, 100. В методе setInterval сравните предыдущее значение location.hash с текущим значением. Если они разные, запустите пользовательское событие hashchange и сохраните новое значение location.hash в переменной. - person Rob W; 18.02.2012
comment
@RobW - эй, если я не придурок, если спрашиваю, можешь показать мне, как это выглядит? Я думаю, что это принесет пользу другим людям, которые рассматривают этот вопрос с той же проблемой несовместимости с IE7... - person Brian; 18.02.2012
comment
@Brian Добавлена ​​надежная кросс-браузерная реализация. Тщательно протестировано. - person Rob W; 18.02.2012
comment
@RobW, хороший ответ. Тем не менее, все еще не уверен, почему ответ с наибольшим количеством голосов не просто не делайте этого самостоятельно, используйте jQuery: D - person Coderer; 05.11.2012
comment
@RobW - это твердо. Спасибо, что поделился. - person Etai; 05.01.2014
comment
@RobW Хорошая работа, но разве вы не должны использовать oldHref = newHref после вызова hashChange? - person Oriol; 22.02.2014
comment
@RobG Почему ты используешь _oldHref? Не получится ли вызвать hashChange с oldHref, а после этого обновления oldHref? - person Oriol; 23.02.2014
comment
@Oriol Представьте, что функция hashChange выдает ошибку. Тогда oldHref никогда не будет сброшен, а функция будет вызываться снова и снова. Чтобы избежать этой проблемы, я сохраняю его в локальной переменной перед использованием. - person Rob W; 23.02.2014
comment
@RobW Не могли бы вы объяснить, что здесь происходит, в частности, необходимость hashChangeFuncs? - person Ian Lunn; 21.05.2014
comment
@IanLunn Эти функции [add|remove]HashChange предлагают абстракцию для привязки событий hashchange. hashChangeFuncs — это список зарегистрированных обратных вызовов, которые будут вызываться при изменении хэша. - person Rob W; 21.05.2014
comment
Полезный! Похоже, что в IE8 нет newURL или oldURL - person Joel; 01.09.2014
comment
@Joel Вы можете удалить часть else if (window.attachEvent) { ...}, если вам нужен новый/старый URL в IE8. - person Rob W; 01.09.2014
comment
@RobW Я сделал именно это. Просто стоит отметить. - person Joel; 02.09.2014

attachEvent принимает два параметра:

bSuccess = object.attachEvent(sEvent, fpNotify)

[И необходим для всех версий IE ниже IE9! :( См. справку по MDN]

Это может сработать:

if(window.addEventListener) {
    window.addEventListener("hashchange", hashChange, false);
}
else if (window.attachEvent) {
    window.attachEvent("onhashchange", hashchange);//SEE HERE...
    //missed the on. Fixed thanks to @Robs answer.
}

Конечно, если это возможно, вы должны просто использовать JQuery, так как он инкапсулирует все это для вашего.

И, как всегда, есть плагин: http://benalman.com/projects/jquery-hashchange-plugin/

person gideon    schedule 18.02.2012
comment
Это здорово, спасибо за наводку. Вопрос: Даже в режиме отладки IE7 JS я не получаю никаких ошибок от самой функции (только addEventListener до того, как я сделал ее условной). Любые другие предложения по отладке? Я попробовал ваш код, но до сих пор нет костей... к сожалению, ошибок тоже нет:/ - person Brian; 18.02.2012