Aajx实现无数据刷新时,我们会遇到浏览器前进后退失效的问题以及URL不友好的问题。
实现方式有两种
1、支持onhashchange事件的,通过更新和读取location.hash的方式来实现
/*
因为Javascript对dom的操作是不持久化的,刷新后就恢复原状,而且也不保存历史记录,也就无法前进后退来查看历史了。但是可以采用“地址栏加hash”技术来解决。@H_301_10@
地址栏中敲入“页面地址#aaa”就表示跳转到“页面地址 ”的“aaa”这个页内锚点(英文叫做hash)。只要改变“aaa”这个锚点内容,@H_301_10@浏览器就认为URL变化,也就会放入浏览历史,这样前进后退问题就解决了。我们只要把不同的AJAX状态通过不同的hash写到地址栏就可以了,当页面加载的时候检测是否有hash值,有的话就读取hash进行相应的ajax还原操作。@H_301_10@
location.hash可以取到或者设置hash的值,当hash改变的时候window.onhashchange事件会被触发,但是页面加载的时候哪怕有hash值,onhashchange事件也不会触发,因此需要在onload事件中也读取hash进行同样的处理,保证刷新页面也能恢复ajax的页面显示。@H_301_10@
下面是例子代码,为了简单的突出问题,这里没有使用ajax,只是通过dom来修改页面状态。点击文本框,文本框的内容会加1(注意观察地址栏),刷新页面后值也还是增加后的值,而且页面可以前进后退。@H_301_10@
代码如下:@H_301_10@
[@H_301_10@html]@H_301_10@
<!DOCTYPE html>@H_301_10@
<html xmlns="http://www.w3.org/1999/xhtml">@H_301_10@
<head>@H_301_10@
<Meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>@H_301_10@
<title>TestDemo</title>@H_301_10@
<script src="jquery-1.4.2-min.js"></script>@H_301_10@
<script type="text/javascript">@H_301_10@
var processHash = function () {@H_301_10@
var hashStr = location.hash.replace("#","");@H_301_10@
if (hashStr) $("#txt1").val(hashStr);@H_301_10@
}@H_301_10@
$(function () {@H_301_10@
$("#txt1").click(function () {@H_301_10@
var i = parseInt($("#txt1").val());@H_301_10@
i++;@H_301_10@
$("#txt1").text(i);@H_301_10@
location.hash = "#" + i;@H_301_10@
});@H_301_10@
window.onload = processHash;@H_301_10@
window.onhashchange = processHash;@H_301_10@
</script>@H_301_10@
</head>@H_301_10@
<body>@H_301_10@
<input type="text" id="txt1" value="1" />@H_301_10@
</body>@H_301_10@
</html>
@H_301_10@
*/
2、通过内嵌一个iframe来模拟实现页面的前进后退,通过iframe的onload事件来实现
/*
我可应很负责任的告诉你:ajax加载页面是无法实现浏览器前进和后退功能的, 因为你是直接通过jq 将当前页面的内容全给替换掉了,而页面并没有跳转。 不过不是所有事都是绝对的。告诉你一个比较笨但是有比较实用的方法。 就是通过@H_301_10@iframe轻松解决问题。 首先,你的页面需要一个隐藏的iframe,且iframe的src对应的是一个任意的html,@H_301_10@jsp都行。 当你ajax加载页面之前,用jq将当前的页面内容给加载到iframe中去,这个时候,你的iframe中的html元素,就是你当前页面的html元素没错把?这时候再加载你需要ajax加载的页面。注意,加载页面的时候千万不要把这个iframe给覆盖掉了。。。 再写一个键盘后退按键的js监控方法,当按下@H_301_10@backspace的时候,将iframe的页面元素加载出来覆盖当前页面,在覆盖之前记得要把现在的页面元素覆盖到iframe中,因为你还有一个前进的操作 前进的操作也是大同小异,说白了就是父页面元素与iframe中的页面元素进行对换的操作@H_301_10@
*/
<!DOCTYPE html>
<html>
<head>
<title></title>
<Meta charset="utf-8">
<style type="text/css">
.tab {
display: inline;
}
.tab a {
color: #fff;
background: #333;
padding: 5px 10px;
border-left: 1px solid #fff;
}
.tab .selected {
color: red;
background: #cecece;
}
.content {
background: #cecece;
width: 50%;
margin-top: 5px;
padding: 10px;
}
pre {
border: 1px inset gray;
height: 20em;
}
</style>
</head>
<body >
<script type="text/javascript">
function Ajax (params) {
if (params) {
this.XMLHttp = params.XMLHttp;
this.method = params.method;
}
this.onsuccess = null;
this.responseType = 'text';
}
Ajax.prototype = {
getXMLHttp : function () {
if (!this.XMLHttp) {
if (window.XMLHttpRequest) {
// code for IE7+,Firefox,Chrome,Opera,Safari
return new XMLHttpRequest();
} else {// code for IE6,IE5
return new ActiveXObject("Microsoft.XMLHTTP");
}
}
return this.XMLHttp;
},
request : function (url,data) {
var self = this;
try {
var http = this.getXMLHttp();
//make a connection to the server ... specifying that you intend to make a GET request
//to the server. Specifiy the page name and the URL parameters to send
var param = '';
for (var item in data) {
param += (item + '=' + data[item] + '&');
}
url += ( (url.indexOf('?') != -1) ? '&' : '?' ) + param;
var urlLen = url.length;
if (url.substr(urlLen - 1,urlLen) == '&') {
url = url.substr(0,urlLen - 1);
}
http.open(this.method,url);
//assign a handler for the response
http.onreadystatechange = function() {
self.response(http);
}
//actually send the request to the server
http.send(null);
} catch (e) {
alert(e.message);
}
},
get : function (url,data,type,onsuccess) {
this.method = 'GET';
this.responseType = type || this.responseType;
this.onsuccess = onsuccess;
this.request(url,data);
},
post : function (url,onsuccess) {
this.method = 'POST';
this.responseType = type || this.responseType;
this.onsuccess = onsuccess;
this.request(url,
response : function(http) {
if (http.readyState == 4) {
// 4 = "loaded"
if (http.status == 200) {
// 200 = OK
this.onloadDone(http);
} else {
this.onerror('加载失败');
}
}
},
onloadDone : function(http) {
// var data = http.responseText || http.responseXML;
var data = this.responseType.toLowerCase() == 'xml' ? http.responseXML : http.responseText;
this.onsuccess.call(this,
onerror : function (message) {
alert("Problem retrieving XML data");
if (this.onerror) {
this.onerror.call(this,message);
}
}
}
var Com = {
isIE6 : (/MSIE 6/.test(navigator.appVersion)),
hasHashchange : function() {
if ("onhashchange" in window) {
return true;
}
return false;
}
};
function PageLoad () {
this.iframeObj = null;
this.iframeWin = null;
this.iframeSrc = this.iframeSrc || 'history.html';
this.location = this.location || window.location;
this.tab = null;
this.output = null;
this.tabs = null;
}
PageLoad.prototype = {@H_301_10@
@H_301_10@
create : function() {@H_301_10@
if (Com.hasHashchange) {@H_301_10@
return;@H_301_10@
}@H_301_10@
if (!this.iframeObj) {@H_301_10@
var ifr = document.createElement_x('iframe');@H_301_10@
ifr.name = 'hashIframe';@H_301_10@
ifr.id = 'HashIframe';@H_301_10@
ifr.style.display = 'block';@H_301_10@
document.body.appendChild(ifr);@H_301_10@
}@H_301_10@
@H_301_10@
},@H_301_10@
@H_301_10@
bindTabEvent : function() {@H_301_10@
var self = this;@H_301_10@
try {@H_301_10@
var tabs = this.tabs;@H_301_10@
for (var i = 0,l = tabs.length; i < l; i++) {@H_301_10@
tabs[i].onclick = function(evt) {@H_301_10@
var ele = (event.srcElement || event.target || evt.srcElement);@H_301_10@
var tg = self.toogleTab(ele);@H_301_10@
return false;@H_301_10@
}@H_301_10@
}@H_301_10@
} catch (e) {@H_301_10@
alert(e);@H_301_10@
}@H_301_10@
},@H_301_10@
@H_301_10@
bindHashEvent : function() {@H_301_10@
// bind onhashchange event@H_301_10@
var self = this;@H_301_10@
onhashchange = function() {@H_301_10@
self.pageLoadDone();@H_301_10@
}@H_301_10@
},@H_301_10@
@H_301_10@
bindIframeEvent : function() {@H_301_10@
var self = this;@H_301_10@
var ifr = self.iframeObj;@H_301_10@
var ifrWind = self.iframeWin;@H_301_10@
@H_301_10@
if (ifr.attachEvent) {@H_301_10@
ifr.attachEvent('onload',function() { @H_301_10@
self.iframeLoadDone();@H_301_10@
});@H_301_10@
} else {@H_301_10@
ifr.onload = function() {@H_301_10@
// self.iframeLoadDone.call(this,self);@H_301_10@
self.iframeLoadDone();@H_301_10@
};@H_301_10@
}@H_301_10@
},@H_301_10@
@H_301_10@
loadDefaultPage : function() {@H_301_10@
var tabname = 'tab1';@H_301_10@
if (Com.hasHashchange) {@H_301_10@
if (this.getHash() == '') {@H_301_10@
// 如果页面hash值为空,则更改hash为初始化的值@H_301_10@
this.setHash(tabname);@H_301_10@
} else {@H_301_10@
// 如果是带hash访问则直接通过hash值回溯页面@H_301_10@
var tab = this.getHash().split('#')[1];@H_301_10@
this.loadDone(tab);@H_301_10@
}@H_301_10@
} else {@H_301_10@
// 如果是不支持onhashchange的浏览器,如ie6等采用iframe@H_301_10@
this.iframeObj.src = this.iframeSrc + '?tab=' + tabname;@H_301_10@
}@H_301_10@
@H_301_10@
},@H_301_10@
@H_301_10@
init : function() {@H_301_10@
if (!this.iframeObj) {@H_301_10@
this.create();@H_301_10@
}@H_301_10@
@H_301_10@
this.iframeObj = document.getElementByIdx_x('HashIframe');@H_301_10@
this.iframeWin = window.frames['hashIframe'];@H_301_10@
@H_301_10@
this.tab = document.getElementByIdx_x('tab');@H_301_10@
this.output = document.getElementByIdx_x('output');@H_301_10@
this.tabs = this.tab.getElementsByTagName_r('a');@H_301_10@
@H_301_10@
this.bindTabEvent();@H_301_10@
if (Com.hasHashchange) {@H_301_10@
this.bindHashEvent();@H_301_10@
} else {@H_301_10@
this.bindIframeEvent();@H_301_10@
}@H_301_10@
this.loadDefaultPage();@H_301_10@
},@H_301_10@
@H_301_10@
loadDone : function(tab) {@H_301_10@
if ('string' != typeof tab) {@H_301_10@
return;@H_301_10@
}@H_301_10@
try {@H_301_10@
var idx = tab.substr(3) - 1;@H_301_10@
var tabs = this.tabs;@H_301_10@
@H_301_10@
var _callBack = function(data) {@H_301_10@
output.innerHTML = data;@H_301_10@
}@H_301_10@
@H_301_10@
this.getContent(tabs[idx],_callBack);@H_301_10@
this.toggle(tabs[idx]);@H_301_10@
@H_301_10@
@H_301_10@
@H_301_10@
@H_301_10@
} catch (e) {@H_301_10@
alert(e.message);@H_301_10@
}@H_301_10@
@H_301_10@
},@H_301_10@
@H_301_10@
pageLoadDone : function() {@H_301_10@
var hash = this.getHash();@H_301_10@
tab = hash.split('#')[1];@H_301_10@
this.loadDone(tab);@H_301_10@
},@H_301_10@
@H_301_10@
iframeLoadDone : function() {@H_301_10@
var hash = this.iframeWin.location.search;@H_301_10@
var tab = hash.split('=')[1];@H_301_10@
this.loadDone(tab);@H_301_10@
@H_301_10@
},@H_301_10@
@H_301_10@
toggle : function(ele) {@H_301_10@
var tabs = this.tabs;@H_301_10@
var idx = 0;@H_301_10@
for (var i = 0,l = tabs.length; i < l; i++) {@H_301_10@
if (ele != tabs[i]) {@H_301_10@
tabs[i].className = '';@H_301_10@
} else {@H_301_10@
tabs[i].className = 'selected';@H_301_10@
}@H_301_10@
}@H_301_10@
},@H_301_10@
@H_301_10@
toogleTab : function (ele) {@H_301_10@
// 更改hash,以便浏览器监听@H_301_10@
if ( !(ele.nodeType == 1) ) {@H_301_10@
return false;@H_301_10@
}@H_301_10@
var tabname = ele.getAttribute('tabname');@H_301_10@
@H_301_10@
this.setSelectedTab(tabname);@H_301_10@
this.toggle(ele);@H_301_10@
@H_301_10@
return false;@H_301_10@
},@H_301_10@
@H_301_10@
setHash : function(hash) {@H_301_10@
//window.location = 'location.html#tab=tab' + idx;@H_301_10@
// window.location.hash = hash;@H_301_10@
window.location.hash = hash;@H_301_10@
},@H_301_10@
@H_301_10@
getHash : function() {@H_301_10@
var hash = window.location.hash;@H_301_10@
return hash;@H_301_10@
},@H_301_10@
@H_301_10@
setSelectedTab : function(tabname) {@H_301_10@
if (Com.hasHashchange) {@H_301_10@
this.setHash(tabname);@H_301_10@
} else {@H_301_10@
this.iframeObj.src = this.iframeSrc + '?tab=' + tabname;@H_301_10@
}@H_301_10@
},@H_301_10@
@H_301_10@
getContentByTarget : function(evt,callBackFun) {@H_301_10@
this.getContent(evt.srcElement);@H_301_10@
},@H_301_10@
@H_301_10@
getContent : function(ele,callBackFun) {@H_301_10@
var ajax = new Ajax();@H_301_10@
var output = this.output;@H_301_10@
@H_301_10@
var _callBack = function(data) {@H_301_10@
if (typeof callBackFun == 'function') {@H_301_10@
callBackFun(data);@H_301_10@
} else {@H_301_10@
// output.innerHTML = data;@H_301_10@
}@H_301_10@
};@H_301_10@
@H_301_10@
output.innerHTML = 'loading...';@H_301_10@
@H_301_10@
var url = ele.href + '?t=' + Math.random() * 100;@H_301_10@
var data = { item : ele.href,'href' : ele.href };@H_301_10@
ajax.get(url,'json',_callBack );@H_301_10@
}@H_301_10@
@H_301_10@
}@H_301_10@
window.onload = function() {
new PageLoad().init();
}
</script>
<br>
<h1>Ajax浏览器前进后退</h1>
<h4>
本例通过隐藏location hash来实现前进后退,更改location.hash,然后通过onhashchange事件来监听hash变化,通过hash值来还原页面,不支持onhashchange事件的浏览器如ie6还是需要通过iframe模拟来实现。<a href="location2.html">查看iframe版本</a></h4>
<div class="tab" id="tab">
<a href="data1.txt" tabname="tab1" class="selected">tab1</a><a href="data2.txt" tabname="tab2">tab2</a><a tabname="tab3" href="data3.txt">tab3</a>
</div>
<div class="content">
<pre id="output">
<strong>Loading Ajax接收显示的内容:</strong>
</pre>
</div>
</body>
</html>