总是在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. function showTab() {
  10. if (window.location.hash == "#tab2"){
  11. showTab2();
  12. } else {
  13. showTab1();
  14. }
  15. }
  16. function showTab1() {
  17. $("#tab2").hide();
  18. $("#tab1").show();
  19. window.location.hash = "#tab1";
  20. };
  21. function showTab2() {
  22. $("#tab1").hide();
  23. $("#tab2").show();
  24. window.location.hash = "#tab2";
  25. };

加上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. // Fall back to normalcy for older browsers.
  3. if ( !$.support.pjax ) {
  4. $.pjax = function( options ) {
  5. window.location = $.isFunction(options.url) ? options.url() : options.url
  6. }
  7. $.fn.pjax = function() { return this }
  8. }

Ajax保留浏览器历史的两种解决方案(HashPjax)相关推荐

  1. 移动端采用Flexible将PX转换REM适配及开发中Retina屏1px边框的两种解决方案

    移动端采用Flexible将PX转换REM适配及开发中Retina屏1px边框的两种解决方案 说明:两个方案均基于Webpack构建. 方案一: 搭建环境及相关配置 webpack 3,需要loade ...

  2. 计算机到未识别网络有个叹号,上网异常:出现黄色感叹号不能上网的两种解决方案...

    我们常常用电脑时会遇到黄色感叹号不能上网的情况,为此不知道怎么办,以下我为大家介绍两种解决方案. 工具/原料 电脑 方法/步骤 第一步:上网异常,常常在右下角出现黄色感叹号,我们直接右击它,如图所示 ...

  3. java.lang.NoSuchMethodError: javax.persistence.OneToMany.orphanRemoval()Z 两种解决方案

    java.lang.NoSuchMethodError: javax.persistence.OneToMany.orphanRemoval()Z 两种解决方案 这个异常是在我们配置spring +  ...

  4. neo4j批量导入数据的两种解决方案

    neo4j批量导入数据的两种解决方案 参考文章: (1)neo4j批量导入数据的两种解决方案 (2)https://www.cnblogs.com/YoungF/p/11632488.html 备忘一 ...

  5. Ajax跨域问题的两种解决方法

    Ajax跨域问题的两种解决方法 参考文章: (1)Ajax跨域问题的两种解决方法 (2)https://www.cnblogs.com/pandang/p/5341250.html 备忘一下.

  6. php 嵌套 mysql_PHP中实现MySQL嵌套事务的两种解决方案,mysql嵌套_PHP教程

    PHP中实现MySQL嵌套事务的两种解决方案,mysql嵌套 一.问题起源 在MySQL的官方文档中有明确的说明不支持嵌套事务: 1. Transactions cannot be nested. T ...

  7. vb跨域访问ajax,解决AJAX的跨域访问-两种有效示例

    这篇文章主要为大家详细介绍了解决AJAX的跨域访问-两种有效示例,具有一定的参考价值,可以用来参考一下. 感兴趣的小伙伴,下面一起跟随512笔记的小玲来看看吧!新的W3C策略实现了HTTP跨域访问,还 ...

  8. php ajax jquery 表单重复提交,jQuery的 $.ajax防止重复提交的两种方法(推荐)

    下面给大家带来两种关于jquery 的ajax防止重复提交的解决方法,具体介绍如下所示: 1.第一种,对于onclick事件触发的的ajax 可以采用如下方法: 即在beforeSend中使点击按钮不 ...

  9. java多个事件_window.onload绑定多个事件的两种解决方案

    前言 有些函数,必须在网页加载完毕 网页加载完毕时会触发一个onload事件,将函数绑定到这个事件上即可. 复制代码 代码如下: window.onload = myFuncti编程客栈on; 问题来 ...

最新文章

  1. python装饰器原理-深入理解 Python 装饰器
  2. 1081. Rational Sum (20) -最大公约数
  3. java 开发书籍 目录_《零基础 Java 开发 》全书目录
  4. 30个Python常用极简代码,拿走就用,赶紧收藏!
  5. 目标识别、目标跟踪算法总结
  6. 傅里叶级数与复的傅里叶级数、傅里叶变换
  7. STM32工具使用---STVP烧录工具
  8. 给大家推荐一个资源库https://www.awesomes.cn/
  9. 网易企业邮箱:与POP3、WebMail相比,为什么Imap4更被接受
  10. c++ 求N个数的最大公约数和最小公倍数
  11. ubuntu18.04-ros-melodic-carlar安装教程详细指南
  12. 个人喜欢的歌曲——女生篇
  13. python predictabel_统计学习方法的python实现
  14. 基于微信小程序的校园二手物品交易平台的设计与实现
  15. 2.STM32F4/7点灯
  16. Altium Designer-打开丝印层、位号,不显示器件位号问题
  17. what?spring已经解决循环依赖了,为啥还报循环依赖错误?
  18. 单光感pid巡线_乐高4种单光感巡线逻辑
  19. 怎么让word文档不显示标记及修改的状态
  20. 计算机中恢复是什么的反操作,电脑屏幕反了哪个快捷键调回来 选择控制面板点击进入(如下图...

热门文章

  1. 21、【易混淆概念集】-第十三章 相关方参与度评估矩阵 VS 相关方参与计划 相关方登记册 VS 相关方参与计划 相关方立方体 VS 凸显模型 权力/利益方格
  2. jqweui 中的tabbar导航
  3. BIM一级考试复习视频
  4. 【python初级】 windows10上升级pip
  5. 怎么把多个ppt文件合并到一个ppt文件中?
  6. 向Oracle电子杂志投稿
  7. 机器学习--集成学习--Bagging,Boosting,Stacking
  8. 传感器配件/胀差卡件A6210Emerson
  9. 计算机二级 学习资料 网盘分享
  10. 激光SLAM导航系列(二)SLAM与导航系统框架