Ajax异步刷新地址栏url改变(利用Html5 history.pushState实现)
效果:
众所周知:ajax可以实现页面的局部刷新,可以做到非常奈斯的数据加载效果,给用户带来非常良好的体验,但是ajax的除了会曝露一些不太安全的服务器信息之外,最蛋疼的就是不能在浏览器的历史会话中保留记录。就是当你点开一个页面,ajax各种数据加载各种欢乐啊,例如一个列表页面,异步加载来翻页。结果用户一不小心刷新了页面,那么页码就得重新开始计算,一旦用户改变了会话状态(浏览器的前进、后退、刷新),那么ajax就会丢失相关的数据。
最近在网上浏览各大网站无意中发现了ajax异步刷新但是地址栏改变的效果。
例如google doodles,大家可以点击下面的链接后翻页查看图片,就可以发现页面ajax刷新地址栏也同步改变了,飞机票在这里,请戳:
http://www.google.com/doodles/grandfathers-day-2014
优点如下:
- 卓越的用户体验
- 对搜索引擎更加友好
- 更多敬请补充...
实现方案(写入会话状态):
对这种效果抱着好奇的心态就去查阅了一下资料。
在Html5中为window.history对象引入了pushState和replaceState方法,对window.history对象还不太了解的童鞋请自行查阅相关资料。
示例:
//格式约定
history.pushState(data, title[, url]);
/// <summary>
/// pushState方法调用示例,replaceState方法同样的参数格式,
/// 本方法负责将自定义数据写入浏览器会话历史
/// linkFly原创,引用请注明出处,谢谢
/// </summary>
/// <param name="data" type="object">
/// 需要进行保存(在历史会话)的数据,该数据可以在下一次会话中读取出来
/// </param>
/// <param name="title" type="String">
/// 写入历史会话的标题,经过测试暂时没有发现用处,不会对当前文档标题产生影响,可以传入空字符串
/// </param>
/// <param name="url" type="String">
/// 要写入浏览器历史会话的Url【注意不允许跨域】
/// </param>
/// <returns type="void" />
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) {
/// <summary>
/// 在页面初始化加载完成中添加该事件,则可以监听到onpopstate事件,而浏览器进行前进、后退、刷新操作都会触发本事件
/// linkFly原创,引用请注明出处,谢谢
/// </summary>/// <returns type="void" />
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) {
/// <summary>
/// 1: 获取地址栏参数方法
///
- getUrlParameter(fieldName) - 在当前Url中查询指定的参数,返回查询得到的值,当不支持pushState或没有查询到参数的时候返回空字符串
/// </summary>
/// <param name="fieldName" type="String">
/// 要查询的字符串
/// </param>
/// <returns type="String" />
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 () {
/// <summary>
/// 检测浏览器是否支持pushState方法
/// </summary>
/// <returns type="Boolean" />
if (window.history.pushState) return true;
return false;
},
pushState: function (data, url) {
/// <summary>
/// 状态保持方法(需要高版本浏览器支持),当canPush为true的时候表示浏览器可以进行push状态,则进行状态push并返回是否成功
/// 1.1 - pushState(data,url) 将指定的data,和url push到浏览器会话历史进行状态保持【注意Url不允许跨域】
/// </summary>
/// <param name="url" type="String">
/// 需要写入浏览器会话历史的url
/// </param>
/// <returns type="Boolean" />
if (historyState.checkCanPush()) {
//注意data虽然可以保存数据,但是不能保存仍然引用着当前页面元素的对象,例如$("DOM")这样一个对象,就会出现ObjectCloneError
window.history.pushState(data, document.title, url);
return true;
}
return false;
},
getUrlParameter: function (fieldName) {
/// <summary>
/// 1: 获取地址栏参数方法
/// - getUrlParameter(fieldName) - 在当前Url中查询指定的参数,返回查询得到的值,当不支持pushState或没有查询到参数的时候返回空字符串
/// </summary>
/// <param name="fieldName" type="String">
/// 要查询的字符串
/// </param>
/// <returns type="String" />
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');
//进行数据还原操作... }
相关资料:
Ajax异步刷新地址栏url改变(利用Html5 history.pushState实现)的更多相关文章
- ajax与HTML5 history pushState/replaceState实例
一.本文就是个实例展示 三点: 我就TM想找个例子,知道如何个使用,使用语法什么的滚粗 跟搜索引擎搞基 自己备忘 精力总是有限的,昨天一冲动,在上海浦东外环之外订了个90米的房子,要借钱筹首付.贷款和 ...
- HTML5 history.pushState()和history.replaceState()新增、修改历史记录用法介绍
抽空研究了下这两个新方法,确实可以解决很多问题 1.使用pushState()方法 可以控制浏览器自带的返回按钮: 有时候我们想让用户点击浏览器返回按钮时,不返回,或执行其他操作,这时,就用到hist ...
- Ajax异步刷新地址栏
公司项目后台使用现成的UI框架,DevExpress,jqGrid,XXXUI之类的,这些展示数据列表的控件/插件,基本是异步的. 这倒也好,有变化也只是数据那一块变化,不会重新加载整个页面. 但是, ...
- 使用ajax和window.history.pushState无刷新改变页面内容和地址栏URL
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- 使用ajax和window.history.pushState无刷新改变页面内容和地址栏URL (转)
在访问现在很火的google plus时,细心的用户也许会发现页面之间的点击是通过ajax异步请求的,同时页面的URL发生了了改变.并且能够很好的支持浏览器的前进和后退.不禁让人想问,是什么有这么强大 ...
- 使用ajax和history.pushState无刷新改变页面URL onpopstate(转)
Javascript代码 var htmlData1 = $.ajax( { url: "/getXXXResponse", async: false }).re ...
- 使用ajax和history.pushState无刷新改变页面URL
表现 如果你使用chrome或者firefox等浏览器访问本博客.github.com.plus.google.com等网站时,细心的你会发现页面之间的点击是通过ajax异步请求的,同时页面的URL发 ...
- 使用ajax和history.pushState无刷新改变页面URL(转)
表现 如果你使用chrome或者firefox等浏览器访问本博客.github.com.plus.google.com等网站时,细心的你会发现页面之间的点击是通过ajax异步请求的,同时页面的URL发 ...
- HTML5无刷新修改Url,history pushState/replaceState
一.认识window.history window.history表示window对象的历史记录,是由用户主动产生,并且接受javascript脚本控制的全局对象.window对象通过history对 ...
随机推荐
- android用讯飞实现TTS语音合成 实现中文版
Android系统从1.6版本开始就支持TTS(Text-To-Speech),即语音合成.但是android系统默认的TTS引擎:Pic TTS不支持中文.所以我们得安装自己的TTS引擎和语音包. ...
- Testing - 质量保证与质量控制
QA QC QM 概念 Quality Assurance (质量保证) Quality Control (质量控制) Quality Manage (质量管理) 定义 为达到质量要求所采取的作业技术 ...
- js每天进步一点点3
JS之样式的改变
- Windows Azure Cloud Service (41) 修改云服务IIS托管管道模式为4.0经典模式
<Windows Azure Platform 系列文章目录> 这是笔者在之前的项目中遇到的问题,做一下总结,给网友做参考. 在一般情况下,Visual Studio开发的Cloud Se ...
- IE条件注释详解
IE条件注释是微软从IE5开始就提供的一种非标准逻辑语句,作用是可以灵活的为不同IE版本浏览器导入不同html元素,如:样式表,html标签等.很显然这种方法的最大好处就在于属于微软官方给出的兼容解决 ...
- IOS开发技巧快速生成二维码
随着移动互联网的发展,二维码应用非常普遍,各大商场,饭店,水果店 基本都有二维码的身影,那么ios中怎么生成二维码呢? 下面的的程序演示了快速生成二维码的方法: 在ios里面要生成二维码,需要借助一个 ...
- python基础知识理解
一.概述 看了一天的python基础语法,基本对python语法有了一个大概的了解(其实之前断断续续也看过python),学习网址:Python 基础教程.因为之前我学过C++,因此在学习python ...
- WinPhone学习笔记(二)——页面外观剖析
上一个篇博文说了WinPhone页面内部的东西,现在介绍表面的东西,先来看看一下一个WinPhone页面 这个页面分了三部分:顶部这个是状态栏, 中间这个是一个页面的内容部分, 最下面则是应用程序栏 ...
- 慎用Assembly.LoadFile()和Assembly.LoadFrom()
经测这俩方法会锁住文件,导致程序运行期间无法对load过的程序集文件进行更名/删除/覆盖等等操作,考虑用Assembly.Load()文件字节组替代: Assembly.Load(File.ReadA ...
- jquery-easyui-tree异步树
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...