移動端爲了減小頁面請求,有時候須要經過單頁面作成多頁面的效果,最近有這麼個需求,表單填完後執行第一步,而後執行第二步,第二步執行完後再執行第三步,每一步都要保留以前的數據。這種狀況用單頁面實現再合適不過了。javascript
通常都是經過修改URL的hash,而後經過監聽hashchange來達到模擬切換頁面的效果。搞定以後,客戶端也就是高大上的IOS開發工程師說獲取不到webview的history,擦,hashchange明明會產生瀏覽器的history,怎麼會獲取不到,哥以前一直都這麼作的,也沒有客戶端的說獲取不到啊,是你本身不知道怎麼獲取吧....固然,這話是在內心說的。他還把這事給經理說了....我去,而後我就知道了還有HTML5中pushstate這麼個玩意。css
先回顧下window.history吧。html
History 對象包含用戶(在瀏覽器窗口中)訪問過的 URL。java
History 對象是 window 對象的一部分,可經過 window.history 屬性對其進行訪問。web
註釋:沒有應用於 History 對象的公開標準,不過全部瀏覽器都支持該對象。ajax
length:返回瀏覽器歷史列表中的 URL 數量。跨域
back():加載 history 列表中的前一個 URL。即後退瀏覽器
forward():加載 history 列表中的下一個 URL。即前進ide
go():加載 history 列表中的某個具體頁面。這個是最經常使用的this
History 對象最初設計來表示窗口的瀏覽歷史。但出於隱私方面的緣由,History 對象再也不容許腳本訪問已經訪問過的實際 URL。
我們來接着說兩個HTML5 history新增的好哥們:History.pushState()和
History.replaceState()
意思就是把一個history記錄插入到歷史記錄中。
state:與要跳轉到的URL對應的狀態信息。
title:頁面標題。
url:要跳轉到的URL地址,不能跨域。
用新的state和URL替換當前。不會形成頁面刷新。
state:與要跳轉到的URL對應的狀態信息。
title:頁面標題。
url:要跳轉到的URL地址,不能跨域。
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。
注意事項:
一、onpopstate只有在點擊瀏覽器的前期和後退纔會觸發;
二、pushState可以改變瀏覽器地址欄中的hash,可是它不會觸發hashchange事件,因此想經過監聽hashchange來執行是無效的。
三、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>