博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Ajax异步刷新地址栏url改变(利用Html5 history.pushState实现)
阅读量:5127 次
发布时间:2019-06-13

本文共 6762 字,大约阅读时间需要 22 分钟。

 

  早些时候在博客园参阅了不少资料,然后决定入驻博客园分享自己的开发心得,最近准备转方向筹备着辞职交接工作,所以有点忙碌,搁置了一个月才匆匆写下这么一篇随笔,希望能给大家带来一点帮助吧,资料和学识有限,如有不正确的地方敬请指出,万分感谢。

  效果:

  众所周知:ajax可以实现页面的局部刷新,可以做到非常奈斯的数据加载效果,给用户带来非常良好的体验,但是ajax的除了会曝露一些不太安全的服务器信息之外,最蛋疼的就是不能在浏览器的历史会话中保留记录。就是当你点开一个页面,ajax各种数据加载各种欢乐啊,例如一个列表页面,异步加载来翻页。结果用户一不小心刷新了页面,那么页码就得重新开始计算,一旦用户改变了会话状态(浏览器的前进、后退、刷新),那么ajax就会丢失相关的数据。

  最近在网上浏览各大网站无意中发现了ajax异步刷新但是地址栏改变的效果。

  例如google doodles,大家可以点击下面的链接后翻页查看图片,就可以发现页面ajax刷新地址栏也同步改变了,飞机票在这里,请戳:

  

  优点如下:

  •   卓越的用户体验
  •   对搜索引擎更加友好
  •   更多敬请补充...

  实现方案(写入会话状态):

  对这种效果抱着好奇的心态就去查阅了一下资料。

  在Html5中window.history对象引入了pushStatereplaceState方法,对window.history对象还不太了解的童鞋请自行查阅相关资料。

  示例:

  

//格式约定history.pushState(data, title[, url]);/// ///     pushState方法调用示例,replaceState方法同样的参数格式, ///   
 本方法负责将自定义数据写入浏览器会话历史 ///   
 linkFly原创,引用请注明出处,谢谢///
/// /// 需要进行保存(在历史会话)的数据,该数据可以在下一次会话中读取出来/// /// /// 写入历史会话的标题,经过测试暂时没有发现用处,不会对当前文档标题产生影响,可以传入空字符串/// /// /// 要写入浏览器历史会话的Url【注意不允许跨域】/// ///
window.history.pushState(     {pageIndex:1,keywords:'善了个哉'},     document.title,     window.location.pathname+'?pageIndex=1'   );

 

  原理:

  该方法隶属Html5,是为了解决ajax方法不能“回到过去”的问题。window.history负责管理浏览器会话历史,而pushState则在浏览器历史中添加一条会话历史(replaceState则是替换一条历史)作为当前会话状态,而在用户刷新了页面之后进入这条会话,这时候我们只需要把会话的数据读取出来就行了。

  对每个参数进行特别说明一下:

  •   Data:可以任意存放一组数据,这组数据存放在该历史对话中,下次进入该对话则可以通过读取该数据来进行状态保持,例如可以存放页码信息,但是注意值不能引用对象,会报ObjectCloneError(对象克隆异常),例如当前页面的Element、$("#testId")这种引用了依赖当前页面的数据,Data数据要保持独立,值不允许为引用类型的对象
  •   Title:参阅的大部分文档对其都没有说明,只是简单的描述了文档标题。应该是在读取会话数据的时候自动对应到页面标题上,但是经过测试并不会对页面标题有任何的影响,如果是为了实现自动对应标题的话,功能就有点鸡肋(完全可以用Data),一般可以传入:document.title''(空字符串)
  •   Url:就是要写入历史会话的url,假定我们已经在历史记录中写入了Url,浏览器进行前进操作,跳转到了别的页面,然后再返回,进入的就是这个url。不允许跨域!本着面向对象的思想,一般可以通过window.location.pathname获取当前url地址,然后通过字符串拼接后面的参数传入就可以生成稳妥的url了。

 

  读取会话历史:

   在轻松写入了会话历史之后,我们还需要将它读出来才行。这个读取的切入点,嗯,查阅了资料说的都是通过onpopstate事件,实际上在这个事件上非常的蛋疼,我查阅的多数的文章都告诉说捕捉这个事件即可,代码如下:

    本示例不推荐使用:

//本代码仅作参考//环境 Firefox 25.0.1级以下版本不推荐使用本代码(高版本尚未测试)window.addEventListener('popstate', function(e) {
/// ///   
 在页面初始化加载完成中添加该事件,则可以监听到onpopstate事件,而浏览器进行前进、后退、刷新操作都会触发本事件 ///   
 linkFly原创,引用请注明出处,谢谢///
