antony--异域空间
性格左右命运,气度影响格局!

以前在测试自己写的webim时发现firefox有一个很人性化的特性:在页面上跟别人聊天的时候如果不小心点到了本页打开的链接,只要点一下 Firefox的后退按钮,就会退后到之前的页面,可以接着聊。也就是说在firefox中点击后退,原来页面的状态会还原,包括JS改变的DOM结构也 会保持。

我们用下面的代码来测试一些常见的浏览器是怎么处理后退的。测试的浏览器有IE8beta2、Firefox3.0.1、Flock1.2.4(Firefox2.0.0.16内核)、Safari3.1(window版)、Opera9.60。

<a href="http://www.baidu.com">百度</a>
<div id="a1"></div>
<script type="text/javascript">
  window.onload = function(){
    alert("load");
    var i = 1;
    setInterval(function(){
      document.getElementById("a1").innerHTML = i++;
    },500);
  };
</script>

测试结果:IE8点后退时会触发之前页面的window.onload事件,计数器回到初始状态重新计数;Opera9.6后退时不会触发前一个页 面的window.onload事件,但定时器停止运行;其它浏览器后退时都不会触发前一个页面的window.onload事件,定时器会接着之前的状 态继续计数。

结论:Firefox、Opera、Safari在这方面都做得比较人性化,完全的保留了页面unload时的状态,估计是直接从内存中读取缓存数 据,所以后退速度相当快;其中Opera9.6会导致计数器停止,可能是个bug。IE在后退时则会回到最初状态,之前JS改变的DOM不复存在。

如果想让非IE浏览器退后时也能触发window.onload事件呢?这篇文章提到了解决方案。其实就是在页面是加入:

window.onunload = function(){};

经测试,此方法可行。对于其中的原理,JK给出了如下解释:

FF/Safari等会努力做得很理想(完完全全的保持上次的unload时的信息),不过,如果他认为用户的代码(典型的是在onunload里)会破坏他的理想计划时,他就退一步,把“后退”当作“后退+reload”。

 

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

见:http://www.qgy18.com/2008/09/howto_control_browser_history/
 

 

 

在Ajax编程时,经常需要从服务端获取数据。通过情况下,我们是直接把要传输的数据放在response正文中,再用responseText或者responseXML来得到内容。最近偶然发现,有时候也可以把数据放在header里,而且一些情况下这样做更有优势。

header是服务器以HTTP协议传送HTML资料到浏览器前所送出的字符串,在php中我们可以这么发送自定义header:

header("author:Jerry Qu");

然后在客户端,正常的创建一个Ajax请求,所不同的地方是callback中获取数据改成:

var a = new Ajax();
a.get("test.php",function(){
    
alert(a.req.getResponseHeader("author"));
});

这样就能取到author的值了。

Javascript中跟response header有关的就两个方法:

getResponseHeader
从响应信息中获取指定的http头
语法
strValue = oXMLHttpRequest.getResponseHeader(bstrHeader);

getAllResponseHeaders
获取响应的所有http头
语法
strValue = oXMLHttpRequest.getAllResponseHeaders();

通过header可以传多少数据呢?我测试了一下,在firefox中如果超过10232个英文字符,客户端就取不到数据了,IE中测试了100W 个字符依然可以,所以基本还是够用的。另外,我也测试过一次发送1000个自定义header,IE和FF中都能正常取到值。如果你想得到http header的更多信息,建议阅读这篇文档

这样做的优点呢?通常如果用Ajax来post数据,服务端返回json格式字符串的情况下,在浏览器中输入request的地址,用户就会看到那 堆奇怪的代码。在页面丢失js时这种现象很常见。但是把返回数据放在header里就不会有这个问题,反正header不会展示出来。正文里可以随意的放 些什么内容,哪怕是放一段自动转向JS也没关系,这样用户体验要稍好一些。

查看本文实例

另见:http://www.w3help.org/zh-cn/causes/BX2004

posted on 2011-01-10 17:41  antony.net  阅读(2155)  评论(1编辑  收藏  举报