經過history.pushState無刷新改變urljavascript
在瀏覽器中改變地址欄url,將會觸發頁面資源的從新加載,這使得咱們能夠在不一樣的頁面間進行跳轉,得以瀏覽不一樣的內容。但隨着單頁應用的增多,愈來愈多的網站採用ajax來加載資源。由於異步加載的特性,地址欄上的資源路徑沒有被改變,隨之而來的問題就是頁面的狀態沒法被保存。這致使咱們難以經過熟悉的方式(點擊瀏覽器前進/後退按鈕),在先後的頁面狀態間進行切換。
爲了解決ajax頁面狀態不能返回的問題,人們想出了一些曲線救國的方法,好比利用瀏覽器hash的特性,將新的資源路徑假裝成錨點,經過onhashchange
事件來改變狀態,同時又避免了瀏覽器刷新。但這樣始終顯得有些hack。
如今HTML5規範爲 window.history
引入了兩個新api,pushState
和 replaceState
,咱們可使用它很方便的達到改變url不重載頁面的目的。css
改變地址欄url,不刷新頁面。
觀察地址欄,能夠看到當url路徑由」join」改變爲」login」時,頁面狀態也隨之改變,但並無形成背景圖片等資源的從新加載。
此時」join」被壓入歷史棧,當點擊瀏覽器後退按鈕時仍然可以回到」join」狀態。html
pushState
與replaceState
方法相似,都有改變當前地址欄URL的做用。主要區別在於pushState
會在瀏覽器中建立一條新的歷史紀錄,而replaceState
僅僅替換將當前地址爲指定URL。
下面以pushState
接口爲例:java
history.pushState(state, title[, url]);
web
執行history.back()
或history.forward()
後觸發 window.onpopstate
事件ajax
state: 對象,能夠存存放一些數據表示當前狀態。當瀏覽器執行前進後退操做時觸發onpopstate
事件,state將成爲event
的子對象,可經過event.state
獲取先前狀態。可是注意state中的屬性值不能爲引用類型對象,會報ObjectCloneError
(對象克隆異常),例如容許{data:」test」},不容許{data:document.querySelector(‘#testId’)}。
title:目前無特殊意義,通常能夠傳入 document.title
或 」(空字符串)。
url:要替換的url,若是是pushState
則會添加一條歷史記錄,不容許跨域。chrome
history.pushState({title:"login"}, "login", "fish/login"); window.addEventListener("popstate", function(event){ if(event.state) { var state = event.state.title; switch(state) { case "login":.............;break; case "join" :.............;break; case "home" :.............;break; } } }, false);
下面以一個具體實例來展現pushState
的做用,注意地址欄的變化。api
兩次點擊白色圓環改變頁面背景,將在當前瀏覽器歷史會話(window.history
)中寫入兩條新記錄:「/pushState.html?state=blue」和「/pushState.html?state=org」。
點擊瀏覽器後退/前進按鈕至關於執行history.back()
與history.forward()
方法,將觸發onpopstate
事件,經過監聽onpopstate
事件改變相應狀態。跨域
本實例在Chrome下編寫調試,請在Chrome、Firefox、IE10+等現代瀏覽器中運行。瀏覽器
<!DOCTYPE html> <html> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"> <meta name="renderer" content="webkit" /> <head> <title>pushState demo</title> <style> body { font-family: "Microsoft YaHei"; transition: background-color .3s; } .bg-org { color: #383c3c; background-color: #FF6633; } .bg-blue { color: #fbfaf5; background-color: #6699FF; } .time { margin-top: 20%; text-align: center; font-size: 4em; font-weight: 100; } .switch { margin: auto; width: 30px; height: 30px; position:absolute; bottom:25%; left:0; right:0; cursor:pointer; box-shadow: 0 0 0 5px rgba(255,255,255,.6); border-radius: 50%; transition: box-shadow .1s; } .switch:hover { box-shadow: 0 0 0 5px rgba(255,255,255,.75); } .switch:active { box-shadow: 0 0 0 30px rgba(255,255,255,.4); } </style> </head> <body class="bg-org"> <h1 id="time" class="time">Loading...</h1> <div id="switch" class="switch"></div> <script> var time = $('#time'); function $(selector) {return document.querySelector(selector);} // 顯示當前時間 setInterval(function(){ var date = new Date(), format = function(n) {return n<10?'0'+n:n}; time.innerHTML = format(date.getHours()) + ' : ' + format(date.getMinutes()) + ' : ' + format(date.getSeconds()); }, 500); $('#switch').addEventListener('click', toggleState, false); // 監聽popstate事件 history.pushState && window.addEventListener("popstate", function(e) { // 獲取history.state對象中的狀態信息 // 在這裏state將自動成爲event的子對象,可直接經過event.state訪問 var flag = e.state && e.state.title; $('body').className = flag || ($('body').className=='bg-org'?'bg-blue':'bg-org'); }, false); function toggleState(e) { var flag = $('body').className=='bg-org'?'bg-blue':'bg-org'; // 新建歷史記錄,將當前狀態信息保存至history.state中 history.pushState && history.pushState({ title: flag }, flag, 'pushState.html?state='+flag.split('-')[1]); $('body').className = flag; } </script> </body>