談談HTML5中的history.pushSate方法,彌補ajax導致瀏覽器前進后退無效的問題


移動端為了減少頁面請求,有時候需要通過單頁面做成多頁面的效果,最近有這么個需求,表單填完后執行第一步,然后執行第二步,第二步執行完后再執行第三步,每一步都要保留之前的數據。這種情況用單頁面實現再合適不過了。

一般都是通過修改URL的hash,然后通過監聽hashchange來達到模擬切換頁面的效果。搞定之后,客戶端也就是高大上的IOS開發工程師說獲取不到webview的history,擦,hashchange明明會產生瀏覽器的history,怎么會獲取不到,哥之前一直都這么做的,也沒有客戶端的說獲取不到啊,是你自己不知道怎么獲取吧....當然,這話是在心里說的。他還把這事給經理說了....我去,然后我就知道了還有HTML5中pushstate這么個玩意。

先回顧下window.history吧。

History 對象

History 對象包含用戶(在瀏覽器窗口中)訪問過的 URL。

History 對象是 window 對象的一部分,可通過 window.history 屬性對其進行訪問。

注釋:沒有應用於 History 對象的公開標准,不過所有瀏覽器都支持該對象。

History 對象屬性

length:返回瀏覽器歷史列表中的 URL 數量。

History 對象方法

back():加載 history 列表中的前一個 URL。即后退

forward():加載 history 列表中的下一個 URL。即前進

go():加載 history 列表中的某個具體頁面。這個是最常用的

 

History 對象最初設計來表示窗口的瀏覽歷史。但出於隱私方面的原因,History 對象不再允許腳本訪問已經訪問過的實際 URL。

咱們來接着說兩個HTML5 history新增的好哥們:History.pushState()History.replaceState()

history.pushState(state, title, url)

意思就是把一個history記錄插入到歷史記錄中。

state:與要跳轉到的URL對應的狀態信息。

title:頁面標題。

url:要跳轉到的URL地址,不能跨域。

history.replaceState(state, title, url)

用新的state和URL替換當前。不會造成頁面刷新。

state:與要跳轉到的URL對應的狀態信息。

title:頁面標題。

url:要跳轉到的URL地址,不能跨域。

window.onpopstate

history.go和history.back(包括用戶按瀏覽器歷史前進后退按鈕)觸發,並且頁面無刷的時候(由於使用pushState修改了history)會觸發popstate事件,事件發生時瀏覽器會從history中取出URL和對應的state對象替換當前的URL和history.state。通過event.state也可以獲取history.state。

大致的思路就是自己創建一個對象記錄,然后把它插入到瀏覽器的歷史記錄,點擊瀏覽器的前進后退按鈕會觸發onpopstate,然后判斷當前的記錄做對應的操作。

與傳統的AJAX的區別

傳統的ajax有如下的問題:

雖然ajax可以無刷新改變頁面內容,但無法改變頁面URL

其次為了更好的可訪問性,內容發生改變后,改變URL的hash。但是hash的方式不能很好的處理瀏覽器的前進、后退等問題 

有的瀏覽器引入了onhashchange的接口,不支持的瀏覽器只能定時去判斷hash是否改變

再有,ajax的使用對搜索引擎很不友好,往往蜘蛛爬到的區域是空的

為了解決傳統ajax帶來的問題,HTML5里引入了新的API,即:history.pushState, history.replaceState

可以通過pushState和replaceState接口操作瀏覽器歷史,並且改變當前頁面的URL。

pushState是將指定的URL添加到瀏覽器歷史里,replaceState是將指定的URL替換當前的URL。

 

注意事項:

1、onpopstate只有在點擊瀏覽器的前期和后退才會觸發;

2、pushState能夠改變瀏覽器地址欄中的hash,但是它不會觸發hashchange事件,所以想通過監聽hashchange來執行是無效的。

3、pushState不會刷新頁面,刷新頁面咱就壓根不會用它了。

本地一個簡單實例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>pushState</title>
    <style type="text/css">
    .hidden {
        display: none;
    }
    </style>
    <script type="text/javascript" src="zepto.min.js"></script>
</head>

<body>
    <section id="step1" class="step-contain" step="1">
        <p>第1步</p>
        <button class="step-btn" step="1">下一步</button>
    </section>
    <section id="step2" class="step-contain hidden" step="2">
        <p>第2步</p>
        <button class="step-btn" step="2">下一步</button>
    </section>
    <section id="step3" class="step-contain hidden" step="3">
        <p>第3步</p>
    </section>
    <script type="text/javascript">
    $(function() {
        stepProgress();

        function stepProgress() {
            var options = {
                curStep: 1,
                nextStep: null
            }
            var defaultState={
                "step": options.curStep,
                 "url": "#step=" + options.curStep
            }
            window.history.pushState(defaultState, "", defaultState.url);
            $(".step-btn").on("click", function() {
                var step = parseInt($(this).attr("step"));
                options.nextStep = step + 1;
                var state = {
                    "step": options.nextStep,
                    "url": "#step=" + options.nextStep
                }
                window.history.pushState(state, "", state.url);
                console.log(state.step)
                swapStaus(options.nextStep);
            });

            function swapStaus(step) {
                $(".step-contain").each(function() {
                    var tmpStep = $(this).attr("step");
                    if (parseInt(tmpStep) == step) {
                        $("#step" + tmpStep).removeClass("hidden");
                    } else {
                        $("#step" + tmpStep).addClass("hidden");
                    }
                });
                options.curStep = step;
            }

            $(window).on("popstate",function(){
                var currentState = history.state;
                goStep=currentState.step?currentState.step:1;
                swapStaus(goStep)
            })
        }

    })
    </script>
</body>

</html>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM