详细内容参看 : http://codecampo.com/topics/84
CodeCampo 是一个小型开发者社区,其代码开源托管于 Github,作者 @chloerei,订阅 @codecampo。
本人做了归纳与调整。
一、有两个问题需要克服
1. Javascript 有一个函数可以改变当前 URL 路径,并载入页面。
window.location = '/'
而如果只改变 URL 的 # 号后面部分,不会导致浏览器重新载入网页。
window.location = '#here' //不会导致页面刷新
2. 浏览器不懂得记录 Ajax 调用的状态。
3. 从非 Ajax 页面返回到 Ajax 页面。处理所有的细节的话,这问题比较棘手存。
采访的方法,让其不存在此情况 : 采用若打开非ajax页面,target="_blank"
二、目标
理想中应该让 Ajax 调用达到这样的状态:
如果 Ajax 调用后的页面逻辑上已经跟之前不是同一个页面,那么 URL 应该随之改变。
前提同上,那么在新页面点击浏览器的后退按钮,应该回到 Ajax 调用前的页面。
三、方案
1. 只改变 URL Hash 的单页面应用 , 对主流浏览器的支持程度很高。
现在的 Twitter,Google,Facebook 的 URL 地址充斥着 #号或者 #! 号。例如一个新版 Twitter 地址是这样的
https://twitter.com/#!/chloerei
其原理:#号后面的改变不会导致页面加载
步骤:
step1: 有关 Ajax 调用的链接全部用 #path 作为链接目标
step2: 设置 onhashchange 事件 (窗口 window 对象的 hash 值(# 号后面部分)发生变化时,会调用 onhashchange 事件。)
在此事件里面,调用ajax方法。如:
window.onhashchange = function(){ ajax方法 }
此方案的副作用 :
把路径写在了 Hash 里面破坏了 URL 原先的含义。
2. 基于 history.pushState API 只支持对HTML5 友好的浏览器
步骤:
step1: 在发送 ajax 请求之前把目标地址推进浏览器的历史记录. (HTML5 新增了 history.pushState 方法,用以向浏览器添加历史记录,但是不触发页面载入)
if (history && history.pushState) {
history.pushState(null, document.title, this.href);
}
step2: 处理后退按钮. 浏览器后退的时候会触发 onpopstate 事件,所以要给这个事件挂上处理方法。
if (history && history.pushState) {
$(window).bind("popstate", function() {
$.getScript(location.href);
});
}
step3: 从非 Ajax 页面返回到 Ajax 页面 (也可以不需要step3,采用若打开非ajax页面,target="_blank")
这时候要做两个处理:
1)要求 Ajax 相关页面不缓存 (缺点:牵扯到性能)
2)处理 popstate 的方法增加一个标志位,第一次载入页面的时候不要调用后面的逻辑。
if (history && history.pushState) {
var loaded = false;
$(window).bind("popstate", function() {
if (!loaded) {
loaded = true;
} else {
$.getScript(location.href);
}
});
}
3. 综合以上两种方案 :
若浏览器有支持history.pushState,则采用方案2 ,否则采用方案1 。 代码实现如下
step1: 在发送 ajax 请求之前 . 设置两种不同写法的url
if (history && history.pushState){
history.pushState(null, document.title, this.href);
}else{ // 不支持 history.pushState
// #path 作为链接目标
window.location = "#!path";
}
step2: 处理回退按钮
if (history && history.pushState){
var loaded = false;
$(window).bind("popstate", function() {
if (!loaded) {
loaded = true;
} else {
$.getScript(location.href);
}
});
}else { // 不支持 history.pushState
window.onhashchange = function(){ ajax方法 }
}