利用HTML5新特性让Ajax改变URL,支持前进后退

Author : lovecicy

最近用到了一个HTML5的新特性:hashchange 事件,此事件监听浏览器地址栏URL”#”号后面的内容的变化。因为浏览器的history会记录hash变化,所以可以利用这个API,让Ajax支持浏览器的前进和后退按钮。

但是后来发现了一个更好的方案:使用HTML5的history API。这样,就可以正常修改URL了,而且同样支持浏览器的前进和后退按钮,但必须保证URL是可访问的。

在HTML5之前,history API只有一个length属性,在支持HTML5的浏览器中,会有一个state属性,同时多了两个方法:pushState()和replaceState(),这两个方法配合window.popstate事件一起工作。

当你在A页面上点击一个链接时,触发了一个Ajax请求,请求返回后通过js修改了页面显示。如果这时候返回了主页,再点击浏览器的返回按钮,你想回到被修改了的A页面,但是,你只会回到初始的A页面。这时候,如果在发送Ajax请求前使用history的pushState()方法,就可以把目标地址推送进浏览器的历史记录,于是浏览器的地址栏发生变化而不会重新加载整个页面,等待Ajax返回以后再局部刷新页面,这样,与直接从A页面跳转到B页面效果相同,却避免了相同内容再次加载。

MDN给出的关于如何使用pushState()方法的例子是这样的:

假设在http://mozilla.org/foo.html 中执行下面的JavaScript代码:

var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 2", "bar.html");

这将导致URL变成这样:http://mozilla.org/bar.html ,但浏览器不会去加载http://mozilla.org/bar.html这个页面甚至不会检查这个页面是否存在。

假定现在用户跳转到了http://google.com,然后点击了后退按钮。这时候,地址栏会显示http://mozilla.org/bar.html,并且页面会触发popstate事件,popstate事件包含一个state对象,即stateObj对象的拷贝。页面本身像foo.html,尽管页面的内容可能在popstate事件处理器中被修改了。

如果我们再点击后退按钮,地址栏将变成http://mozilla.org/foo.html,并且会触发另一个popstate事件,这个popstate事件将包含一个空的state对象。同样,文档的内容和前一步相比没有改变,你也可以在popstate事件处理器中修改页面的内容。

pushState()函数接手3个参数:state object,title和URL,pushState()函数会向history栈中压入一个新的history entry。

state object是一个JSON对象,与当前创建的history entry相关。当用户导航到新的state时,会触发popstate事件,此事件的state属性是当前history entry的state属性的一个拷贝。

title属性没有被使用。

URL是一个可选的参数,表示当前history entry的URL,地址栏的URL将会改成此URL,但是浏览器当前不会加载此页面。URL可以使相对地址也可以是绝对地址。

需要注意的是pushState()函数永远不会触发hashchange事件,即使新旧URL只有hash部分由差别。

replaceState()函数与pushState()函数类似,不同的是它替换了当前的history entry而不是新建了一个history entry。

popstate事件仅在同一个document下的history entry切换时被触发。注意,仅仅调用pushState()方法不会触发popstate事件。popstate事件仅在点击浏览器前进/后退按钮或者javascript操作前进/后退(history.back()/history.forward())时触发。

来看看GitHub的大致实现:

$(‘#slider a’).click(function() {
history.pushState({ path: this.path }, ”, this.href)
$.get(this.href, function(data) {
$(‘#slider’).slideTo(data)
})
return false
})

先修改URL地址,再通过Ajax获取内容,在回调函数中实现滑动效果。当点击返回按钮时,URL改变,再触发popstate事件

$(window).bind(‘popstate’, function() {
$(‘#slider’).slideTo(location.pathname)
})

更加详细的讲解,可以看这里(貌似被墙了,需要翻墙):

HTML5,让 Ajax 改变 URL 且支持后退

更多详细信息,可以查看:

Manipulating the browser history

window.onpopstate

 

standard

Have your say