在浏览器中更改URL而不使用JavaScript加载新页面


297

我将如何执行一个JavaScript动作,该动作可能会对当前页面产生一些影响,但同时也会更改浏览器中的URL,因此,如果用户点击重新加载或添加书签,则会使用新的URL?

如果“后退”按钮将重新加载原始URL,那也很好。

我正在尝试在URL中记录JavaScript状态。


1
太好了 当然,它将限于同域修改。但是,由于页面重载是许多应用程序的“最后手段”,因此某些客户端对路径的控制(而不仅仅是散列)是合乎逻辑的步骤。
哈波

1
“很好的”使用pushStatefor(i=1;i<50;i++){var txt="..................................................";txt=txt.slice(0,i)+"HTML5"+txt.slice(i,txt.length);history.pushState({}, "html5", txt);}
德里克·朕会功夫2012年

例如在操作这种效果:dujour.com

2
这种效果的示例:facebook.com(在灯箱中打开图像时)

这是一个很好的问题。但是,令人遗憾的情况是,如果今天以这种方式提出这个问题,那么它就会被否决并跳入“这不是让人们为您编写所有代码的站点”。
2014年

Answers:


118

对于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>

和href:

<a href="#" id='click'>Click to change url to bar.html</a>

如果要更改URL而不在后退按钮列表中添加条目,请history.replaceState改用。


您是对的,上次我尝试使用Chrome。我刚才在Ubuntu上尝试使用Firefox 3.6,但没有成功。我想我们必须等到FF完全支持HTML5时
clu3 2010年

15
示例代码是从developer.mozilla.org/en/DOM/Manipulating_the_browser_history中剪切并粘贴的。在这种情况下,实际上困扰着解释foo和bar的含义。
mikemaccana '02

2
foo和bar没有任何意义,它是一个任意定义的状态对象,您可以稍后再取回。
Paul Dixon

3
@Paul:是的,上面的文章提供了该信息。
mikemaccana '02

