昨天提到在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瀏覽器還提供了額外的強化:

  1. state內容被保存在瀏覽器內部,因此不需要在URL加上讓使用者困惑的hash字串(如: #s=v)
  2. title可設定該筆歷史記錄的標題(但Firefox還沒支援)
  3. 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>&nbsp;</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是否存在應是不錯的做法,或是你還有其他考量?

Post a comment