前言
在应用ajax与服务器进行数据交互的过程中,实现了页面的局部刷新,极大地改善了用户体验。但是却出现了一些问题:用户发出若干次ajax请求后,浏览器的前进后退功能失效了,这时点击浏览器返回按钮,会直接返回到最初的url资源页面。
比如,在一个页面中的分页模块,使用ajax与后台进行数据交互,如若不做特殊处理,用户浏览了若干页后,假设现在正在浏览第六页,用户现在点击返回键,不会返回到第五页的数据界面,而是是直接返回上一个url资源界面。出现这种情况的原因是,浏览器会记录地址栏的url资源链接,如果url链接发生变化,浏览器会把该url链接保存到一个特殊的数据结构中,这样当用户点击返回与前进按钮时,会快速访问已经被记录的url链接资源。
而使用ajax进行局部数据更新时,浏览器地址栏的url链接没有改变,所以浏览器也就不会保存记录。这时候的结果就是,点击返回按钮出现了非期待性结果。这种问题在SPA(single page web application)单页面应用中尤为常见。
解决方案
通过设置window.location.hash。
location.hash用于设置页面的标签值。
假设一个名为hash.html的页面主题内容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<style>
div{
height:600px;
width:500px;
}
</style>
<body>
<a href="#section3">to part3</a>
<div id="section1">part1</div>
<div id="section2">part2</div>
<div id="section3">part3</div>
</body>
</html>
浏览器访问该页面:
点击超链接to part3,定位到part3部分:
我们看到浏览器的地址栏改变了,后面多了个#section3
,这个部分就是location.hash的值。
虽然我们一直在hash.html这个页面,但是增加location.hash值后,浏览器的url地址栏资源链接改变了,浏览器就会把该url链接作为历史记录保存下来。这时候点击返回按钮,我们能回到hash.html的原始位置:hash.html。即:浏览器认为hash.html与hash.html#section3是两个不同的url,所以浏览器会保存上述url链接。
由此,我们可以在需要的时候,在ajax与服务器进行交互时,设置
window.location.hash的值:
function updateView (attr){
$.ajax({
type:...,
url:...,
data:{attr : attr},
success:function(datas){
//设置hash值
window.location.hash = "#"+attr;
//do somthing
},
error:function(status){
//do somthing
}
});
}
这个值最好是该次请求所需的参数。假设该请求代表A.html页面中的翻页功能,即:调用updateView (1),代表查看第一页,调用过后,浏览器地址栏变为:A.html#1,再次调用updateView (6),查看第六页,浏览器地址栏变为:A.html#6。
这时,设置onhashchange事件监听:
window.onhashchange=function(){
var attr=window.location.hash.replace("#","");
updateView (attr);
}
用户依次访问了第一页,第六页,这时点击浏览器返回键,onhashchange事件触发,获取到attr的值为1;调用updateView (1),显示第一页的视图,用户体验良好,但服务器压力增大。
BUG解决
这样处理后,用户点击第一页的视图,ajax请求成功后,会主动改变hash值,这时候又触发onhashchange,又一次更新视图,两次访问服务器。
设置一个全局变量,记录hash值的改变是怎样引起的:
var innerDocClick;
$('body').on('mouseleave',function(){
innerDocClick=false;//鼠标在页面外(点击了返回按钮)
});
$('body').on('mouseover',function(){
innerDocClick=true;//鼠标在页面内(没有点击返回按钮)
});
window.onhashchange=function(){
if(!innerDocClick)//若点击了返回按钮
{
var attr=window.location.hash.replace("#","");
updateView (attr);
}
}
同理,刷新功能不攻自破。
暂时解决问题。
附:完整SPA展示:www.lword.top