Ajax保留浏览器历史的两种解决方案(Hash&Pjax)

总是在github down点东西,github整个界面做的不错,体验也很好~对于其中的源代码滑动的特效最为喜欢了~刚开始以为这个只是普通的ajax请求效果,但是发现这个特效能够导致浏览器地址栏跟随变化,并且再点击前进后退按钮后又可以将代码滑回滑出~~于是乎就来研究下吧~

一、通过锚点Hash实现:

在这方面其实国内很早就有做了,比如淘宝画报,通过的是在地址栏后面加#锚点实现的,浏览器是可以识别锚点为单位的历史记录的。但不是说页面本身有这个锚点,锚点的Hash只是起到一个引导浏览器将这次的记录推入历史记录栈顶的作用。

来做一个小小的demo:

Html代码  

  1. <style type="text/css">  
  2.     #tab1_header,#tab2_header{  
  3.         cursor:pointer;  
  4.         border:1px solid;  
  5.         width:50px;  
  6.     }  
  7.     #tab1,#tab2{  
  8.         width:90%;  
  9.         height:200px;  
  10.         border:1px solid;  
  11.     }  
  12. </style>  
  13. <div id="tab_header">  
  14.     <span id="tab1_header">Tab1</span>  
  15.     <span id="tab2_header">Tab2</span>  
  16. </div>  
  17. <div id="tab1">1</div>  
  18. <div id="tab2">2</div>  

 一个很简单的Tab切换如果一般情况下就直接:

 

Js代码  

  1. $("#tab1_header").click(function() {  
  2.             $("#tab2").hide();  
  3.             $("#tab1").show();  
  4. });  
  5. $("#tab2_header").click(function() {  
  6.             $("#tab1").hide();  
  7.             $("#tab2").show();  
  8. });  

但假如点击到tab2时想通过后退按钮退到tab1时就不行了,假如刷新的话浏览器的行为完全不是出于用户的想法,这样的话,我们可以加入#锚点来模拟新页面,为什么要说模拟呢,假如直接通过js改变window.location浏览器会重新加载页面,但加#就不会重新加载并且能保存在历史中。JS通过window.location.hash来控制URL后面的锚点#。

我们把代码改为这样:

 

Js代码  

  1. $(function(){  
  2.             showTab();  
  3.             $(window).bind('hashchange', function(e){  
  4.                 showTab();  
  5.             });  
  6.             $("#tab1_header").click(showTab1);  
  7.             $("#tab2_header").click(showTab2);  
  8.         });  
  9.   
  10.         function showTab() {  
  11.             if (window.location.hash == "#tab2"){  
  12.                 showTab2();  
  13.             } else {  
  14.                 showTab1();  
  15.             }  
  16.         }  
  17.         function showTab1() {  
  18.             $("#tab2").hide();  
  19.             $("#tab1").show();  
  20.             window.location.hash = "#tab1";  
  21.         };  
  22.         function showTab2() {  
  23.             $("#tab1").hide();  
  24.             $("#tab2").show();  
  25.             window.location.hash = "#tab2";  
  26.         };  

  加上window.location.hash = "#tab1"这一段代码就行了,在点击tab后,地址栏后面就会加上#tab1,点击tab2后就会改成#tab2,当浏览器检测到url变化时就会触发hashchange这一事件,就是用户在点击后退时能够得到的事件就能够通过window.location.hash进行判断并进行ajax操作了,但是haschange这个事件并不是每个浏览器都有的,只有现代高级浏

览器才有,所以在低级的浏览器中需要用轮询来检测URL是否在变化,这个这里就不具体说了。

 

二、通过HTML5加强型的History对象实现(类Pjax)

可以通过window.history.pushState这个方法无刷新的更新浏览器地址栏,这个方法在更新地址栏的同时将地址压入历史记录堆栈里,而要取出这个栈顶页面则可以用popstate这个事件来捕获~

来模拟一下github的环境,github中每个url是对应一个完整的实际页面的,所以在ajax请求页面时需要异步获取target页面中指定id容器中的内容:

比如有这样两个页面:

index.html

 

Html代码  

  1. <!DOCTYPE HTML>  
  2. <html>  
  3.     <head>  
  4.         <meta http-equiv="Content-Type" content="text/html; charset=gbk">  
  5.         <title>index</title>  
  6.     </head>  
  7.     <body>  
  8.         <script>document.write(new Date());</script>  
  9.         <div id="cn">  
  10.             <a href="second.html">加载前</a>  
  11.         </div>  
  12.     </body>  
  13. </html>  

 

second.html

 

 

Html代码  

  1. <!DOCTYPE HTML>  
  2. <html>  
  3.     <head>  
  4.         <meta http-equiv="Content-Type" content="text/html; charset=gbk">  
  5.         <title>second</title>  
  6.     </head>  
  7.     <body>  
  8.         <script>document.write(new Date());</script>  
  9.         <div id="cn">  
  10.             <a href="index.html">加载后</a>  
  11.         </div>  
  12.     </body>  
  13. </html>  

