使用JavaScript在不加载新页面的情况下更改浏览器中的URL

304

如何编写一个JavaScript动作,既可以在当前页面上产生一些效果,又可以更改浏览器中的URL,以便用户在单击刷新或添加书签时使用新的URL?

如果返回上一页,最好能够重新加载原始URL。

我试图在URL中记录JavaScript状态。


1
这将非常好。当然,它将仅限于同域修改。但是,现在许多应用程序的页面重新加载已成为一种“最后手段”,因此对路径(而不仅仅是哈希)进行一些客户端控制是一个合乎逻辑的步骤。 - harpo
2
一个“有点”好的pushStateз”Ёжі•пјљfor(i=1;i<50;i++){var txt="..................................................";txt=txt.slice(0,i)+"HTML5"+txt.slice(i,txt.length);history.pushState({}, "html5", txt);} - Derek 朕會功夫
这个效果在实际中的例子:http://www.dujour.com/ - Ben
2
这种效果的例子:facebook.com(在灯箱中打开图像时) - user659025
这是一个不错的问题。然而,情况有点令人沮丧,因为如果今天以这种方式提出这个问题,它很可能会被投票下降并受到批评:“这不是那种让别人为你编写所有代码的网站”。 - dewd
14个回答

187
如果你想让它在不支持 history.pushStatehistory.popState 的浏览器中工作,那么“旧”方法是设置片段标识符,这不会导致页面重新加载。
基本思路是将 window.location.hash 属性设置为包含所需状态信息的值,然后使用 window.onhashchange 事件,或者对于不支持 onhashchange 的旧浏览器(IE < 8、Firefox < 3.6),定期检查哈希是否已更改(例如使用 setInterval),并更新页面。还需要在页面加载时检查哈希值以设置初始内容。
如果使用 jQuery,则有一个hashchange 插件,它将使用浏览器支持的任何方法。我相信其他库也有插件可用。
要注意的一件事是与页面上的 ID 冲突,因为浏览器将滚动到具有匹配 ID 的任何元素位置。

2
搜索引擎会忽略这些内部链接(哈希)吗?在我的场景中,我希望蜘蛛也能捕捉到这些链接。 - Drew Noakes
3
据我所知,搜索引擎没有办法将页面的一部分作为单独的搜索结果处理。 - Matthew Crumley
8
现在有一个提议,让搜索引擎能够看到哈希值:http://googlewebmastercentral.blogspot.com/2009/10/proposal-for-making-ajax-crawlable.html - LKM
5
不使用setInterval来检查document.location.hash,可以使用更受欢迎的hashchange事件。在此处检查各个浏览器支持的标准。我目前的做法是在支持它的浏览器上使用push/popState。对于其他浏览器,我设置哈希并仅在支持该功能的浏览器中监视hashchange。这将使IE<=7无法使用历史记录,但可以使用有用的永久链接。但是,谁会在意IE<=7的历史记录呢? - Irae Carvalho
2
@gabeDel 是的,虽然我不认为Analytics会记录哈希值,所以它将具有相同的URL。更好的方法是手动调用_trackPageview并使用新页面的“真实”URL。 - Matthew Crumley
显示剩余2条评论

124

使用 HTML 5,可以使用 history.pushState 函数。例如:

<script type="text/javascript">
var stateObj = { foo: "bar" };
function change_my_url()
{
   history.pushState(stateObj, "page 2", "bar.html");
}
var link = document.getElementById('click');
link.addEventListener('click', change_my_url, false);
</script>

和 a href:

<a href="#" id='click'>Click to change url to bar.html</a>
如果你想要改变URL但不想在后退按钮列表中增加一个条目,可以使用history.replaceState代替。

