JavaScript中记录哈希/锚点变化的历史记录

28

我目前正在实现一个JavaScript库,用于跟踪地址栏哈希部分的更改历史。这个想法是可以在哈希部分中保留状态,并使用后退按钮返回到上一个状态。

在大多数现代浏览器中,这是自动的,你只需轮询location.hash属性以检测变化(在IE8中,你甚至不需要这样做;你只需将函数附加到onhashchange事件即可)。

我的疑问是,有哪些不同的方法来跟踪历史记录?我已经实现了经过测试可以在Internet Explorer 6/7/8、Firefox和Chrome中工作的功能,但其他浏览器呢?以下是我目前保持历史记录的方式:

编辑:请看下面的答案,了解各种浏览器的操作步骤。

5个回答

32

首先,感谢回答问题的各位!=)

我现在已经做了更多的研究,并且我相信我对我的实现感到满意。以下是我的研究结果。

首先是我完成的Hash。这是一个独立的库,没有依赖关系。它有两个函数:Hash.init(callback,iframe)Hash.go(newHash)。每当哈希值发生变化时,回调函数被调用,新哈希作为其第一个参数传递,第二个参数作为标志,指示回调是由于初始状态(true)还是由于哈希值的实际更改(false)而被调用。

Hash.js (MIT许可证)

我还制作了一个jQuery插件,使其更易于使用。同时添加了全局hashchange事件。请参见源代码中的示例。

jquery.hash.js (MIT许可证)

要查看它们的使用情况,请转到我的JavaScript“领域”页面:

Blixt的JavaScript领域

Internet Explorer 8

顺畅航行!只需将一个onhashchange事件附加到window对象(使用attachEvent),并在事件处理程序中获取location.hash值。

无论用户是否单击带有哈希值的链接,或者您是否以编程方式设置哈希值,历史记录都会被完美地保存。

Chrome、Firefox、Safari 3+、Opera 8+

顺畅的浏览!只需使用setInterval和函数,轮询检查location.hash属性的更改记录。

历史记录可以完美工作。对于Opera浏览器,我将history.navigationMode设置为'compatible'。说实话,我不确定它具体是什么作用,我是在YUI代码的评论中得到的建议。

注意: Opera 浏览器需要进行额外的测试,但至目前为止对我来说已经运行良好。

惊喜的小问题奖励!(真的吗?!) 原来 Firefox 浏览器(仅在3.5+版本中确认)会解码location.hash属性,因此这可能会触发两次 hashchange 事件(先是编码版本,然后是未编码版本)。我的 Hash.js 库有一个新版本,通过使用 location.href属性来解决该问题(由 Aaron Ogle 提供更改)。

Internet Explorer 6、7

现在问题变得更加复杂。较旧版本的 Internet Explorer 浏览器中的导航历史忽略哈希变化。为了解决这个问题,通常接受的解决方案是创建一个 iframe,并将其内容设置为新的哈希。这会在导航历史中创建一个新条目。当用户返回时,这将使iframe的内容恢复为其先前的内容。通过检测内容的更改,可以获取并将其设置为活动哈希。

仍然需要检查 location.hash 属性是否更改,以处理当前地址的手动更改。但请注意下面提到的小问题。

虽然这个解决方案似乎是最好的解决方案,但在 Internet Explorer 6 中仍然不完美,它对于后退/前进按钮有些奇怪的问题。不过,在 Internet Explorer 7 中运行良好。

惊喜奇怪特性附赠1!在Internet Explorer 6中,每当哈希中有问号时,它会被提取出来放入location.search属性中!它将从location.hash属性中删除。但是,如果有真正的查询字符串,location.search将包含该查询字符串,您只能通过解析location.href属性来获取整个真正的哈希值。

惊喜奇怪特性附赠2!如果设置了location.search属性,则任何后续的#字符都将从location.href(和location.hash)属性中删除。在Internet Explorer 6中,这意味着每当路径或哈希中有问号时,您都会遇到此问题。在Internet Explorer 7中,仅当路径中有问号时才会出现此问题。您难道不喜欢Internet Explorer的一致性吗?