///
if (e.state) { //e.state就是pushState中保存的Data,我们只需要将相应的数据读取下来即可 } });// 传闻可以直接使用history.state来获取当前对应的state数据,笔者尚未测试,有兴趣的可以自行研究下,注意主要测试Firefox

  注意,以上代码在Firefox下存在问题。

  在这些资料中都只是草草的告诉说onpopstate事件可以做到读取数据,但在Firefox下,页面加载中根本不会触发onpopstate事件。

  参考:

  大家注意中间一大段的最后一句:

  Chrome and Safari always emit a popstate event on page load, but Firefox doesn't.

  翻译过来就是Chrome和Safari都会在页面加载中触发该事件,但是Firefox不会。

  所以这时候有两种处理方案:

  • 在页面加载中手动触发该事件
  • 通过解析url来实现,注意如果希望通过url来获取数据的话,那么之前是pushState主要需要保存的数据并非是data,而是url。这个概念需要清晰。

  在页面加载中手动触发该事件代码如下:

  

$(function(){     //通过jQuery.trigger()方法触发    //或者自己手写js触发,具体代码这里就不贴了...    $(window).trigger("hashchange"); });

 

  通过解析url代码如下:

  

function getUrlParameter(fieldName) {        ///         ///     1: 获取地址栏参数方法        ///     
- getUrlParameter(fieldName) - 在当前Url中查询指定的参数,返回查询得到的值,当不支持pushState或没有查询到参数的时候返回空字符串 ///
/// /// 要查询的字符串 /// ///
    if (window.history.pushState) { var urlString = document.location.search; if (urlString != null) { var typeQu = fieldName + "="; var urlEnd = urlString.indexOf(typeQu); if (urlEnd != -1) { var paramsUrl = urlString.substring(urlEnd + typeQu.length); var isEnd = paramsUrl.indexOf('&'); if (isEnd != -1) { return paramsUrl.substring(0, isEnd); } else { return paramsUrl; } } else { return ""; } } else { return ""; } } else { return ''; } }//调用方法:getUrlParameter('要查询的参数')

 

  总结:

  表达能力实在有限,快速总结一下。我个人采用的是url的方法来获取参数的,因为觉得这样更加稳妥,毕竟对于onpopstate中e.state琢磨的还是很透彻,而url从某种方式来更加的合理与稳妥一点。具体还需要根据实际情况来处理,采用url的方式需要服务器上对相应的url进行一番处理。

  •   window.history.pushState()方法中参数Data里面的值不允许存在和页面相关引用对象,可以这样{ pageIndex : 1 },但是不可以这样{ pageDom : document.getElementById('testId') }
  •   window.history.pushState()方法中参数url不允许跨域。
  •   目前在Firefox下onpopstate事件不会在page load中加载执行。
  •   如果后台需要区别是ajax还是经过push历史的ajax,可以在pushState中的ajax里面发送特殊的请求头,后台接收到该特殊的请求头信息后进行特殊处理。
  •   还有没补充的例如浏览器兼容性神马的请拉到文章最下面。

 

  其他:

  提供一份自己写的一份相应的js,直接copy使用即可。

  

//historyState对象,提供push历史数据和获取历史数据方法。//linkFly原创,引用请注明出处,谢谢var historyState = {    checkCanPush: function () {        ///         ///     检测浏览器是否支持pushState方法        ///         /// 
if (window.history.pushState) return true; return false; }, pushState: function (data, url) { /// /// 状态保持方法(需要高版本浏览器支持),当canPush为true的时候表示浏览器可以进行push状态,则进行状态push并返回是否成功 ///
1.1 - pushState(data,url) 将指定的data,和url push到浏览器会话历史进行状态保持【注意Url不允许跨域】 ///
/// /// 需要写入浏览器会话历史的url /// ///
if (historyState.checkCanPush()) { //注意data虽然可以保存数据,但是不能保存仍然引用着当前页面元素的对象,例如$("DOM")这样一个对象,就会出现ObjectCloneError window.history.pushState(data, document.title, url); return true; } return false; }, getUrlParameter: function (fieldName) { /// /// 1: 获取地址栏参数方法 ///
- getUrlParameter(fieldName) - 在当前Url中查询指定的参数,返回查询得到的值,当不支持pushState或没有查询到参数的时候返回空字符串 ///
/// /// 要查询的字符串 /// ///
if (historyState.checkCanPush()) { var urlString = document.location.search; if (urlString != null) { var typeQu = fieldName + "="; var urlEnd = urlString.indexOf(typeQu); if (urlEnd != -1) { var paramsUrl = urlString.substring(urlEnd + typeQu.length); var isEnd = paramsUrl.indexOf('&'); if (isEnd != -1) { return paramsUrl.substring(0, isEnd); } else { return paramsUrl; } } else { return ""; } } else { return ""; } } else { return ''; } }}//historyState对象调用示例window.onload = function () { //写入历史会话 historyState.pushState({ pageIndex: 1 }, window.location.pathname + '?pageIndex=1'); //获取历史会话的数据(获取url的参数数据) var pageIndex = historyState.getUrlParameter('pageIndex'); //进行数据还原操作...}

  相关资料:

      

      

      

 

作者:linkFly
原文:
出处:
声明:嘿!你都拷走上面那么一大段了,我觉得你应该也不介意顺便拷走这一小段,希望你能够在每一次的引用中都保留这一段声明,尊重作者的辛勤劳动成果。

转载于:https://www.cnblogs.com/silin6/p/linkFly_pushState.html

你可能感兴趣的文章
接口和抽象类
查看>>
poj2151 Check the difficulty of problems(概率dp)
查看>>
UI- UINavigationController UITabBarController 使用总结
查看>>
BZOJ3926: [Zjoi2015]诸神眷顾的幻想乡(广义后缀自动机)
查看>>
mysql 中 時間和日期函數大全
查看>>
mongodb基本语法
查看>>
[凯立德]2014全分辨率C-Car 4.0机车C2610版完美懒人包
查看>>
[LeetCode] Same Tree
查看>>
给Entity Framework添加执行的超时时间
查看>>
【总结】瞬时高并发(秒杀/活动)Redis方案(转)
查看>>
numpy模块
查看>>
iPhone图形开发绘图小结
查看>>
从零开始搭建微信硬件开发环境全过程——1小时掌握微信硬件开发流程
查看>>
Android应用程序线程消息循环模型分析
查看>>
Swift - 下标脚本方法介绍及实例
查看>>
解决方案设置centos上redmine2.3.0点击我的帐户和个人设置出现500错误的解决方案...
查看>>
最小较小codeforces 2B The least round way
查看>>
对象编译器ARC内部工作原理
查看>>
Java URLClassLoader动态加载外部java代码
查看>>
做一名合格的软件使用者
查看>>