pushState + ajax 实现浏览器无刷新前进后退

如果你制作过网站,那么一定不会对ajax感到陌生,它让我们充分享受到了异步请求所增强的交互体验和更高的执行效率。唯一的遗憾是无法同时修改浏览器的地址栏及历史记录,这就使得我们无法利用浏览器对ajax的请求进行前进后退的操作。

举个简单的例子:假设有一个利用ajax来实现分页效果的页面,当点击第3页的时候,浏览器中就会显示第3页的内容。但此时浏览器地址栏中仍然是第1页的地址,点击浏览器后退按键会发现根本无法回到第1页,如果刷新浏览器,则又会回到第1页。


两种解决方案

  1. 利用 location.hash 来实现

hash 属性是Javascript原生的属性,是一个可读写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)。比如 location.href = "http://blog.chenxu.me/post/#1",那么  location.hash = "#1"。通过设置 hash 可以操作浏览器的历史记录(即前进、后退)。


  1. 利用 history.pushState API

pushState 是 Html5 中引入的新特性,用来修改浏览器的历史记录。通过 pushState 把记录保存到浏览器的历史数据中,然后通过windows.onpopstate事件来响应浏览器的前进、后退操作。下文将详细介绍如何使用该API来实现浏览器的前进与后退。


如何使用pushState

如上所述,history.pushState 可以将一条记录 push 到浏览器历史集合中。调用方式如下:

var url = "http://example.com/page/2";
var state = {url:url, title:"第二页", content:data};
history.pushState(state, "", url);


参 数

pushState 接受3个参数,分别为 state、title、url。

state 参数是一个标准的 javascript 对象,用来传递一些可序列化的状态信息(比如当前页面的地址、title,甚至是整个页面的代码),如 state = {title:"第二页", url:"http://example.com/page/2"};

title 参数目前还没有被各大浏览器支持,所以建议先用空字符串来代替,以免对日后的逻辑造成影响;

url 参数会替换掉当前浏览器地址栏中的地址,但是并不会去加载它,明显的好处是当我们刷新浏览器窗口的时候,浏览器会去加载该URL;


何时使用

当我们完成一次ajax调用后,就应当使用该API将新的记录执行。


响应浏览器的前进与后退

当使用 pushState 向浏览器写入一条新历史记录的时候,会发现地址栏发生了变化,有些童鞋就兴奋的去点击浏览器的后退按钮,结果发现地址栏的地址发生了后退的效果,但是浏览器的内容却丝毫未变。我只想说:“淡定”。


Html5 增加了 window.onpopstate 事件来响应浏览器的这些操作。当点击浏览器上的前进、后退按钮或者使用 javascript 代码 history.go、history.back 都会触发onpopstate事件,并返回 pushState时传入的 state 对象以供调用。我们只要在该事件处理函数中把页面内容复原就OK了。

window.onpopstate = function (evt) {
    var state = evt.state;
    
    //chrome 和 safari 会在第一次加载页面的时候触发该事件,因此要做一些逻辑上的处理以免出现怪异的情况 
    if (state) {		
	$("#container").html(state.content);
    }
}


把初始载入的页面放入历史记录中

在介绍 pushState 的时候说过,当完成一次ajax请求的时候,应该把新的 url 等状态信息保存到历史记录中。而当页面第一次加载的时候,我们其实并没有调用 pushState 来保存过历史记录。这会不会有问题呢?

答案是肯定的,因为历史记录中并没有针对第一页的记录,所以当我们试图从第二页后退到第一页的时候,会发现尽管地址栏发生了变化,但是浏览器内容却一点变化都没有。

解决办法是使用 replaceState


history.replaceState 与 history.pushState 的方法几乎一样,只是 pushState 是往浏览器的历史记录中新建一条,而 replaceState 则是用当前的记录替换掉原来的记录。第一次加载第一页的时候,我们应该使用 replaceState 替换掉当前的历史,从而把我们希望的 state 加入到历史记录中。

if (history.replaceState) {
    history.replaceState({ url: location.href, title:"",content:data }, "", location.href);
}



查看示例

文章索引

[隐 藏]

本站采用知识共享署名 3.0 中国大陆许可协议进行许可。 ©2014 Charley Box | 关于本站 | 浙ICP备13014059号