惊喜奇怪特性附赠3!如果页面上的另一个元素具有与哈希值相同的ID值,那么该哈希值将完全破坏历史记录。因此,经验法则是避免使用与页面上任何元素相同的ID值作为哈希值。如果哈希值是动态生成的并可能与id冲突,请考虑使用前缀/后缀。

其他浏览器

除非您拥有非同寻常的用户群体,否则不需要支持更多浏览器。未列出在上面的浏览器属于<1%的使用率类别。


5
"这是一个独立的库,没有任何依赖关系。" - 谢谢!太好了。 - outcassed
这个明显的失败在于:当你点击一个新链接时,hashchange事件只会触发,如果该链接是使用你的软件创建的(我认为一个简单的“a”标签是不够的,你的代码需要篡改它),或者你从另一个页面访问。但是,在浏览器的后退和前进时,它却不会触发。根据其他实现的经验,我认为你需要一个计时器来轮询变化。 - ijw
我知道这有点老了,但是有人可以详细说明一下“惊喜怪癖奖励#3”的细节吗?问题到底是什么?你有展示问题的测试用例吗? - Grodriguez

3

根据您所做的努力,我认为您已经看过YUI浏览器历史管理器,但以防万一...

他们对他们的实现进行了很好的介绍,我发现他们的源代码非常易读。

这是关于Opera的内容:

* location.hash is a bit buggy on Opera. I have seen instances where
* navigating the history using the back/forward buttons, and hence
* changing the URL, would not change location.hash. That's ok, the
* implementation of an equivalent is trivial ... more below

我找到了一些适用于Safari 1.x和2.0的解决方案。看起来你会对此感兴趣。

希望这有所帮助。


是的,我参考了他们的实现,并在我的代码中使用了一些灵感。我确实看过他们的Safari实现,但是我找不到一个简单的方法使其工作,并且要大幅增加代码量,这就是为什么我在想是否还有足够多的人在使用Safari 2及以下版本以值得支持的原因。 - Blixt
2
根据 http://www.w3counter.com/globalstats.php?date=2009-01-31 的数据,2009 年 1 月份 Safari 2 占有率为 0.5%。因此,在 6 个月之前,占有率约为 1/200。 - Keith Bentrup
谢谢Keith!我决定不支持Safari 2,因为代码会干扰现代浏览器,除非实施浏览器嗅探...而我不喜欢。=) - Blixt

1

我需要一种轻量级的方法来简单地跟踪哈希值并支持所有常用浏览器中相同的前进/后退按钮行为。RSH似乎不是这样一个库,因为即使在YUI压缩下也超过9kB,并且仍然依赖于外部库...我的自己的库目前压缩后只有835字节,在IE6+、Firefox、Chrome和可能的Opera 8+和Safari 3+中工作,没有依赖项...我主要想知道是否还有其他浏览器需要支持以及如何支持它们。 - Blixt

0

我还没有看到任何关于我即将说的内容的提及,所以我想分享一下,看看这是否是常识。

在IE(仅在IE7中验证),当屏幕上有一个id等于哈希值的页面元素时,哈希值与历史记录可以正常工作。例如,在维基页面上的目录(TOC)中,TOC中的每个链接都链接到页面上某个id或锚点名称元素的哈希值:

<div id="TOC">
<a id="SampleHeaderLink" href="#SampleHeader">Sample Header</a>
</div>

<h2 id="SampleHeader">Sample Header</a>

因此,当单击SampleHeaderLink时,IE浏览器的默认设置是导航到SampleHeader并在历史记录中注册状态。使用后退按钮和前进按钮按预期工作。

然而,如果页面上不存在SampleHeader div,则浏览器仅注册url更改,但不为其创建新状态。

同样,这仅在IE7中得到验证。我不知道这些信息有多常见,但当我浏览以解决自己应用程序中的此问题时,我从未找到任何相关内容。


我确实提到了这一点 - 或者说它的反面。如果使用“iframe”方法,如果您尝试使用现有元素的id作为哈希值,历史记录将完全混乱。因此,我想您必须在不使用任何id或仅使用id之间进行选择。 - Blixt

-1

GWT提供历史管理功能。它也是他们MVP框架的一个重要组成部分。他们还通过地点和活动增强了历史API。


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