我想使用window.location.hash
或history.pushState
更新URL。
每种方法的差异和优势是什么?
location.hash
法比history.pushState
法具有更好的支撑作用。
pushState
方法的优点是您可以将状态绑定到历史条目。
如果你不需要这个状态对象,我建议使用location.hash
属性,以更好地兼容旧的浏览器。
location.hash = 'new-hash';
console.log(history.state); // null or undefined
history.pushState({extraData: "some state info"}, '', 'new-hash'); //<---
console.log(history.state); // [object Object] = {"extraData": "some state info"}
Pushstate是未来。它之所以更好是因为:
- 看起来更干净了。
- 在重新访问一个深度链接时,你实际上可以显示真实的服务器端数据来支持SEO和Facebook Open Graph(两者都发送蜘蛛来抓取你页面的html)。
- 服务器没有访问哈希标签数据,所以你不会在服务器日志中看到它,所以它有助于分析。
- 它帮助修复哈希标签问题。例如,我重写了Nginx,将访问我的应用程序的用户重定向到相同的https url。它适用于所有浏览器,但Safari会将你重定向到没有哈希的域名(太烦人了)!
- 你实际上可以使用哈希标签来达到目的,深度链接到长页面的各个部分。
- 对于不支持推送状态的浏览器,你可以退回到使用真实的HTTP后端请求,或者退回到使用哈希标签。两者都需要额外的实现,但很容易完成一点工作。
参见Github designer的演讲:http://warpspire.com/talks/responsive/
这是一个相当老的问题(在这个回复的时候已经5年多了),但是很多对现有回复的评论都要求根据"当前"状态进行更新。
事情是这样的:
所有主流浏览器都支持HTML5的pushState。如果你也支持旧的浏览器,history.js提供了一个很好的polyfill,让你可以本地使用pushState,并很容易地退回到旧浏览器的遗留url。但是,现在本机支持pushState并不意味着它一定是要走的路。有一个非常重要的问题在以前的答案中都没有提到,那就是hash url和pushState url不仅在外观上不同,而且在工作方式上也不同。这两者之间的根本区别可能会导致你选择其中一个而不是另一个。
pushState更漂亮、更干净,可以用来在你的网站/应用程序中完全伪造导航。例如,GitHub使用它来替换所有不可见的导航。当您单击他们网站上的任何链接时,javascript用于拦截该点击并将其转换为AJAX请求,该请求在不加载新页面的情况下更新页面内容,同时位置栏中的URL更改以匹配所获取的内容。这就是pushState被用于的目的。
在GitHub的情况下,http://mysite/page1和http://mysite/page2都是有效的url。它们是带有"真实"内容的"真实"链接,最初访问任何一个页面都要通过传统的MVC方法。GitHub在现代浏览器中使用pushState进行导航,但并不需要它-即pushState被用作"功能添加"(在他们看来),当涉及到导航时,会带来更好的用户体验。当您复制浏览器地址栏中的链接时,您正在复制通过javascript形成的链接&pushState,但链接仍然是真实有效的。
然而,如果你从头开始创建一个单页的应用程序,不使用MVC框架,机会是,你实际上只有一个页面,特别是如果你不使用动态后端(即内容都是通过javascript检索,从来没有由服务器生成)。在这种情况下,如果在散列URL上使用pushState,则需要处理浏览器中的URL不是真实URL的情况。我来举例说明。
用户加载单页应用程序:http://mysite/mainpage
在这一点上,浏览器栏包含了真正的链接到你的应用程序,并将带用户到他们目前看到的相同视图:主页面。现在他们点击一个链接,这个链接会把他们带到一个显示某些活动细节的"页面"。此时,您需要更新位置栏,以指示状态的更改。你可以使用一个哈希URL,你的位置栏看起来像http://mysite/mainpage#charts/1或者你使用pushState,把它变成http://mysite/mainpage/charts/1如果你使用pushState,那不是一个真正的链接。通过浏览器的后退/前进按钮导航将工作得很好,用户将从主页到位置栏和应用程序中的详细页面(假设你正确地处理了状态更改),但如果用户将此链接添加为书签或复制并粘贴链接以共享它,则需要额外的服务器端巫术。
你需要将请求重定向到/mainpage/charts/1到/mainpage,然后使用JS解析实际的URL并执行预期的状态更改操作。服务器重定向是绝对需要的。如果没有可编写脚本的http服务器,则无法在AWS或本地磁盘上托管此页面。
现在如果您使用哈希URL,您的用户将看到并与之交互的URL将是http://mysite/mainpage#/charts/1,这是一个有效的,真正的URL。浏览器知道只有一个页面,无论用户是复制和粘贴链接还是添加书签,你只需要在javascript中处理哈希状态,不需要任何服务器端魔法来使事情正常工作。
似乎没有人提到的是pushState和hash链接并不是互斥的。pushState只是一个API,用于操作用户可见的浏览器位置,并在现代浏览器中实现可靠的后退/前进导航。它没有说明你的URL方案应该是什么样子。
在2017年,谷歌和几乎所有其他支持js的机器人都能理解哈希url并很好地遍历它们。谷歌希望你使用#!搜索引擎优化憎恶最大化的目的,但即使你不这样做,你的网站也会很好地导航。
正确的答案是使用最适合你需要的东西。如果你有真实的url并且想要在它们之间进行导航,使用pushState和carry on(对于旧的浏览器可以选择使用polyfill)。但如果你的应用是单页的,不要假装没有(除非你有很好的理由)。使用哈希url使您的工作更轻松,并且不会引入不必要的问题,然后使用pushState来操作这些哈希url,以利用更好的向后/向前支持。
history.pushState
优于location.hash
。但这是HTML5的特性。因此,最好有一个如下所示的回退方法。
if (typeof(window.history.pushState) == 'function') {
window.history.pushState(null, path, path);
} else {
window.location.hash = '#!' + path;
}
我同意其他答案,但这里有一些支持location.hash
:
- 它适用于所有浏览器,包括Internet explorerTM
- 历史。pushState是一个正在开发的标准,API可能会在未来发生变化
- 如果用户在新窗口/选项卡中打开链接,一个散列url确保没有服务器请求需要加载页面(如果设置了正确的缓存头)
- 服务器配置很简单,因为所有服务器都看到的是没有哈希部分的URL
edit: I forgot one
- 与标签,你可以使用真正的链接(
a href
)。因此,您不必设置点击侦听器,这可以提高性能并减少代码大小。
window.location.hash与HTML5历史的优缺点。推送状态在很大程度上取决于您希望页面降级的程度。
在这里,您可能对两种不同场景中的优雅降级感兴趣:第一个是客户端没有启用javascript,或一个自动机器人/爬虫访问您的网站。从SEO的角度来看,这一点尤为重要。如果您的网页/web应用程序使用哈希url,那么通过这些链接提供的内容对这些最终用户是不可用的。如果您只通过哈希url提供部分内容而没有回退,这肯定是一个问题。但是,如果您使用标签链接来修改应用程序状态,这绝对不是问题,因为如果页面降级,应用程序状态根本不会保留意义。
作为一个例子,考虑这样一个场景:在一个选项卡布局小部件的三个选项卡中有一个页面,其中有三个部分的文本。现在有两种可能的情况:在第一种情况中,您将在页面加载期间加载所有内容—选项卡小部件将仅用于隐藏其他部分并显示特定部分。因此,如果在用于构造选项卡控件的链接中使用哈希url,则只使用它们来更改客户端应用程序状态。当javascript关闭/不可用时,用于构建选项卡布局的javascript不会运行,所有内容都立即可用——这是一个合理的优雅的回退。在这种情况下,不同的应用程序状态根本不存在,因此哈希url降级为仅指向html中的锚——这是预期的目的。如果在这种情况下使用html5 pushstate而不是hash-urls,这将是一个坏主意。原因是用户可能会将链接收藏到特定选项卡。因为您的服务器必须接受该url并向用户呈现他所期望的客户端状态。这对于瘦服务器体系结构来说并不好,因为客户端应该负责自己的状态管理。当然,您可以在服务器端忽略这方面,让客户端在页面加载开始时检查url,然后切换到适当的应用程序状态。但这仍然不是一个好主意,因为你的服务器端路由系统关心额外的url片段的开销,它应该忽略,因为它不应该从美学的角度来考虑这个片段。这完全符合设计哈希url时的需求,强烈建议使用它们。如果在这三个部分中,文本是在单击特定选项卡拇指时动态加载的,那么使用哈希url就不是一个好主意。原因是,如果javascript不可用,用户将无法访问链接的内容。这对SEO尤其不利。在这种情况下,如果您在服务器端处理url(在正常情况下会被"劫持"one_answers"ajax化")以使内容可用,那么从最终用户体验和SEO的角度来看,这都是非常好的。
第二种情况是客户端有一个过时的浏览器,不支持html5推送状态。虽然上述观点仍然成立,但我还认为,强迫没有推送状态的用户使用与没有javascript相同的降级级别是不合理的。很多终端用户根本不知道为什么他们收到的是降级版本。
我建议您不要总是遵循使用最新技术的教条动机,并根据您的使用场景决定最佳选择。
目前,所有现代浏览器都支持pushState
。因此pushState
比location.hash
好,但这是HTML5的功能。
所以,location.hash
并没有死,事实上它还会存在很长很长一段时间。
使用它的一个好方法是使用支持pushState
的库,但也优雅地降级为使用location.hash
。
——https://github.com/browserstate/history.js
此外,location.hash
对于跳转到命名锚仍然有用。pushState
将对构建web应用程序提供巨大的帮助。我期待着使用它。
我个人更喜欢pushState,因为它使url看起来更好看,我认为这对用户体验很重要。
如果你想使用pushState,你可以使用history.pushState
和使用history.js polyfill的哈希回退,但不想在旧浏览器的支持下出现问题。
一个非常小的区别,我没有看到任何地方注意到这个线程:
设置window.location.hash
将强制立即滚动跳转到文档中的新哈希元素(至少在我的浏览器中是这样)。如果你想要一个平滑的滚动,但也希望在url栏的哈希值更新/改变,你必须使用window.history.pushState
像这样:
document.getElementById(id).scrollIntoView({ behavior: "smooth" });
window.history.pushState(null, null, "#" + id);