让 hashchange 事件在所有浏览器(包括 IE7)中工作

Posted

技术标签:

【中文标题】让 hashchange 事件在所有浏览器(包括 IE7)中工作【英文标题】:Get the hashchange event to work in all browsers (including IE7) 【发布时间】:2012-03-09 12:55:19 【问题描述】:

我有一些代码(由另一位开发人员编写)在 WordPress 中进行 AJAX 页面加载(例如,没有页面重新加载),当您单击导航项时,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

【问题讨论】:

【参考方案1】: attachEvent 要求事件以 on 为前缀。 您对该方法有不同的大小写。将 attachEvent 中的 hashchange 更改为 hashChange 以使该事件在 IE8 中运行。 使用建议的实现来支持 IE7 和其他旧浏览器的 hashchange 实现。

我创建了一个跨浏览器实现,它将hashchange 功能添加到浏览器,即使是那些使用not support 的浏览器。回退基于the specification。

//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 事件很有用。如果要添加多个hashchange 处理程序,请使用以下方法。 它定义了两个函数,addHashChangeremoveHashChange。两种方法都将函数作为参数。

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

【讨论】:

事件监听器现在已经正确绑定了,但是在IE7中不会做任何事情,因为它是not supported。 IE8 do support hashchange 事件虽然。对于 IE7,您必须通过 setInterval 检测 hashchanges。 嗯,你肯定在这里赢得了你的声誉@RobW - 谢谢一百万。你刚刚为我节省了几个小时,老实说,我不知道是否值得通过整个 setInterval 事情。看起来很头疼。 @RobW 干得好,但您不应该在 调用 hashChange 之后使用 oldHref = newHref 吗? @Oriol 假设hashChange 函数抛出错误。然后oldHref 将永远不会被重置,并且该函数会被一遍又一遍地调用。为了避免这个问题,我在使用它之前将它存储在一个局部变量中。 @IanLunn 这些 [add|remove]HashChange 函数提供了一个抽象来绑定 hashchange 事件。 hashChangeFuncs 是已注册回调的列表,在哈希更改时调用。【参考方案2】:

attachEvent 有两个参数:

bSuccess = object.attachEvent(sEvent, fpNotify)

[并且对于IE9以下的所有IE版本都需要! :(见MDN reference ]

这可以工作:

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/

【讨论】:

太好了,感谢您的提示。问题:即使在 IE7 JS 调试模式下,我也没有从函数本身得到任何错误(只有 addEventListener 在我使它成为条件之前)。还有其他调试建议吗?我试过你的代码,但仍然没有骰子......令人沮丧的是,也没有错误:/

以上是关于让 hashchange 事件在所有浏览器(包括 IE7)中工作的主要内容,如果未能解决你的问题,请参考以下文章

前端面试题之什么是hash,以及hashchange事件?

仅捕获不是由锚点点击引起的 hashchange 事件

hashchange 事件未在 IE10 和 IE11 中触发,具有 history.pushState 和 url 手动操作的组合

JS Hashchange 事件的 msie 问题

jQuery不支持hashchange事件

雷林鹏分享:jQuery Mobile 事件