假如用同步的http请求打开的话完全是两个页面,两个页面加入很多地方一样的话我们完全可以用这种方法来实现ajax请求变更DOM,我在这里加了<script>document.write(new Date());</script>语句通过它的变化能得知是否取自两个http请求,局

部的ajax请求是不会改变这个时间显示的。

 

Js代码  

  1. $(function(){  
  2.         var state = {  
  3.                     title: "index",  
  4.                     url: "index.html"  
  5.                 };  
  6.                 $("#cn").click(function(){  
  7.                     window.history.pushState(state, "index", "second.html");  
  8.                     var $self = $(this);  
  9.                     $.ajax({  
  10.                         url:"second.html",  
  11.                         dataType: "html",  
  12.                         complete: function(jqXHR, status, responseText){  
  13.                             responseText = jqXHR.responseText;  
  14.                             if (jqXHR.isResolved()) {  
  15.                                 jqXHR.done(function(r){  
  16.                                     responseText = r;  
  17.                                 });  
  18.                                 $self.html($("<div>").append(responseText.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "")).find("#cn"));  
  19.                             }  
  20.                         }  
  21.                     });  
  22.                     document.title = "second";  
  23.                     return false;  
  24.                 });  
  25.                 $(window).bind('popstate', function(e){  
  26.                     var st = e.state;  
  27.                     //$("#cn").load(st.url + " #cn");  
  28.                     $.ajax({  
  29.                         url:"index.html",  
  30.                         dataType: "html",  
  31.                         complete: function(jqXHR, status, responseText){  
  32.                             responseText = jqXHR.responseText;  
  33.                             if (jqXHR.isResolved()) {  
  34.                                 jqXHR.done(function(r){  
  35.                                     responseText = r;  
  36.                                 });  
  37.                                 $("#cn").html($("<div>").append(responseText.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "")).find("#cn"));  
  38.                             }  
  39.                         }  
  40.                     });  
  41.                     document.title = e.state.title;  
  42.                 });  
  43. });  

 

上面语句中当#cn元素被点击时将state通过pushState方法压入历史记录栈,并在第三个参数中将浏览器URL框中指向second页面,并通过ajax将second页面异步载入,将相应的部分加入容器中,这样就实现了异步加载并改变地址栏url了,同样用户点击后退时,触发popstate,刚才pushState方法中的第一个参数state便是这里传入的形参e中的state属性,通过var st = e.state取出供开发使用。同时载入index页面中对应内容。时间有限这个js没有进行重构,直接写$.ajax了,其实假如不需要任何特效单纯的异步载入在jQ中可以直接用$("#cn").load(st.url + " #cn");将请求的html对应的#cn放到本页面的#cn容器中,但加入要更加炫的特效的话就要直接操作ajax传回的数据了。

 

Js代码  

  1. $("#cn").html($("<div>").append(responseText.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "")).find("#cn"));  

 

先创建一个div容器在将经过script过滤过的代码装入这个容器在通过find方法找到里面对应的选择器容器插入本身的页面中,这里可以不用html来填充,可以根据自己的项目需要用slideUp,show什么的特效进行内容显示~~

 

