【東網技術大咖】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對象和鏈接里的參數來進行不同的處理,以達到切換標簽的效果,用戶體驗時的感覺和前進后退是沒有任何差異的,由于沒有刷新頁面,體驗甚至會更好。
至此,問題得到圓滿解決。