你说得对,上次我是在Chrome上尝试的。我刚刚在我的Ubuntu上尝试了Firefox 3.6,但它没有起作用。我想我们必须等到HTML5在FF中得到完全支持。 - clu3
16
示例代码从https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history中复制并粘贴。这里其实很麻烦地解释了foo和bar在这种情况下的含义。 - mikemaccana
2
foo和bar并没有任何意义,它们只是一个任意定义的状态对象,稍后可以获取回来。 - Paul Dixon
3
@Paul:是的,上面的文章提供了那些信息。 - mikemaccana
2
截至发表此评论,它在Firefox、Chrome和Safari上运行良好。但是,在iPad或iPhone的移动Safari上没有成功:( - Sid
显示剩余2条评论

37

window.location.href包含当前URL。您可以从中读取,可以添加内容,也可以替换它,但这可能导致页面重新加载。

如果您希望在URL中记录JavaScript状态以便将其添加到书签中,而无需重新加载页面,则可以在#后将其附加到当前URL,并让一个由onload事件触发的JavaScript代码段解析当前URL以查看其是否包含保存的状态。

如果使用? 而非#,则会强制重新加载页面,但由于您将在加载时解析已保存的状态,因此实际上可能并非问题;此外,这也将使前进和后退按钮正常工作。


2
记录 JavaScript 状态在 URL 中正是我想要做的。 - Steven Noble

22
我强烈怀疑这是不可能的,因为如果可以这样做,那将是一个令人难以置信的安全问题。例如,我可以制作一个看起来像银行登录页面的页面,并使地址栏中的URL看起来“就像真正的银行”!
也许如果你解释一下为什么想这样做,人们可能会建议替代方法...
[2011年编辑:自2008年写下这个答案以来,有关HTML5技术的更多信息已经浮出水面,只要来自相同来源,就允许修改URL]

6
如果不重新加载页面时仅限于路径、查询字符串和片段(即不包括权限(域名等)),那么这并不是一个大问题。 - Ollie Saunders
2
http://www.youtube.com/user/SilkyDKwan#p/u/2/gTfqaGYVfMg 是一个例子,尝试切换视频 :) - Spidfire
正如Matthew Chumley在被接受的答案中所指出的那样,您只能更改location.hash(#后面的所有内容)。 - Paul Dixon
3
你使用Facebook吗?Facebook在不重新加载页面的情况下使用history.pushState()来更改URL地址。 - Derek 朕會功夫
Paul Dixon,你应该注意Facebook的收件箱,在左侧点击名称时,只有URL会更改,并且新的聊天会加载到聊天框中,页面不会刷新。此外,还有许多使用WebGL的网站也是如此。 - Dheeraj Thedijje

10

jQuery有一个非常好的插件,可以改变浏览器的URL,叫做jQuery-pusher

JavaScript pushState和jQuery可以一起使用,例如:

history.pushState(null, null, $(this).attr('href'));

示例:

$('a').click(function (event) {

  // Prevent default click action
  event.preventDefault();     

  // Detect if pushState is available
  if(history.pushState) {
    history.pushState(null, null, $(this).attr('href'));
  }
  return false;
});
只使用 JavaScript 的 history.pushState() 方法可以改变引用页,即在更改状态后创建的 XMLHttpRequest 对象中使用的 HTTP 标头所使用的引用页。pushState() 方法有三个参数:状态对象、标题和 URL(可选)。状态对象是一个与 pushState() 创建的新历史记录条目相关联的 JavaScript 对象。标题当前被忽略,URL 是新历史记录条目的 URL。这个方法不会尝试加载 URL。如果没有指定 URL,则将其设置为文档的当前 URL。新 URL 不需要是绝对的;如果它是相对的,则相对于当前 URL 解析它。新 URL 必须与当前 URL 同源;否则,pushState() 将抛出一个异常。

8
浏览器安全设置防止人们直接修改显示的URL。你可以想象这会引起的网络钓鱼漏洞。
只有使用内部链接或哈希的可靠方式才能在不改变页面的情况下更改URL。例如:http://site.com/page.html 变成 http://site.com/page.html#item1。这种技术通常用于 hijax(AJAX + 保留历史记录)。
在执行此操作时,我经常使用带有哈希作为href的链接,然后使用jquery添加单击事件来确定并委托操作所请求的哈希。
希望这能让您走上正确的道路。

抱歉,但您的答案不正确。是的,您可以更改URL。 - Derek 朕會功夫
1
可以使用HTML5历史API,但它不是跨浏览器兼容的,不过可以使用poly-fill来回退到哈希URL。 - Jethro Larson

4

3
Facebook的相册使用URL中的#hash实现此功能。以下是一些示例URL:
在单击“下一个”之前:
/photo.php?fbid=496429237507&set=a.218088072507.133423.681812507&pid=5887027&id=681812507

点击“下一步”后:
/photo.php?fbid=496429237507&set=a.218088072507.133423.681812507&pid=5887027&id=681812507#!/photo.php?fbid=496435457507&set=a.218088072507.133423.681812507&pid=5887085&id=681812507

请注意哈希-叹号(#!)后面紧跟着新URL的格式。

3

A more simple answer i present,

window.history.pushState(null, null, "/abc")

这将在浏览器URL中的域名后添加/abc。只需复制此代码并粘贴到浏览器控制台中,即可看到URL更改为"https://stackoverflow.com/abc"。


2

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