上次一位网友在我blog留言问到如何修正Ajax后退失效,这是在开发Ajax应用时很常见的需求。这篇文章就简单的介绍一下怎么解决这个问题。
首先我们要清楚后退按钮会失效的原因:使用Ajax时,页面通过XMLHttpRequest来更新内容,并没有Redirect,所以浏览器不会出现前进后退。这也是Ajax刚出来时遭到很多人批判的一个原因,其中细节可以参考这两篇文章《Ajax: 99% Bad》、《AJAX的七宗罪》。这个问题其实跟Ajax无关,不过Ajax的出现使得一个页面实现无刷新更新更容易,这个时候人们开始意识到,一个页面发生巨大改变而不能后退是一件很痛苦的事情。
要解决这个问题,就要控制浏览器的history,在页面发生改变时往浏览器历史里插入一条记录。但是出于安全的目的,JS是不能直接操作history的。我们必须采用其他方法:IE中,在页面中插入一个隐藏的iframe,通过改变iframe的location或者DOM,都可以在主窗口的history中产生新记录,详细研究可以参考这篇文章;在其他浏览器(Firefox、Opera、Safari)中没有这么复杂,只需改变url就可以产生一条新的history记录,当然url不能乱改,要不页面就跳转走了,通常我们改变的是location.hash,也就是url“#”以后的部分。下面是具体实现:
首先在页面中放一个隐藏的iframe:
<
style
type
=
"text/css"
title
=
"default"
media
=
"screen"
>
#history_iframe{position:absolute;top:0; left:0;width:1px; height:1px;visibility:hidden}
</
style
>
<
iframe
id
=
"history_iframe"
src
=
"blank.html"
></
iframe
>
|
blank.html的内容也很简单,放了一个div来存当前的hash:
<
html
>
<
head
><
title
>hack iframe</
title
></
head
>
<
body
><
div
id
=
"state"
></
div
></
body
>
</
html
>
|
对不同浏览器采用不同方法控制history:
var
isIE =
typeof
(window.opera)!=
"object"
&&window.navigator.userAgent.indexOf(
"MSIE"
)>0;
var
$ =
function
(s){
return
document.getElementById(s)};
function
update_status(str){
if
(isIE){
try
{
var
doc = $(
"history_iframe"
).contentWindow.document;
doc.open();
doc.write(
'<html><body><div id="state">'
+str+
'</div></body></html>'
);
doc.close();
}
catch
(e){}
}
location.hash = str;
};
|
可以测试一下了:
<
button
onclick
=
"update_status('test1')"
>test1</
button
>
<
button
onclick
=
"update_status('test2')"
>test2</
button
>
<
button
onclick
=
"update_status('test3')"
>test3</
button
>
|
上面就是控制浏览器history的基本原理,通过点击三个按钮,会往浏览器写入三条历史记录,这样尽管页面依旧没有刷新,但是浏览器的前进后退却能开始工作了。剩下的工作很简单:利用一个定时器不停的检测状态是否发生变化(IE检测iframe里state的innerText;其他浏览器检测location.hash),然后在检测到状态改变时调用相应的方法还原页面内容。限于篇幅,这一部分代码就不贴出来了。完整的实例在这里。