【東網技(jì )術大咖】HTML5 history api搭配ajax實現前進後退
發布時間: 2017-04-01 15:16:39
AJAX即“Asynchronous Javascript And XML”(異步JavaScript和XML),是指一種創建交互式網頁(yè)應用(yòng)的網頁(yè)開發技(jì )術。通過在後台與服務(wù)器進行少量數據交換,AJAX 可(kě)以使網頁(yè)實現異步更新(xīn)。這意味着可(kě)以在不重新(xīn)加載整個網頁(yè)的情況下,對網頁(yè)的某部分(fēn)進行更新(xīn)。
在良品鋪子生命周期系統開發中(zhōng),遇到過這樣一種情況,我們使用(yòng)ajax來加載不同标簽頁(yè)的數據,用(yòng)戶在使用(yòng)的時候想用(yòng)前進後退來切換标簽頁(yè),發現直接退出了當前功能(néng),于是向我們反饋了這一問題。确實,在用(yòng)戶使用(yòng)中(zhōng),不同标簽頁(yè)的切換對于他(tā)們來說是意味着不同的頁(yè)面,自然而然會想前進後退來切換,但是實際中(zhōng)ajax是無法前進後退的,便造成很(hěn)糟糕的體(tǐ)驗,比如填好的表單後退後全部消失,查詢好的數據後退一下又(yòu)需要重新(xīn)查詢。
那麽如何解決這一問題呢(ne)?在實際開發中(zhōng),單純使用(yòng)ajax,浏覽器地址是不會發生變化,前進後退是無法控制标簽切換的,這個時候我們必須借助HTML5裏新(xīn)的history api搭配ajax來解決這個問題。
我們先來回顧一下現有(yǒu)html規範中(zhōng),history對象的三個方法:
方法 |
描述 |
back() |
加載 history 列表中(zhōng)的前一個 URL。 |
forward() |
加載 history 列表中(zhōng)的下一個 URL。 |
go() |
加載 history 列表中(zhōng)的某個具(jù)體(tǐ)頁(yè)面。 |
使用(yòng)ajax時,由于地址未發生變化,這三個api是無法進行頁(yè)面控制的。
新(xīn)的HTML5标準為(wèi)我們解決了這一難題,html5标準中(zhōng)history對象增加了兩個方法。
方法 |
描述 |
pushState() |
存儲當前曆史記錄點 |
replaceState() |
替換當前曆史記錄點 |
還有(yǒu)一個搭配使用(yòng)的popstate事件,用(yòng)于監聽url的變化。
pushState能(néng)改變當前url(添加新(xīn)的曆史記錄點),popstate監聽url的變化,浏覽器的前進後退改變url(在曆史記錄點之間切換),三者結合便能(néng)解決ajax中(zhōng)前進後退的問題。
讓我們先來看下pushState,replaceState,popstate這個三個新(xīn)的api的詳細介紹。
存儲的方式類似于數組的入棧(Array.push()),在window.history裏新(xīn)增一個曆史記錄點,例如:
// 當前的url為(wèi):http://www.example.com/demo.html
var json={time:new Date().getTime()};
//@狀态對象:記錄曆史記錄點的額外對象,可(kě)以為(wèi)空
//@頁(yè)面标題:目前所有(yǒu)浏覽器都不支持
//@可(kě)選的url:浏覽器不會檢查url是否存在,隻改變url,url必須同域,不能(néng)跨域
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方法後,頁(yè)面的url地址為(wèi):
http://www.example.com/demo.html#test
window.history.replaceState和window.history.pushState類似,不同之處在于replaceState不會在window.history裏新(xīn)增曆史記錄點,其效果類似于window.location.replace(url),都是不會在曆史記錄點裏新(xīn)增一個記錄點的。當你為(wèi)了響應用(yòng)戶的某些操作(zuò),而要更新(xīn)當前曆史記錄條目的狀态對象或URL時,使用(yòng)replaceState()方法會特别合适。
監聽曆史記錄點,直觀的可(kě)認為(wèi)是監聽URL的變化,但會忽略URL的hash部分(fēn),可(kě)以通過window.onpopstate來監聽url的變化,并且可(kě)以獲取存儲在該曆史記錄點的狀态對象,也就是上文(wén)說到的json對象。
值得注意的是:window.history.pushState和window.history.replaceState不會觸發onpopstate事件。
了解了這三個新(xīn)的api,再讓我們看看如何實際開發中(zhōng)來進行應用(yòng)。
一個分(fēn)頁(yè)的例子,點擊不同頁(yè)面使用(yòng)ajax加載不同的地市編号和地市名(míng)稱,默認加載第一頁(yè),如果帶有(yǒu)頁(yè)碼n會加載第n頁(yè)的數據,前進後退能(néng)夠在不同頁(yè)面進行切換
頁(yè)面部分(fē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();
效果截圖:
可(kě)以看到,浏覽器裏面的鏈接變為(wèi)url+#+頁(yè)碼,這個時候可(kě)以通過前進後退來觸發onpopstate 來實現ajax加載不同頁(yè)面的數據,監聽事件觸發後可(kě)以根據json對象和鏈接裏的參數來進行不同的處理(lǐ),以達到切換标簽的效果,用(yòng)戶體(tǐ)驗時的感覺和前進後退是沒有(yǒu)任何差異的,由于沒有(yǒu)刷新(xīn)頁(yè)面,體(tǐ)驗甚至會更好。
至此,問題得到圓滿解決。