在Javascript中处理URL片段标识符(锚点)更改事件

95

如何编写 JavaScript 回调函数,以在 URL 片段标识符(锚点)改变时执行?

例如从 http://example.com#ahttp://example.com#b

7个回答

130

谷歌自定义搜索引擎使用定时器检查哈希值是否与先前的值匹配,而在不同域上的子iframe会更新父级的位置哈希以包含iframe文档体的大小。当计时器捕获到更改时,父级可以调整iframe的大小以匹配body的大小,以便不显示滚动条。

类似以下内容即可达到相同的效果:

var storedHash = window.location.hash;
window.setInterval(function () {
    if (window.location.hash != storedHash) {
        storedHash = window.location.hash;
        hashChanged(storedHash);
    }
}, 100); // Google uses 100ms intervals I think, might be lower

Google Chrome 5、Safari 5、Opera 10.60Firefox 3.6Internet Explorer 8全部支持hashchange事件:

if ("onhashchange" in window) // does the browser support the hashchange event?
    window.onhashchange = function () {
        hashChanged(window.location.hash);
    }

然后将它组合在一起:

if ("onhashchange" in window) { // event supported?
    window.onhashchange = function () {
        hashChanged(window.location.hash);
    }
}
else { // event not supported:
    var storedHash = window.location.hash;
    window.setInterval(function () {
        if (window.location.hash != storedHash) {
            storedHash = window.location.hash;
            hashChanged(storedHash);
        }
    }, 100);
}

jQuery也有一个插件,它将检查hashchange事件并在必要时提供自己的事件- http://benalman.com/projects/jquery-hashchange-plugin/.

编辑:更新了浏览器支持(再次)。


为了完整性,在“将它们放在一起”摘要块中添加“var storedHash = window.location.hash;”。顺便说一句:我认为现在这被称为 polyfill。 - Frank N
1
现在你可以监听window上的hashChange事件。https://dev59.com/4Gw15IYBdhLWcg3wzO1_ - Timo Huovinen
@AndyE 我已经阅读了答案,但我错过了小注释,并且我从未见过像 hashChanged(storedHash); 这样的事件。 - Timo Huovinen
1
@TimoHuovinen:“hashChanged”在这种情况下是由使用此代码的开发人员实现的函数。这里的答案仅演示了如何在“onhashchange”事件不可用的情况下监视哈希值的更改,并结合基于事件和基于计时器的方法提供通用解决方案。我的观点是,你链接的答案对这里的答案毫无贡献;-)。它们提供了相同的基本信息,甚至包括Ben Alman的jQuery插件链接。唯一的区别是我在我的答案中提供了一个纯JS解决方案。 - Andy E
@AndyE 好的,我不知道需要实现那个函数,谢谢你澄清。 - Timo Huovinen
1
我正在寻找一些轻量级的JS路由器,但这个工作做得很好。还消除了所有依赖 :) - gskema

11

可以为 hashchange 事件添加一个事件监听器,在片段标识符变化时触发:

window.addEventListener('hashchange', function() {
  // Perform action
  // [...]
})

我建议采用这种方法,而不是覆盖window.onhashchange,否则您将阻止其他插件使用此事件。

从今天全球浏览器的使用情况来看,不再需要回退,因为现代浏览器都支持此事件。


3

根据我在其他SO问题中看到的,唯一可行的跨浏览器解决方案是使用计时器。例如,请查看此问题


3

setInterval()是目前唯一的通用解决方案。但未来有一些光明的迹象,以hashchange事件的形式出现。


FYI:onhashchange事件的Mozilla开发者网络文档 - user216084

2
(仅供参考)YUI3的“hashchange”合成事件与已接受的答案基本相同。
YUI().use('history-hash', function (Y) {
  Y.on('hashchange', function (e) {
    // Handle hashchange events on the current window.
  }, Y.config.win);
});

1
这是一个使用jQuery的简单方法,对我很有效。我还添加了一个动画来滚动到锚点元素:
$(window).on('hashchange', function(e){
     var origEvent = e.originalEvent;
         var elementToBeClicked = $('a[href^="'+window.location.hash+'"]').click();  
        $([document.documentElement, document.body]).animate({
        scrollTop: 200
    }, 100);
});

希望它对你有用。

0
你可以从这里获取更多信息: 变异事件类型 引用:
变异事件模块旨在允许通知文档结构的任何更改,包括属性和文本修改。

这是关于DOM更改的内容。 - Raj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接