另外这里要推荐一个jQuery组件叫pjax(https://github.com/defunkt/jquery-pjax),比较牛叉的一个组件,异步的部分load进来另外一个页面对应容器中的内容,实现的机理和我上面的第二种方案一致。pushState + ajax = pjax 感觉这个应用会热起来的。

 

稍微总结下,两种方案其实对于想IE6或者FF3.6等比较低级的浏览器支持不是很好,前者若要兼容低端浏览器要用轮询来监听浏览器地址栏行为,而后者的话是完全的HTML5应用,对于非HTML5浏览器只能做判断跳转了。

如pjax最后的一段无奈的兼容处理:

 

 

Js代码  

  1. $.support.pjax = window.history && window.history.pushState  
  2.   
  3.   
  4. // Fall back to normalcy for older browsers.  
  5. if ( !$.support.pjax ) {  
  6.   $.pjax = function( options ) {  
  7.     window.location = $.isFunction(options.url) ? options.url() : options.url  
  8.   }  
  9.   $.fn.pjax = function() { return this }  
  10. }  
时间: 2024-09-23 19:46:28

Ajax保留浏览器历史的两种解决方案(Hash&Pjax)的相关文章

Ajax打开新窗口被浏览器拦截的两种解决办法

最近在做支付时发现打开支付窗口时被浏览器拦截了,百度了一下才发现是因为打开窗口前用ajax验证是否能支付,所以不是用户主动触发的打开ixin窗口,浏览器认为这样不安全,所以给拦截了. 解决办法一 先开始打开一个空的新窗口,然后改变新窗口的url,具体代码为 var wd = window.open(); $.ajax({ type: "POST", dataType: "json", url: URL, data: {orderNo:orderNo}, succes

上网异常:出现黄色感叹号不能上网的两种解决方案

  我们常常用电脑时会遇到黄色感叹号不能上网的情况,为此不知道怎么办,以下我为大家介绍两种解决方案. 工具/原料 电脑 方法/步骤 第一步:上网异常,常常在右下角出现黄色感叹号,我们直接右击它,如图所示 第二步,右击黄色感叹号时,会出现打开网络和共享中心,然后选择点击它,如图所示 第三步:点击进去后会看到有个红色X的,点击那里,如图所示 第四步:点击红色X后会进到以下这个正在检测页面,系统会自动帮你修复,然后黄色感叹号就给修复好了,如图所示如果不行,请试第二个方法 方法/步骤2 第一步:点击右下

Ajax解决多余刷新的两种方法(总结)

控制器Servlet则提供了简单的改变: 对于Ajax系统而言,服务器响应无须是整个页面内容,可以仅是 必需的数据,控制器不能将数据请求转发到jsp页面. 此时控制器有两个选择: 1.直接生成简单的响应数据. 在这种模式下,Servlet直接通过response获取页面输出流,通过 输出流生成字符响应. package pers.zkr.chat.web; import java.io.IOException; import java.io.PrintWriter; import javax.s

Ajax中解析Json的两种方法对比分析

  这里给大家介绍的是Ajax中解析Json的两种方法对比分析,十分的实用,本文为学习笔记,属新手文章,欢迎指教! eval(); //此方法不推荐 JSON.parse(); //推荐方法 一.两种方法的区别 我们先初始化一个json格式的对象: ? 1 2 3 4 5 var jsonDate = '{ "name":"周星驰","age":23 }'   var jsonObj = eval( '(' + jsonDate + ')' );

XP系统经常提示“应用程序正在运行”的两种解决方案

XP系统经常提示"应用程序正在运行"的两种解决方案 原因一:输入法出现问题 打开"任务管理器",就会发现每次打开IE都会多运行一个ctfmon.exe进程,当把任务栏多出来的ctfmon.exe进程删掉的时候,在打开连接还是一样会再多出来一个ctfmon.exe进程. 解决方案一: 1.打开 控制面板-区域和语言选项-语言-详细信息-高级-把兼容配置下的"将高级文字服务支持应用于所有程序"选中-重启,即可解决问题; 2.借助第三方修复工具来修复c

XP系统笔记本摄像头倒置的两种解决方案

  XP系统笔记本摄像头倒置的两种解决方案         方案一: 1.一般是驱动的问题,需要根据摄像头的硬件ID进行查找下载; 2.设备管理器; 3.图像设备--选择图像设备下的摄像头点; 4.选择图像设备下的摄像头点击右键属性--详细信息; 5.详细信息--查看VID和PID; 6.然后到华硕的官网上下载摄像头驱动; 7.进入华硕官网选择"服务支持"--"更多详情"; 8.在搜索框中输入"Camera",选择对应的操作系统.再根据摄像头的硬

XP系统提示“无法访问您要使用的功能所在的网络位置”的两种解决方案

XP系统提示"无法访问您要使用的功能所在的网络位置"的两种解决方案   方案一: 直接覆盖安装或者选择修复安装Office即可. 方案二: 1.打开注册表(打开方法:开始-运行,输入:regedi). 2.按f3搜索gaozhi.msi(ps:先备份). 3.你可以在"hkey_current_usersoftwaremicrosoftinstallerproducts762812c5feec1b428f26679f2dfae7c"键值中找到相应的东东. 4.先备份

WinXp桌面快捷方式图标变成蓝色的两种解决方案

  WinXp桌面快捷方式图标变成蓝色的两种解决方案         方案一: 1.在桌面上单击右键,点击"属性"; 2.点击"桌面"选卡,点击下面的[自定义]按钮; 3.点击"Web"选卡,在"网页"框中将所有网址勾选,然后点击"删除",在弹出的提示框总点击"是" ,点击确定--确定; 方案二: 1.在"我的电脑"上单击右键,选择"属性" ; 2

jQuery的 $.ajax防止重复提交的两种方法(推荐)_jquery

下面给大家带来两种关于jquery 的ajax防止重复提交的解决方法,具体介绍如下所示: 1.第一种,对于onclick事件触发的的ajax 可以采用如下方法: 即在beforeSend中使点击按钮不可用,ajax结果返回后置为可用 $.ajax( { type: 'POST', url: APP+'?m=Shopping&a=ajaxSubmitorder&sid='+sid+'&src='+src, cache:false, dataType: 'json', data: {'