如何控制浏览器的历史记录

上次一位网友在我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),然后在检测到状态改变时调用相应的方法还原页面内容。限于篇幅,这一部分代码就不贴出来了。完整的实例在这里

本文链接:参与评论 »

--EOF--

提醒:本文最后更新于 3013 天前,文中所描述的信息可能已发生改变,请谨慎使用。

Comments