2
在发布此评论时,它适用于Firefox Chrome和Safari。在ipad或iphone上没有手机浏览器的运气:(
Sid

187

如果你想让它在不支持的浏览器的工作history.pushStatehistory.popState还没有,“老字号”的方法是设置片段标识符,这将不会导致页面重新加载。

基本思想是将window.location.hash属性设置为包含所需状态信息的值,然后使用window.onhashchange事件,或者对于不支持的旧版浏览器onhashchange(IE <8,Firefox <3.6),定期检查查看哈希是否已更改(setInterval例如使用)并更新页面。您还需要检查页面加载时的哈希值以设置初始内容。

如果您使用的是jQuery,则有一个hashchange插件,它将使用浏览器支持的任何一种方法。我确定还有其他库的插件。

要注意的一件事是与页面上的ID冲突,因为浏览器将滚动到具有匹配ID的任何元素。


2
搜索引擎是否不忽略这些内部链接(哈希)?在我的场景中,我也希望蜘蛛也能使用这些链接。
德鲁·诺阿克斯

3
据我所知,@ Drew无法让搜索引擎将页面的一部分视为单独的结果。
马修·克鲁姆利

8
现在有为了使搜索引擎看到哈希的建议:googlewebmastercentral.blogspot.com/2009/10/...
LKM

5
无需使用setInterval检查事件document.location.hash就可以使用该hashchange事件,因为它已被广泛采用。在此处检查哪些浏览器支持每种标准。我目前的方法是在支持push / popState的浏览器上使用它。在其他情况下,我设置哈希值,并且仅hashchange在支持的浏览器中观看。这使IE <= 7没有历史支持,但具有有用的永久链接。但是谁在乎IE <= 7历史呢?
Irae Carvalho

2
@gabeDel是的,尽管我不认为Google Analytics(分析)会记录哈希,因此它具有相同的URL。更好的方法是手动_trackPageview使用新页面的“真实” URL进行调用。
马修·克鲁姆利

37

window.location.href包含当前URL。您可以阅读它,可以添加到它,也可以替换它,这可能会导致页面重新加载。

听起来,如果您想在URL中记录javascript状态以便可以将其添加为书签,而无需重新加载页面,请在#之后将其附加到当前URL,并通过onload事件触发一段javascript来解析当前查看是否包含保存状态的URL。

如果使用?代替#,您将强制重新加载页面,但是由于您将在加载时解析保存的状态,因此这实际上可能不是问题;这样一来,前进和后退按钮也将正常工作。


2
在URL中记录javascript状态正是我要执行的操作
Steven Noble

21

我强烈怀疑这是不可能的,因为如果存在的话,那将是一个令人难以置信的安全问题。例如,我可以制作一个看起来像银行登录页面的页面,并使地址栏中的URL看起来像真实的银行

也许如果您解释为什么要这样做,那么人们也许可以建议其他方法...

[2011年编辑:自从我在2008年写完这个答案以来,关于HTML5技术的更多信息就曝光了,只要该URL来自同一来源,就可以对其进行修改。]


6
如果非重装更改仅限于路径,查询字符串和片段(即不是权限(域等)),那么问题就不大了。
奥利·桑德斯

2
youtube.com/user/SilkyDKwan#p/u/2/gTfqaGYVfMg是一个可能的示例,请尝试切换视频:)
Spidfire 2010年

正如马修·楚姆利(Matthew Chumley)在接受的答案中指出的那样,您只能更改location.hash(在#号之后的所有内容)。
保罗·迪克森

2
你使用Facebook吗?Facebook使用更改URL 而无需重新加载history.pushState()
德里克·朕会功夫2012年

保罗·迪克森(Paul Dixon),您应该注意到Facebook收件箱,当您单击左侧的名称时,仅URL被更改并且新的聊天被加载到聊天框中,页面未刷新。在WebGL上也有很多网站,它们也做同样的事情
Dheeraj Thedijje 2014年

8

浏览器安全设置可防止人们直接修改显示的URL。您可以想象会导致网络钓鱼的漏洞。

在不更改页面的情况下更改url的唯一可靠方法是使用内部链接或哈希。例如:http : //site.com/page.html变为http://site.com/page.html#item1。此技术通常用于hijax(AJAX +保存历史记录)中。

这样做时,我通常只会使用哈希作为href的动作链接,然后使用jquery添加单击事件,该事件使用请求的哈希来确定和委托动作。

我希望这能使您走上正确的道路。


抱歉,您的答案不正确。是的,您可以更改URL。
Derek朕会功夫2012年

1
是的,您可以使用html5历史记录api,但它不是跨浏览器,尽管您可以使用将回退到哈希网址的poly-fill。
杰斯罗·拉森

8

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标头中使用。

例:

window.history.pushState("object", "Your New Title", "/new-url");

pushState()方法:

pushState()具有三个参数:状态对象,标题(当前被忽略)和(可选)URL。让我们更详细地检查这三个参数:

  1. 状态对象 —状态对象是一个JavaScript对象,与通过创建的新历史记录条目相关联pushState()。每当用户导航到新状态时,都会触发popstate事件,并且该事件的state属性包含历史记录条目的状态对象的副本。

    状态对象可以是任何可以序列化的对象。由于Firefox将状态对象保存到用户的磁盘上,以便用户重新启动浏览器后可以将其还原,因此我们对状态对象的序列化表示施加了640k个字符的大小限制。如果将序列化表示形式大于此值的状态对象传递给pushState(),则该方法将引发异常。如果您需要更多空间,建议您使用sessionStorage和/或localStorage。

  2. title -Firefox当前会忽略此参数,尽管将来可能会使用它。在此处传递空字符串应该可以防止将来对方法的更改。另外,您可以为要移动的州传递简短的标题。

  3. URL-新历史记录条目的URL由此参数指定。请注意,浏览器不会在调用之后尝试加载此URL pushState(),但可能会稍后尝试加载URL,例如,在用户重新启动浏览器之后。新的URL不必是绝对的。如果是相对的,则相对于当前URL进行解析。新网址必须与当前网址具有相同的来源;否则,pushState()将引发异常。该参数是可选的。如果未指定,则将其设置为文档的当前URL。



3

Facebook的图片库通过在URL中使用#哈希来实现此目的。以下是一些示例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

请注意,紧随其后的是新输入网址的井号(#!)。



2

对我history.replaceState()有用的是- 功能如下-

history.replaceState(data,"Title of page"[,'url-of-the-page']);

这不会重新加载页面,您可以在javascript事件中使用它


1

我想知道只要页面中的父路径是相同的,是否还会有可能,只有新的内容附加到它。

因此,假设用户在页面上:http://domain.com/site/page.html 然后浏览器可以让我这样做location.append = new.html ,页面变为:http://domain.com/site/page.htmlnew.html并且浏览器不会对其进行更改。

或者只是允许人们更改get参数,所以让我们开始吧location.get = me=1&page=1

因此原始页面变为http://domain.com/site/page.html?me=1&page=1,并且不会刷新。

#的问题在于,更改哈希后,数据不会被缓存(至少我不这么认为)。因此,就像每次加载新页面一样,而非Ajax页面中的后退和前进按钮能够缓存数据,而无需花费时间重新加载数据。

从我看到的结果来看,雅虎历史记录已经可以一次加载所有数据。它似乎没有执行任何Ajax请求。因此,当使用a div来处理不同的方法超时时,不会为每个历史记录状态存储该数据。


1

我的代码是:

//change address bar
function setLocation(curLoc){
    try {
        history.pushState(null, null, curLoc);
        return false;
    } catch(e) {}
        location.hash = '#' + curLoc;
}

和动作:

setLocation('http://example.com/your-url-here');

和例子

$(document).ready(function(){
    $('nav li a').on('click', function(){
        if($(this).hasClass('active')) {

        } else {
            setLocation($(this).attr('href'));
        }
            return false;
    });
});

就这样 :)


1

我提出的一个更简单的答案,

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

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


0

我在以下方面取得了成功:

location.hash="myValue";

它只是添加#myValue到当前URL。如果需要在“加载”页面上触发事件,则可以使用该事件location.hash来检查相关值。只需记住#location.hash例如返回的值中删除

var articleId = window.location.hash.replace("#","");
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.