在AJAX应用中修改地址栏URL以匹配当前状态


166

我正在编写一个AJAX应用程序,但是当用户浏览该应用程序时,尽管页面没有重新加载,但我还是希望地址栏中的URL能够更新。基本上,我希望他们能够在任何时候添加书签,从而返回到当前状态。

人们如何处理维护AJAX应用程序中的RESTful?


2
它用于保持应用程序的状态,但与“ RESTfulness”无关。
穆罕默德

29
window.history.pushState(null,'hi','page1?id=32')
Omu 2012年

3
接受的答案写在5年之前,与此同时,我们得到了window.history.pushState,就像@Omu所说的那样。location.hash带来了很多问题,最好避免这种情况。
pcarvalho

我已经编辑了答案,使pushState方法更加突出。
jasonjwwilliams 2014年

Answers:


116

执行此操作的方法是location.hash在AJAX更新导致您希望使用离散URL的状态更改时进行操作。例如,如果您的页面网址是:

http://example.com/

如果客户端功能执行了以下代码:

// AJAX code to display the "foo" state goes here.

location.hash = 'foo';

然后,在浏览器中显示的URL将更新为:

http://example.com/#foo

这使用户可以为页面的“ foo”状态添加书签,并使用浏览器历史记录在状态之间进行导航。

使用此机制后,您将需要使用JavaScript在客户端解析URL的哈希部分,以创建并显示适当的初始状态,因为片段标识符(#后面的部分)不会发送到服务器。

如果您使用jQuery,Ben Alman的hashchange插件使后者变得轻而易举。


看起来你是对的。那是唯一的方法。这似乎是对您的建议的很好的详细解释:< ajaxpatterns.org/Unique_URLs >
jasonjwwilliams

@buymeasoda感谢您的编辑;我不确定写那部分时在想什么。
戴夫·沃德

1
哇,这个答案很有帮助。尽管URL示例有些混乱,但是SO可能会自动将标题替换为链接。如何将它们替换为example.com和example.com/#foo之类的内容,以便我们可以以纯文本格式看到整个URL。
尼尔

4
@Pascal可以(但仅在支持HTML5的pushState的浏览器中)。此处的好信息:diveintohtml5.info/history.html
戴夫·沃德

1
我最终成为了history.js的忠实
拥护者

18

查看类似于book.cakephp.org的网站。该站点无需使用哈希即可更改URL并使用AJAX。我不确定它是如何做到的,但是我一直在努力弄清楚。如果有人知道,请告诉我。

在特定项目中导航时也请访问github.com。


我大约一周前在GitHub上注意到了这一点。他们到底是怎么做到的?必须回去检查。
德鲁·诺阿克斯

16
他们似乎正在使用JavaScript函数pushState()。这会增加浏览器的历史记录。了解更多; 这很有趣,很酷。
daniel.wright 2011年

谢谢,这正是我想要的。我想知道github是如何做到的。起初,我认为它必须重新加载,但只有AJAX请求。在Opera中,它确实重新加载了页面。
kamranicus 2011年

fb在浏览不同组的页面时使用了类似的技术。您有一个左导航栏,其中提到了不同的组。单击特定的组名时,URL会更改,只有主内容窗格的内容会随URL一起更改(无哈希值)。因此,当用户重新加载页面时,他们不会重定向到主页,而是重定向到组的页面。
Madeyedexter


11

这类似于凯文所说的。您可以将客户端状态作为某些javascript对象,并且要保存状态时,可以序列化对象(使用JSON和base64编码)。然后,您可以将href的片段设置为此字符串。

var encodedState = base64(json(state));
var newLocation = oldLocationWithoutFragment + "#" + encodedState;

document.location = newLocation; // adds new entry in browser history
document.location.replace(newLocation); // replaces current entry in browser history

第一种方法会将新状态视为新位置(因此,后退按钮会将它们带到先前的位置)。后者没有。


是否可以在不刷新页面的情况下将条目添加到书签历史记录?设置位置(如您的第一个示例中所示)将导致刷新,不是吗?
德鲁·诺阿克斯

做document.location.replace还将浏览器重定向到该URL(只是在chrome控制台中尝试过)
Omu 2012年

3

SWFAddress可在Flash和Javascript项目中使用,它使您可以创建可加书签的URL(使用上述哈希方法),并为您提供后退按钮支持。

http://www.asual.com/swfaddress/


3

window.location.hash方法是首选的处理方式。有关如何执行此操作的说明,请参见 Ajax模式-唯一URL

YUI将这种模式实现为一个模块,其中包括IE专用的解决方法,用于使后退按钮起作用,并使用哈希值重新写入地址。YUI浏览器历史记录管理器

其他框架也具有类似的实现。重要的一点是,如果您希望历史记录与重写地址一起使用,则不同的浏览器需要不同的处理方式。(这在第一篇链接文章中有详细介绍。)

IE需要基于iframe的hack,而Firefox将使用相同的方法产生双重历史记录。


3

如果OP或其他人仍在寻找一种修改浏览器历史记录以启用状态的方法,那么按照IESUS的建议,使用pushState和replaceState是现在的“正确”方法。与location.hash相比,它的主要优势是哈希可以创建实际的网址,而不仅仅是散列。如果保存了使用哈希的浏览器历史记录,然后在禁用javascript的情况下重新访问了该应用,则该应用将无法运行,因为哈希不会发送到服务器。但是,如果已使用pushState,则将整个路由发送到服务器,然后可以对其进行构建以对路由做出适当响应。我看到了一个示例,其中服务器和客户端都使用了相同的胡须模板。如果客户端启用了javascript,则他将避免访问服务器,从而获得快速响应,但如果没有javascript,该应用将可以正常运行。因此,在没有javascript的情况下,该应用可以正常降级。

另外,我相信这里有一些框架,名称类似于history.js。对于支持HTML5的浏览器,它使用pushState,但如果浏览器不支持,则自动退回到使用哈希。


2

检查用户是否在页面中,当您单击网址栏时,javascript表示您不在页面内。如果您更改网址栏,然后在其中按下带有“#”符号的“ ENTER”键,那么您将再次进入该页面,而无需使用鼠标光标手动单击该页面,因此来自javascript的键盘事件命令(document.onkeypress)将能够检查是否已进入并激活了JavaScript以进行重定向。您可以使用window.onfocus检查用户是否在页面中,并通过window.onblur检查用户是否不在页面中。

是的,有可能。

;)


这是我在用户使用#符号编辑网址栏时更改页面的一种优雅方式。
马塞洛
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.