修改 AJAX 应用程序中的地址栏 URL 以匹配当前状态
Posted
技术标签:
【中文标题】修改 AJAX 应用程序中的地址栏 URL 以匹配当前状态【英文标题】:Modify Address Bar URL in AJAX App to Match Current State 【发布时间】:2010-09-05 07:30:39 【问题描述】:我正在编写一个 AJAX 应用程序,但是当用户在应用程序中移动时,我希望地址栏中的 URL 能够更新,尽管没有重新加载页面。基本上,我希望他们能够在任何时候添加书签,从而返回到当前状态。
人们如何在 AJAX 应用程序中维护 RESTful?
【问题讨论】:
用于维护你的应用程序的状态,但与“RESTful”无关。window.history.pushState(null,'hi','page1?id=32')
接受的答案是 5 年前写的,与此同时,我们得到了 window.history.pushState,就像@Omu 说的那样。 location.hash 带来了很多问题,最好避免它。
我已经编辑了答案以突出 pushState 方法。
【参考方案1】:
执行此操作的方法是在 AJAX 更新导致您希望拥有一个离散 URL 的状态更改时操纵 location.hash
。例如,如果您的页面的 url 是:
http://example.com/
如果客户端函数执行了此代码:
// AJAX code to display the "foo" state goes here.
location.hash = 'foo';
然后,浏览器中显示的 URL 将更新为:
http://example.com/#foo
这允许用户为页面的“foo”状态添加书签,并使用浏览器历史记录在状态之间导航。
使用此机制后,您需要在客户端使用 javascript 解析出 URL 的哈希部分,以创建并显示适当的初始状态,因为片段标识符(# 之后的部分)不是发送到服务器。
Ben Alman's hashchange plugin 如果您使用的是 jQuery,则让后者变得轻而易举。
【讨论】:
看来你是对的。这是唯一的方法。这似乎是对您建议的一个很好的详细解释:ajaxpatterns.org/Unique_URLs> @buymeasoda 感谢您的编辑;我不确定我在写那部分时在想什么。 哇,这个答案很有帮助。尽管 URL 示例有点令人困惑,但 SO 可能会自动将链接替换为标题。用 example.com 和 example.com/#foo 之类的内容替换它们怎么样,这样我们就可以以纯文本形式查看整个 url。 @Pascal 你可以,但只能在支持 html5 的 pushState 的浏览器中。这里有很好的信息:diveintohtml5.info/history.html 我最终成为了 history.js 的忠实粉丝,以涵盖浏览器兼容性的基础github.com/andreasbernhard/history.js【参考方案2】:查看诸如 book.cakephp.org 之类的网站。此站点更改 URL 而不使用哈希并使用 AJAX。我不确定它是如何做到的,但我一直在试图弄清楚。如果有人知道,请告诉我。
在查看某个项目中的导航时也可以访问 github.com。
【讨论】:
大约一周前,我在 GitHub 上注意到了这一点。他们到底是怎么做到的?必须回去检查。 他们似乎在使用 javascript 函数 pushState()。这会增加浏览器的历史记录。了解更多;这很有趣也很酷。 谢谢,这正是我想要的。我想知道github是如何做到的。起初我以为它必须重新加载,但只有 AJAX 请求。在 Opera 中,它确实重新加载了页面。 fb 在浏览不同组的页面时使用了类似的技术。您有一个左侧导航列,其中提到了不同的组。当您单击特定组名称时,url 会发生变化,并且只有主内容窗格的内容会随着 url 发生变化(无哈希)。因此,当用户重新加载页面时,他们不会重定向到主页,而是重定向到组的页面。【参考方案3】:在使用 Ajax 时,作者不太可能想要重新加载或重定向他的访问者。
但是为什么不使用 HTML5 的pushState
/replaceState
呢?
您可以随意修改地址栏。 Get natural looking urls, with AJAX.
查看我最新项目的代码: http://iesus.se/
【讨论】:
【参考方案4】:这与凯文所说的相似。您可以将您的客户端状态作为一些 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 控制台中尝试过)【参考方案5】:SWFAddress 在 Flash 和 Javascript 项目中工作,让您可以创建可收藏的 URL(使用上面提到的哈希方法)并为您提供后退按钮支持。
http://www.asual.com/swfaddress/
【讨论】:
【参考方案6】:window.location.hash 方法是首选的做事方式。有关如何执行此操作的说明, Ajax Patterns - Unique URLs.
YUI 以模块的形式实现了这种模式,其中包括 IE 特定的解决方法,用于使后退按钮与使用哈希重写地址一起工作。 YUI Browser History Manager.
其他框架也有类似的实现。重要的一点是,如果您希望历史记录与重写地址一起工作,不同的浏览器需要不同的处理方式。 (这在第一篇链接文章中有详细说明。)
IE 需要基于 iframe 的 hack,Firefox 将使用相同的方法生成双重历史记录。
【讨论】:
【参考方案7】:如果 OP 或其他人仍在寻找修改浏览器历史记录以启用状态的方法,则按照 IESUS 的建议,使用 pushState 和 replaceState 是现在的“正确”方法。与 location.hash 相比,它的主要优势似乎在于它创建了实际的 URL,而不仅仅是哈希。如果保存了使用哈希的浏览器历史记录,然后在禁用 JavaScript 的情况下重新访问,则应用程序将无法运行,因为哈希不会发送到服务器。但是,如果已使用 pushState,则整个路由将被发送到服务器,然后您可以构建该服务器以适当地响应路由。我看到了一个例子,在服务器端和客户端都使用了相同的胡子模板。如果客户端启用了 JavaScript,他会通过避免往返服务器而获得快速响应,但如果没有 JavaScript,应用程序将完全正常工作。因此,应用程序可以在没有 JavaScript 的情况下正常降级。
另外,我相信有一些框架,名称类似于 history.js。对于支持 HTML5 的浏览器,它使用 pushState,但如果浏览器不支持它,它会自动回退到使用哈希。
【讨论】:
【参考方案8】:检查用户是否在页面中,当您单击 URL 栏时,JavaScript 会说您不在页面中。 如果您更改 URL 栏并在其中按带有符号“#”的“ENTER”,然后您再次进入该页面,而无需使用鼠标光标手动单击该页面,那么来自 JavaScript 的键盘事件命令 (document.onkeypress) 将能够检查它是否进入并激活 JavaScript 以进行重定向。 您可以使用 window.onfocus 检查用户是否在页面中,并使用 window.onblur 检查他是否在页面外。
是的,有可能。
;)
【讨论】:
当用户使用 # 符号编辑 url 栏时,这是我看到的优雅更改页面的方式。以上是关于修改 AJAX 应用程序中的地址栏 URL 以匹配当前状态的主要内容,如果未能解决你的问题,请参考以下文章