在不重新加载页面或使用哈希值的情况下更新地址栏中的新URL

739

我似乎梦到了Chrome(开发频道)通过JavaScript实现更新地址栏的方法(路径,而非域名)而不重新加载页面,但我找不到我认为我读过的文章。

我是疯了还是确实有这种方法(在Chrome中)?

顺便说一下,我不是在谈论window.location.hash等。 如果上述方法存在,则此问题的答案将不正确。


3
当这个问题最初在2009年被提出时,它是不可能的。 - David Murdoch
8
当然不是。但现在,问题要求相同的内容。可惜的是另一个问题有一个已过时的答案被你接受了(我注意到了)...你知道吗?让我们反向关闭另一个问题,没有人说“原始”的必须是较旧的那个,事实上已经有先例了。 - Tobias Kienzler
@tobiaskienzler,另一个问题没有过时的被接受答案。 - David Murdoch
好的,不过更加复杂。不过,在我看来这两个问题似乎非常相似,但也许我漏掉了一些细微差别…… - Tobias Kienzler
3
这是一个六年前的问题,你为什么还要费心去关注它呢?只需享受这个精彩的答案,并将其应用于你的应用程序中。在过去的六年中,成千上万的SO用户认为这是一个惊人的问题,请将其保留原样。 - Imam Assidiqqi
4个回答

985

3
啊,这个功能已经在 WebKit 中实现了,几个月前就发布了 https://bugs.webkit.org/show_bug.cgi?id=36152。不错的发现! - oldestlivingboy
IE9及以下版本怎么办?有类似的解决方案吗? - shubniggurath
15
小提示:这些函数还可以使用相对路径(例如 ../new-url../../new-url)。至少在 Chrome 中,它们似乎会按照你的期望进行操作。 - Mahn
6
我想补充一点,window.replaceState 更容易设置并且通常更受欢迎,例如当您希望在用户更改下拉菜单或搜索字段的值后更新 URL 时。如果您想使用 pushState,则还需要正确支持 onpopstate 事件。 - Kos
1
@fwzard statestate 对象是一个 JavaScript 对象,它与由 pushState() 创建的新历史记录条目相关联。每当用户导航到新的 state 时,就会触发 popstate 事件,并且事件的 state 属性包含历史记录条目的 state 对象的副本。state 对象可以是任何可序列化的东西。因此,它实际上不仅仅是 "object or string"。文档:https://developer.mozilla.org/en-US/docs/Web/API/History/pushState - David Murdoch
显示剩余3条评论

198

只更改井号后面的内容 - 旧版浏览器

document.location.hash = 'lookAtMeNow';

更改完整的URL。Chrome,Firefox,IE10+

history.pushState('data to be passed', 'Title of the page', '/test');

上述操作会添加一个新的历史记录,因此您可以按“返回”按钮返回到先前的状态。要在不添加新条目到历史记录的情况下直接更改URL,请使用

history.replaceState('data to be passed', 'Title of the page', '/test');

现在尝试在控制台中运行这些命令!


20
“replaceState”正是我所需要的,感谢您对原始回复的扩展说明。 - Choylton B. Higginbottom
1
域名和协议必须与原始网址相同!这可以防止一些钓鱼网站更改地址栏URL。 - Rick
3
不应将绝对URL传递给此函数。如果这样做,您很可能需要从当前方案、主机和端口动态构建它 - 这需要很多工作,而您只需将其设置为相对URL(“foo.html”甚至是“/foo.html”),并让浏览器处理即可。 - DimeCadmium
1
@DimeCadmium 很好的简化。已更新。 - Pawel
history.replaceState 在 Firefox 66.0b1 中添加到历史记录。 - azzamsa
@azzamsa可能是一个 bug。在最近的版本中已经没有发生了。 - Pawel

37

更新David的回答,以便甚至检测不支持pushstate的浏览器:

if (history.pushState) {
  window.history.pushState(stateObj, "title", "url");
} else {
  window.history.replaceState(stateObj, "title**", 'url');
  // ** It seems that current browsers other than Safari don't support pushState
  // title attribute. We can achieve the same thing by setting it in JS.
  document.title = "Title";
}

stateObj

状态对象是一个与传递给 replaceState 方法的历史记录条目相关联的 JavaScript 对象。状态对象可以为 null。

title

大多数浏览器当前忽略此参数,尽管它们将来可能会使用它。在这里传递空字符串应该对方法的未来更改是安全的。或者,您可以传递一个短标题来表示状态。

url 可选的

历史记录条目的 URL。新 URL 必须与当前 URL 相同; 否则,replaceState 将抛出异常。


25
document.location.href重新加载页面。 - paullb
1
我在caniuse网站上看到了pushstatereplacestate的兼容性,它们都是相同的,不支持旧浏览器。 - syahid246

18
var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?foo=bar';
window.history.pushState({path:newurl},'',newurl);

11
虽然这段代码片段可能解决了问题,但是包括一些解释会真正有助于提高你的文章质量。请记住,你正在回答未来读者的问题,这些人可能不知道你提出代码建议的原因。 - Maximouse
@MaxiMouse,谢谢你的建议,我会记在心里的。 - Kevin Mendez
4
建议修改:const url = new URL(window.location); url.searchParams.set('foo', 'bar'); window.history.pushState({}, '', url); - user3579536

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