AJAX動態內容支援回上頁-HTML5篇
3 | 34,196 |
昨天提到在AJAX情境支援回上頁的做法,Ammon馬上補充重要資訊(再次感謝!!) --- 針對AJAX模式下記錄瀏覽歷程的需求,HTML5 history物件已增加了新功能。(詳情可參考MDN文件)
jQuery BBQ透過pushState(), getState()及hashchage事件實現AJAX變動歷程的記錄,而HTML5則是在既有history物件上增加了pushState()、replaceState()方法、state屬性,並在window物件新增onpopstate事件。
hisotry.pushState()接受三個參數state、title與url,跟jQuery.bbq.pushState()的用途相似,用來在瀏覽歷程新增一筆記錄,但HTML5瀏覽器還提供了額外的強化:
- state內容被保存在瀏覽器內部,因此不需要在URL加上讓使用者困惑的hash字串(如: #s=v)
- title可設定該筆歷史記錄的標題(但Firefox還沒支援)
- url參數十分有趣,它可以用來修改目前的URL網址。例如: 在/WebApp/list清單網頁點選第3筆後,透過pushState()傳入url參數可把URL改成/WebApp/detail/3,當下瀏覽器的地址列及瀏覽歷史裡的記錄都會被更換成/WebApp/detail/3。但這類應用需配合URL Rewriting或Routing機制,且不能亂設一通,否則稍後使用者按回上頁時要存取/WebApp/detail/3時就會被判定網頁不存在而傳回HTTP 404,那就糗了。
history.state等同於jQuery.bbq.getState(),可以取回該筆瀏覽歷程記錄所儲存的狀態物件。
history.replaceState()的參數及概念與history.pushState()相似,差別在於它只更新目前瀏覽歷程記錄的state、title及url,而不會增加新的歷程記錄。(這個功能是用hash無法實現的,當hash不同,就會因URL不同被瀏覽器視為另一筆瀏覽歷程)
onpopstate事件的概念則類似onhashchage,在呼叫history.pushState(), history.replaceState()或使用者按回上頁/回下頁時都會被觸發。
我寫了一個示範網頁:
<!DOCTYPE html>
<html>
<head>
<title>HTML 5 hisotry Demo</title>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.3.js"> </script>
<script>
$(function () {
if (typeof(history.pushState) == "undefined") {
$("body").html(
"<div>您的瀏覽器不支援HTML5 history新功能," +
"請前往<a href='Html5History2.htm'>相容版</a></div>");
}
function writeLog(m) {
$("#ulLog").append("<li>" + m + "</li>");
}
$(window).bind("popstate", function () {
writeLog("popstate event!");
});
$(":button").click(function () {
var st = $("#txtState").val();
var url = $("#txtUrl").val();
switch (this.id) {
case "btnPushState":
history.pushState({ "v": st }, "", url);
break;
case "btnReplaceState":
history.replaceState({ "v": st }, "", url);
break;
case "btnGetState":
writeLog(JSON.stringify(history.state));
break;
}
});
});
</script>
</head>
<body>
<table>
<tr><td>State</td><td><input id="txtState" /></td></tr>
<tr><td>Url</td><td><input id="txtUrl" /></td></tr>
<tr><td> </td>
<td>
<input type="button" id="btnPushState" value="Push State" />
<input type="button" id="btnReplaceState" value="Replace State" />
<input type="button" id="btnGetState" value="Get State" />
</td>
</tr>
</table>
<ul id="ulLog"></ul>
</body>
</html>
如上圖所示,透過HTML5 history的新功能,我們可在URL乾乾淨淨的情況下增加瀏覽歷程並保存該歷程的狀態資料,而且還可將URL調成任何想要的樣子。(不過亂改後在回上頁會發生HTTP 404(找不到網頁)的狀況就是了)
好消息是IE10、Firefox、Chrome、Safari的最新版都已支援HTML5 history新功能了! (線上展示)
壞消息是IE7/8/9還不支援hisotory的HTML5新功能!! 因此現階段還是得透過額外加掛History.js等相容程式庫維持跨瀏覽器相容。
如以下程式範例,由於history.js的作者將功能模組化,所以有多個js檔需要載入,而在使用時,也要以新增加的History物件取代內建的window.history物件以維持通透性,history.state則要用History.getHash()取代(範例中則還是用getState(),突顯getSate()可取得比getHash()更完整的資訊),而onpopstate事件則要改用onstatechange。
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.3.js"> </script>
<script src="scripts/json2.js"></script>
<script src="scripts/history.jquery.adapter.js"></script>
<script src="scripts/history.js"></script>
<script src="scripts/history.html4.js"></script>
<script>
$(function () {
function writeLog(m) {
$("#ulLog").append("<li>" + m + "</li>");
}
$(window).bind("statechange", function () {
writeLog("statechange event!");
});
$(":button").click(function () {
var st = $("#txtState").val();
var url = $("#txtUrl").val();
switch (this.id) {
case "btnPushState":
History.pushState({ "v": st }, "", url);
break;
case "btnReplaceState":
History.replaceState({ "v": st }, "", url);
break;
case "btnGetState":
writeLog(JSON.stringify(History.getState()));
break;
}
});
});
</script>
在HTML4瀏覽器執行時,還是要迴歸用hash方式實現狀態保存及瀏覽歷程新增的效果,而URL也無法被任意修改,跟jQuery BBQ的效果差不多。以此看來,在限定瀏覽器平台的前題下或等待瀏覽器全面HTML5化之後,HTML5 history的新功能才能充分發揮其效。
Comments
# by ChaN
希望 HTML 可以趕快普及~
# by Samuel
不知道還有什麼方法可以判斷有無支援HTML5? 除了判斷pustate是否undefinedu以外...
# by Jeffrey
to Samuel, 早期的JS會用檢查瀏覽器版號加Hard-Coding來決定瀏覽器支援哪些功能,但現在較主流的做法是直接檢測某個物件或方法是否存在加以判斷,比查版號更精確,且不受瀏覽器改版或客制化停用/啟用的影響。因此,檢查History.pushState是否存在應是不錯的做法,或是你還有其他考量?