【东网技术大咖】HTML5 history api搭配ajax实现前进后退
发布时间: 2017-04-01 15:16:39
AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术。通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
在良品铺子生命周期系统开发中,遇到过这样一种情况,我们使用ajax来加载不同标签页的数据,用户在使用的时候想用前进后退来切换标签页,发现直接退出了当前功能,于是向我们反馈了这一问题。确实,在用户使用中,不同标签页的切换对于他们来说是意味着不同的页面,自然而然会想前进后退来切换,但是实际中ajax是无法前进后退的,便造成很糟糕的体验,比如填好的表单后退后全部消失,查询好的数据后退一下又需要重新查询。
那么如何解决这一问题呢?在实际开发中,单纯使用ajax,浏览器地址是不会发生变化,前进后退是无法控制标签切换的,这个时候我们必须借助HTML5里新的history api搭配ajax来解决这个问题。
我们先来回顾一下现有html规范中,history对象的三个方法:
方法 |
描述 |
back() |
加载 history 列表中的前一个 URL。 |
forward() |
加载 history 列表中的下一个 URL。 |
go() |
加载 history 列表中的某个具体页面。 |
使用ajax时,由于地址未发生变化,这三个api是无法进行页面控制的。
新的HTML5标准为我们解决了这一难题,html5标准中history对象增加了两个方法。
方法 |
描述 |
pushState() |
存储当前历史记录点 |
replaceState() |
替换当前历史记录点 |
还有一个搭配使用的popstate事件,用于监听url的变化。
pushState能改变当前url(添加新的历史记录点),popstate监听url的变化,浏览器的前进后退改变url(在历史记录点之间切换),三者结合便能解决ajax中前进后退的问题。
让我们先来看下pushState,replaceState,popstate这个三个新的api的详细介绍。
存储的方式类似于数组的入栈(Array.push()),在window.history里新增一个历史记录点,例如:
// 当前的url为:http://www.example.com/demo.html
var json={time:new Date().getTime()};
//@状态对象:记录历史记录点的额外对象,可以为空
//@页面标题:目前所有浏览器都不支持
//@可选的url:浏览器不会检查url是否存在,只改变url,url必须同域,不能跨域
window.history.pushState(json,"","http://www.example.com/demo.html#test");
var state = {title: title,
url: options.url,
otherkey: othervalue
};
window.history.pushState(state, document.title, url);
执行了pushState方法后,页面的url地址为:
http://www.example.com/demo.html#test
window.history.replaceState和window.history.pushState类似,不同之处在于replaceState不会在window.history里新增历史记录点,其效果类似于window.location.replace(url),都是不会在历史记录点里新增一个记录点的。当你为了响应用户的某些操作,而要更新当前历史记录条目的状态对象或URL时,使用replaceState()方法会特别合适。
监听历史记录点,直观的可认为是监听URL的变化,但会忽略URL的hash部分,可以通过window.onpopstate来监听url的变化,并且可以获取存储在该历史记录点的状态对象,也就是上文说到的json对象。
值得注意的是:window.history.pushState和window.history.replaceState不会触发onpopstate事件。
了解了这三个新的api,再让我们看看如何实际开发中来进行应用。
一个分页的例子,点击不同页面使用ajax加载不同的地市编号和地市名称,默认加载第一页,如果带有页码n会加载第n页的数据,前进后退能够在不同页面进行切换
页面部分:
Js代码:
var page_data=[{
"CityID": 159,
"name": "武汉市",
"ProID": 17,
"CitySort": 159
}, {
"CityID": 160,
"name": "襄樊市",
"ProID": 17,
"CitySort": 160
}, {
"CityID": 161,
"name": "鄂州市",
"ProID": 17,
"CitySort": 161
}, {
"CityID": 162,
"name": "孝感市",
"ProID": 17,
"CitySort": 162
}, {
"CityID": 163,
"name": "黄冈市",
"ProID": 17,
"CitySort": 163
}];
//保存当前页码
var page=-1;
function loadPage(no){
//加载数据
loadData(no);
//添加记录点,每次push都会添加一个记录点,即使url相同
//防止重复添加
if(page==no){
return;
}else{
page=no;
push(no);
}
}
function loadData(no){
//加载分页数据,实际应用中为ajax取分页数据
document.getElementById("content").innerHTML = page_data[no-1].CityID + " --- " + page_data[no-1].name;
}
function push(no){
//json对象
var state = {
no: no
};
var title = "第"+no+"页";
var query = "#"+no;
//添加记录点
history.pushState(state,title,location.href.split("?")[0].split("#")[0] + query );
}
//监听url变化,根据url和json对象进行不同的处理,相当于路由的功能
window.onpopstate = function(event){
var state = event.state;
loadData(state.no);
};
//初始化,默认加载第1页,如果带有页面n,则加载第n页
function init(){
page = location.href.split("?")[0].split("#")[1];
if(undefined==page){
loadPage(1);
}else{
loadPage(page);
}
}
init();
效果截图:
可以看到,浏览器里面的链接变为url+#+页码,这个时候可以通过前进后退来触发onpopstate 来实现ajax加载不同页面的数据,监听事件触发后可以根据json对象和链接里的参数来进行不同的处理,以达到切换标签的效果,用户体验时的感觉和前进后退是没有任何差异的,由于没有刷新页面,体验甚至会更好。
至此,问题得到圆满解决。