ajax浏览器后退功能实现

FeatureChromeFirefoxIEOperaSafari
support5.03.6 (1.9.2)8.010.65.0

由于chrome引发的版本号竞赛,现在chrome20+,firefox16+,opera12了,因此对于标准浏览器我们不必顾虑支持问题,精力集中在IE678上。IE8在兼容模式下虽然有此事件,但不生效。这个检测也很简单。至于如何产生历史,这也很简单,直接在隐藏iframe中调用document.write方法就行。hash的变化,是通过定时器检测,不十分及时,但对于坚持IE67的操蛋用户就不应该给好脸色他们看!

如何观察hash的变化呢?这其实有三个hash值,一个是主窗口之前的hash值(last_hash),主窗口当前的hash值,一个是iframe中的hash值(history_hash),我们可以比较前两者得知hashchange,但当用户点击后退按钮后,AJAX引发的效果是作用于iframe中的,因此这时是比较last_hash与history_hash。发生变化后,我们再手动修改主窗口的hash,触发onhashchange回调。

最后提一提hash值的提取,这里存在两个兼容性问题:

IE6直接用location.hash取hash,可能会取少一部分内容:

比如 http://www.cnblogs.com/rubylouvre#stream/xxxxx?lang=zh_c

ie6 => location.hash = #stream/xxxxx

其他浏览器 => location.hash = #stream/xxxxx?lang=zh_c

firefox 会自作多情对hash进行decodeURIComponent

比如 http://www.cnblogs.com/rubylouvre/#!/home/q={%22thedate%22:%2220121010~20121010%22}

firefox 15 => #!/home/q={"thedate":"20121010~20121010"}

其他浏览器 => #!/home/q={%22thedate%22:%2220121010~20121010%22}

下面是mass Framework中的实现

define( "hashchange" , [ "$event" ], function (){
     $.log( "已加载hashchange模块 by 司徒正美" )
 
     var  hashchange = 'hashchange' ,  DOC = document,  documentMode = DOC.documentMode,
     supportHashChange = ( 'on'  + hashchange in  window) && ( documentMode === void 0 || documentMode > 7 );
    
     $.fn[ hashchange ] = function (callback){
         return  callback?  this .bind(hashchange, callback ) : this .fire( hashchange);
     }
     $.fn[ hashchange ].delay = 50;
     if (!supportHashChange){
         $.log( "不支持hashchange,使用iframe加定时器模拟" )
         var  iframe, timeoutID, html = '<!doctype html><html><body>#{0}</body></html>'
         
         if ( $.fn[ hashchange ].domain){
             html = html.replace( "<body>" , "<script>document.domain =" +
                 $.fn[ hashchange ].domain + "</script><body>"  )
         }
 
         function  getHash ( url) { //用于取得当前窗口或iframe窗口的hash值
             url = url || DOC.URL
             return  '#'  + url.replace( /^[^#]*#?(.*)$/, '$1'  );
         }
         function  getHistory(){
             return  getHash(iframe.location);
         }
         function  setHistory(hash, history_hash){
             var  doc = iframe.document;
             if  (  hash !== history_hash ) { //只有当新hash不等于iframe中的hash才重写
                 //用于产生历史
                     doc.open();
                     doc.write($.format(html, hash));
                     doc.close();
             }
         }
         var  last_hash = getHash(), history_hash, hash = "#" ;
         $.eventAdapter[ hashchange ] = {
             setup: function (desc) {
                 $.require( "ready" , function (){
                     if  (!iframe) {
                         //创建一个隐藏的iframe,使用这博文提供的技术 http://www.paciellogroup.com/blog/?p=604.
                         //iframe是直接加载父页面,为了防止死循环,在DOM树未建完之前就擦入新的内容
                         var  el = $( '<iframe tabindex="-1" style="display:none" widht=0 height=0 title="empty" />' ).appendTo( document.body )[0], fn
                         iframe = el.contentWindow
                         $.bind(el, "load" ,fn = function (){
                             $.unbind(el, "load" , fn)
                             var  doc = iframe.document
                             doc.open();
                             doc.write($.format(html, hash))
                             doc.close();
                             timeoutID = setInterval(poll,  $.fn[ hashchange ].delay)
                         });
                         function  poll() {
                             var  hash = getHash(), //取得主窗口中的hash
                             history_hash = iframe.document.body.innerText; //取得现在iframe中的hash
                             if (hash !== last_hash){ //如果是主窗口的hash发生变化
                                 setHistory(last_hash = hash, history_hash )
                                 $(desc.currentTarget).fire(hashchange)
                             } else  if (history_hash !== last_hash){ //如果按下回退键,
                                 location.href = location.href.replace( / #.*/, '' ) + history_hash;
                             }
                         }
                     }
                    
                 });
             },
             teardown: function (){
                 if (!iframe){
                     clearTimeout(timeoutID);
                     $(iframe).remove();
                     iframe = 0;
                 }
             }
         };
     }
 
})

具体例子可见这里

打开后点击“运行代码”,然后点击页面触发hashchange,它的回调会在页面添加一行红字,然后再点击后退按钮就看到效果了。

 

 

location的hash部分和使用window.onhashchange实现ajax请求内容时使用浏览器后退和前进功能

 

 在js跨域双向数据传递时可以用iframe加上location.hash来实现,在研究这个的时候深入学习了一下hash的特性。

  hash就是uri中#及后面的部分,例如:www.google.com.hk#123的#123。当只有hash部分发生变化时,浏览器的历史记录会产生记录,但不会向服务器发出请求,这时按后退键地址栏的uri会变化但页面内容不变。

  而hash变化但不发出请求就是js跨域双向数据传递的基础啦。

  下面就讲述一下hash结合ajax的使用,ajax每次取数据时页面更新后浏览器并不产生历史记录,也就是说后退和前进按钮失去应用的效用,这时可以结合hash和window.onhashchange来使用,注意ie6、7均不支持onhashchange,但可以用setInterval定期检查hash的改变,或者onload中检查的方法。

  具体实现:

复制代码
 1 <body>
2
3 <div id="div1"></div>
4 <input type="button" value="click" onclick="GetT()" />
5
6 </body>
7 </html>
8 <script type="text/javascript" src="js/AjaxHasPool.js">
9 </script>
10 <script type="text/javascript">
11 var ajax = new AjaxHasPool();
12 var method="get";
13 var url ="Handler.ashx";
14 var i = 1;
15 var obj = new Object();
16 function GetT()
17 {
18 document.getElementById("div1").innerHTML=i;
19 ajax.Startup(null,url,method,ep);
20 }
21 function ep(xmlobj){
22 eval("obj['"+i+"']="+i+";");
23 location.hash="#"+i;
24 ++i;
25 }
26
27 window.onhashchange=function(){
28 var hashStr = location.hash.replace("#","");
29 if(typeof(eval("obj['"+hashStr+"']"))!="undefined")
30 document.getElementById("div1").innerHTML=eval("obj['"+hashStr+"']");
31 }
32 </script>
复制代码
1.AjaxHasPool是自己封装的ajax类,其中的ajax.Startup()就是发送ajax请求;
2.Object对象保存历史记录,如果对象属性为数字的话,要用obj["1"]的方式来实例化,否者会违反命名规范。
3.在使用window.onhashchange检测hash值获取历史数据。

转载于:https://www.cnblogs.com/qqyuhaitao/archive/2013/03/14/2958650.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值