H5系列之History(必知必會)


H5系列之History(必知必會)
 
目錄
 

 
 
概念
 
 
  • 理解History Api的使用方式
  • 目的是為了解決哪些問題
 
作用:ajax獲取數據時,可以改變歷史記錄,從而可以使用瀏覽器的后退和前進。
 
【】
 
 
【01】 History 對象
 
【】Window對象的history屬性引用的是該窗口的History對象。
 
【】 History 對象包含用戶(在瀏覽器窗口中)訪問過的 URL。
History 對象是 window 對象的一部分,可通過 window.history 屬性對其進行訪問。
注釋:沒有應用於 History 對象的公開標准,不過所有瀏覽器都支持該對象。
 
History接口允許操作瀏覽器的曾經在標簽頁或者框架里訪問的會話歷史記錄。
 
 
History 對象最初設計來表示窗口的瀏覽歷史。
但出於隱私方面的原因,History 對象不再允許腳本訪問已經訪問過的實際 URL。
 

 
history對象保存着用戶上網的歷史記錄,從窗口被打開的那一刻算起。
因為history是window對象的屬性,因此每個瀏覽器窗口、每個標簽頁乃至每個框架,都有自己的history對象與特定的window對象關聯。
 
出於安全方面的考慮,開發人員無法得知用戶瀏覽過的URL。(如果允許,則任意腳本都可以窺探你的瀏覽歷史。)
 
不過,借由用戶訪問過的頁面列表,同樣可以在不知道實際URL的情況下實現后退和前進。
 
 
 
【】back()和forward(),頁面通常是從瀏覽器緩存中加載,而不是重新要求服務器發送新的請求。
 
【】雖然history並不常用,但在創建自定義的“后退”和“前進”按鈕,以及檢測當前頁面是不是用戶歷史記錄中的第一個頁面時,還是必須使用它。
當頁面的URL改變時,就會生成一條歷史記錄。
 
在IE8及更高版本、Opera、Firefox、Safari 3及更高版本以及Chrome中,這里所說的改變包括URL中hash的變化(因此,設置location.hash會在這些瀏覽器中生成一條新的歷史記錄)。
 
 

【01】

History API
 
Web應用通常都是動態地生成或載入頁面內容,並在無須刷新頁面的情況下就顯示新的應用狀態。
如果想要提供用戶能夠通過瀏覽器的“后退”和“前進”按鈕,直觀地切換應用狀態,像這類應用就必須自己處理應用的歷史記錄管理。
 
【】
Ajax有一個問題一直困擾着開發者, 就是網頁狀態無法被添加到歷史記錄中 ,這意味着用戶 不能通過瀏覽器的“前進”和“后退”按鈕前進或者退回到某個狀態。
 
【】可以在歷史記錄 中添加狀態或改變狀態
 
【】可以使用JavaScript來部分更新頁面,又能更新地址欄和瀏覽 器歷史記錄。
 
 
【】使用History API實現了地址欄改變而頁面不跳轉的效果。
 
【】 而通過狀態管理API,能夠在不加載新頁面的情況下改變瀏覽器的URL。
 
 

【】在使用HTML5的狀態管理機制時,請確保使用pushState()創造的每一個“假”URL,在Web服務器上都有一個真的、實際存在的URL與之對應。否則,單擊“刷新”按鈕會導致404錯誤。

 
 

 
 
【】可能犯的一個錯誤
 
 
如果你遇到使用History API沒有起作用的情況,可以嘗試用try catch來試着捕獲異常。
 
很可能會發現異常顯示為SECURITY_ERR:DOM Exceptin 18。
 
這是由於History API采用同源控 制策略來保證安全性,避免惡意網站修改用戶其他網站的歷史記錄。
 
出現這種情況的原因是你 沒有正確設置URL或者使用本地頁面,History API認為你修改的是另外一個域名的歷史記錄。
 
 

 

先來看看"history"接口的詳細方法:

interface History {
   readonly attribute long length;
   readonly attribute any state;
   void go(optional long delta);
   void back();
   void forward();
   void pushState(any data, DOMString title, optional DOMString? url = null);
   void replaceState(any data, DOMString title, optional DOMString? url = null);
 };
 

 
 
HTML5定義了兩種用於歷史記錄管理的機制。
 
其中比較簡單的歷史記錄管理技術就是利用location.hash和hashchange事件。
 
 
設置location.hash屬性會更新顯示在地址欄中的URL,同時會在瀏覽器的歷史記錄中添加一條記錄。
hash屬性設置URL的片段標識符,通常是用於指定要滾動到的文檔中某一部分的ID。
 
 
 
 
但是location.hash不一定非要設置為一個元素的ID:
它可以設置成任何的字符串。
如果能夠將應用狀態編碼成一個字符串,就可以使用該字符串作為片段標識符。
 
設置了location.hash屬性后,接下來要實現允許用戶通過“后退”和“前進”按鈕來切換不同的文檔狀態。這個時候,應用必須要想辦法檢測狀態變化,以便它能夠讀取出存儲在片段標識符中的狀態並相應地更新自己的狀態。
 
支持HTML5的瀏覽器一旦發現片段標識符發生了改變,就會在Window對象上觸發一個hashchange事件。
 
這樣,在支持hashchange事件的瀏覽器中,就可以通過設置window.onhashchange為一個處理程序函數,使得每次由於切換歷史記錄導致片段標識符變化的時候,都會調用該處理程序函數。
當調用該處理程序函數的時候,就可以對location.hash的值進行解析,然后使用該值包含的狀態信息來重新顯示應用。
 
 

  為了提高Web頁面的響應速度,越來越多的開發者開始采用單頁面結構(single-page application)的解決方案。

所謂的單頁面結構就是指多個頁面間切換時,不刷新當前整個頁面,更新頁面展示數據,並且相應地改變地址欄中的url,以使用戶可以分享這個url。

  

如果你使用chrome或者firefox等瀏覽器訪問"github.com、plus.google.com"等網站時,細心的你會發現頁面之間的點擊是通過ajax異步請求的,

同時頁面的URL發生了改變。並且能夠很好的支持瀏覽器前進和后退。

 

 
 
【】如果窗口包含多個子窗口(比如<iframe>元素),子窗口的瀏覽歷史會按時間順序穿插在主窗口的歷史中。
這意味着在主窗口調用history.back()(舉例)可能會導致其中一個子窗口往回跳轉到前一個顯示的文檔,但主窗口保留當前狀態不變。
 
【】現代Web應用可以不通過載入新文檔而動態地改變自身內容(這么做可能希望用戶能用“后退”和“前進”按鈕在這些動態創建的應用狀態之間進行跳轉。)
 
【】HTML5之前的歷史管理是個更復雜的難題。
應用程序必須要在窗口瀏覽歷史中創建一個新的條目來管理自身的歷史記錄,用歷史條目關聯自身的狀態信息,判斷什么時候用戶使用了“后退”按鈕來移動到不同的歷史條目,聯合那個條目獲取狀態信息,並且重新創建應用程序之前的狀態。
 
 
【】一種方式是用隱藏的<iframe>來保存狀態信息並在瀏覽器的歷史中創建條目。
為了創建新的歷史條目,需要用Document對象的open()和write()方法動態地把一個新文檔寫入這個隱藏的窗體。
不管怎樣,文檔內容應該包含重新創建應用狀態所需要的狀態信息。當用戶單擊“后退”按鈕,隱藏的窗體的內容會改變。
在HTML5之前,沒有生成事件來通知你這個改變,因此,為了檢測用戶是否單擊了“后退”按鈕,可能要用setInterval()每秒對隱藏的窗體檢測兩到三次,來看它是否改變了。
 
【】在實際工作中,在那些需要以前的HTML5歷史管理的項目中,開發者通常會使用一些現成的解決方案。
很多JavaScript框架都實現了這種功能。比如,jQuery有history插件,另外也有些單獨的管理歷史記錄的類庫。
 

 


 
 
兼容性
 
 
【03】兼容性
 
Firefox 4+、Safari 5+、Opera 11.5+和Chrome8+
IE10支持。
 
 IOS 手機支持5.1+
安卓4.3+
 

為了用變成方式確定瀏覽器是否支持這個API,可以用下面的一行代碼檢驗:

return ! ! ( window .history &&history .pushState ) ;
 
 
 
 

如果你是用的現代瀏覽器,可以用下面的代碼:

if (Modernizr .history ) {
     / / History API Supported
}

如果你的瀏覽器不支持History API,可以使用history.js代替。

 
 
 
 
 
 

**

 

屬性

【02】
length 屬性
定義和用法
 
返回一個整數,該整數表示會話歷史中元素的數目,包括當前加載的頁。例如,在一個新的選項卡(瀏覽器)加載的一個頁面中,這個屬性返回1。

 
length 屬性聲明了瀏覽器歷史列表中的元素數量。
 
保存着歷史記錄的數量。這個數量包括所有歷史記錄,即所有向后和向前的記錄。對於加載到窗口、標簽頁或框架中的第一個頁面而言,history.length等於0。
 
通過像下面這樣測試該屬性的值,可以確定用戶是否一開始就打開了你的頁面。
if (history.length == 0){
    //這應該是用戶打開窗口后的第一個頁面
}
 
 
注釋:IE 6 和 Opera 9 以 0 開始,而 Firefox 1.5 以 1 開始。
 
語法
history.length
 
實例
<html>
<body>
<scripttype="text/javascript">     console.log(history.length); </script>
</body>
</html>
 
 
【】魔芋:chrome以1開始。
 

**

【02】state
 
History.state:
返回一個表示歷史堆棧頂部的狀態的值。這是一種可以不必等待popstate事件而查看狀態而的方式
 
 
用於存儲history.pushState(data)和history.repalceState(data)的data數據。
不同瀏覽器的讀寫權限不一樣。
 
 
history.pushState({name:"魔芋"},"moyu","moyu.html");
console.log(history.state);
 
 
 

 

 

**

【03】 scrollRestoration
 
 
 
History.scrollRestoration:
允許Web應用程序在歷史導航上顯示地設置默認滾動恢復行為。此屬性可以是自動的auto或者手動的manual
 
 
 
 
方法
【04】 forward() 方法
調用該方法的效果等價於點擊前進按鈕或調用 history.go(1)。
語法
定義和用法
forward() 方法可加載歷史列表中的下一個 URL。
history.forward()
 
等同於點擊瀏覽器的前進按鈕。
 
實例

下面的例子可以在頁面上創建一個前進按鈕:

<html>
<head>
<scripttype="text/javascript">functiongoForward() { window.history.forward() } </script>
</head>
<body>

<inputtype="button"value="Forward"onclick="goForward()" />

</body>
</html>
 
 
【03

back() 方法

 

定義和用法

back() 方法可加載歷史列表中的前一個 URL(如果存在)。

調用該方法的效果等價於點擊后退按鈕或調用 history.go(-1)。

 

等同於點擊瀏覽器的后退按鈕。

語法:

history.back()
 

例子:

<html>
<head>
<scripttype="text/javascript">functiongoBack() { window.history.back() } </script>
</head>
<body>

<inputtype="button"value="Back"onclick="goBack()" />

</body>
</html>
 
 

**

【05】go() 方法
 

定義和用法

go() 方法可加載歷史列表中的某個具體的頁面。

語法

history.go(number|URL)
 
 
負數表示向后跳轉(類似於單擊瀏覽器的“后退”按鈕),正數表示向前跳轉(類似於單擊瀏覽器的“前進”按鈕)。
history.go(-2);// 后退兩個歷史記錄,相當於單擊"后退"按鈕兩次
 
go(1) ;//前進一個;
 
go(-1) ; /后退一個;

說明

URL 參數使用的是要訪問的 URL,或 URL 的子串。而 number 參數使用的是要訪問的 URL 在 History 的 URL 列表中的相對位置。

 
使用go()方法可以在用戶的歷史記錄中任意跳轉,可以向后也可以向前。
這個方法接受一個參數,表示向后或向前跳轉的頁面數的一個整數值。
當整數參數超出界限時,例如:如果當前頁為第一頁,前面已經沒有頁面了,我傳參的值為-1,那么這個方法沒有任何效果也不會報錯。
調用沒有參數的go()方法或者不是整數的參數時也沒有效果。
 
 

也可以給go()方法傳遞一個字符串參數,此時瀏覽器會跳轉到歷史記錄中包含該字符串的第一個位置——可能后退,也可能前進,具體要看哪個位置最近。

如果歷史記錄中不包含該字符串,那么這個方法什么也不做,例如:

//跳轉到最近的wrox.com頁面
history.go("wrox.com");

//跳轉到最近的nczonline.net頁面
history.go("nczonline.net");
 
 
其中 history.go(0)相當於刷新當前頁面。
 

實例

下面例子會加載歷史列表中的前一個頁面:

<html>
<head>
<scripttype="text/javascript">functiongoBack() { window.history.go(-1) } </script>
</head>
<body>

<inputtype="button"value="Back"onclick="goBack()" />

</body>
</html>
 
 
 
H5方法
【01】 pushState()
用於向history對象添加當前頁面的記錄,並且改變瀏覽器地址欄的URL。
(魔芋:就是在歷史記錄里加入新的url地址, 瀏覽器地址欄也會變成新的相對URL
 
 
有3個參數,分別是state對象、 可選的 新狀態的 標題 (普通的文本字符串) 以及 可選參數目標URL。
 
state是一個JavaScript對象,記 錄要插入到歷史記錄條目的相關信息。
該對象可以是任何能夠通過JSON.stringify()方法轉換成相應字符串形式的對象,也可以是其他類似Date和RegExp這樣特定的本地類型。
而第一個參數則應該盡可能提供初始化頁面狀態所需的各種信息。state會在onpopstate事件觸發時作為參數傳遞過去。
 
 
 
該方法的第二個可選參數是一個可選的標題,瀏覽器可以使用它(比如,在一個<Back>菜單中)來標識瀏覽歷史記錄中保存的狀態。
 

但是,瀏覽器並不會真的向服務器發送請求,即使狀態改變之后查詢location.href也會返回與地址欄中相同的地址。

另外,第二個參數目前還沒有瀏覽器實現,因此完全可以只傳入一個空字符串,或者一個短標題也可以。

 

 
該方法的第三個參數是一個可選的URL,表示當前狀態的位置。
相對的URL都是以文檔的當前位置為參照,通常該URL只是簡單地指定URL(諸如#state)這樣的hash(或者“片段標識符”)部分。
將一個URL和狀態關聯,可以允許用戶將應用的內部狀態作為書簽添加到瀏覽器中,並當在URL中包含足夠信息的時候,應用可以在從書簽中載入的時候就恢復它的狀態。
缺省為當前頁面地址。
新的網址,必須與當前頁處在同一個域。瀏覽器的地址欄將顯示這個網址。
 
 
 
 
 
pushState()的示例代碼如下:
 
 
history.pushState(javascriptObj,"some string","url");
 
例子:
history.pushState({username: "html5"}, "user account", "user.html");
 
注意 pushState()帶來地址欄的變化不會觸發 hash
(用過錨的開發者應該了解,URL #號后 面的部分就是hash。改變hash的值后,頁面不會跳轉到新頁面,也不會刷新)跳轉。
 
moyu:
我在b.html里面加上了
<script> history.pushState({username: "html5"}, "user account", "c.html"); console.log(history); </script>
結果:打開的是a.html頁面,但是地址欄為b.html。
不會跳轉到b.html。 也不會檢查b .html 是否存在,它只是成為瀏覽歷史中的最新記錄。
 
 打開谷歌瀏覽器的歷史記錄,你會發現有2條數據了。
 
 
 

 
pushState 方法不會觸發頁面刷新,只是導致 history 對象發生變化,地址欄會有反應。
 

如果pushStateurl參數,設置了一個新的錨點值(即hash),並不會觸發hashchange事件。如果設置了一個跨域網址,則會報錯。

history.pushState({title: 'twitter'}, 'twitter', 'https://twitter.com/moyu')

 

上面代碼中,pushState想要插入一個跨域的網址,導致報錯。

這樣設計的目的是,防止惡意代碼讓用戶以為他們是在另一個網站上。

 

 

 

 

在Safari和Chrome中,傳遞給pushState()replaceState()的狀態對象中不能包含DOM元素

而Firefox支持在狀態對象中包含DOM元素。

Opera還支持一個history.state屬性,它返回當前狀態的狀態對象。

 

 

 

【】pushState()方法接受一個狀態對象並為該對象創建一份私有副本。
 
這是對一個對象進行深拷貝或者深復制:它會遞歸地復制所有嵌套對象或者數組的內容。
 
HTML5標准將這類復制稱為“結構性復制”(structured clone)。
 
創建一個結構性復制的過程就好比是將一個對象傳遞給JSON.stringify()方法,然后再將結果字符串傳遞給JSON.parse()方法。
 
但是JSON只支持JavaScript的基礎類型和對象以及數組。
 
在HTML5標准中提到,結構性復制算法必須還能夠復制Date對象、RegExp對象、ImageData對象(來自<canvas>元素)、FileList對象、File對象以及Blob對象。
 
但是在結構性復制算法中會顯式排除JavaScript中的函數和錯誤以及絕大部分諸如窗口、文檔、元素等這類宿主對象。
 
或許還不會存儲文件或者圖片數據作為歷史狀態的一部分,但是結構性復制還被其他一些HTML5相關的標准用到。
 
 
 
 
 

**

【02】replaceState()
 
 
replaceState()類似於pushState(),只是將當前頁面狀態替換為新的狀態,示例代碼 如下:
調用這個方法不會在歷史狀態棧中創建新狀態,只會重寫當前狀態。
 
 
history.replaceState({username: "html5" }, "user account", "user.html");
 
截圖:
 
 
 

**

【03】onpopstate事件
【01】 另外,History API還提供了 onpopstate 事件,該事件在窗口歷史記錄改變時被觸發。
 
當用戶單擊瀏覽器的后退和前進按鈕時觸發該事件。
 
在事件處理函數中,讀取觸發觸發事件的事件對象的state屬性值。該屬性為pushState()的第一個參數值。
 
 
當你瀏覽會話歷史記錄時,不管你是點擊前進或者后退按鈕,還是使用history.go和history.back方法,popstate都會被觸發。
 

pushState()會創建新的歷史狀態,會發現“后退”按鈕也能使用了。

按下“后退”按鈕,會觸發window對象的popstate事件。

 
 
 
【】每當同一個文檔的瀏覽歷史(即history對象)發生變化時,就會觸發popstate事件。
 
需要特別注意的是,僅僅調用history.pushState()history.replaceState()方法時,並不會觸發popstate事件。
 
只有用戶點擊瀏覽器后退按鈕和前進按鈕,或者使用JavaScript調用history.back()history.forward()history.go()方法時才會觸發。
另外,popstate事件只針對同一個文檔,如果瀏覽器歷史的切換,導致加載不同的文檔,該事件也不會被觸發。
 
 
 
window的屬性事件么?魔芋
 
示例 代碼如下:
 
window.onpopstate = function(event){
    console.log(event.state); //輸出pushState()或者replaceState()設置的state信息
}
 

也可以這樣使用:

window.addEventListener('popstate', function(event) {
    console.log('location: ' + document.location)
    console.log('state: ' + JSON.stringify(event.state))   
})

 

 
 
 
演示在用JavaScript更新頁面內容時通過History API來改 變頁面地址和歷史記錄。
<div id="click-item"></div> 
<div id="result-item"></div> 
<script type="text/javascript"> var clickItem = document.getElementById('click-item'); var resultItem = document.getElementById('result-item'); clickItem.onclick = function(){     resultItem.innerHTML = 'clicked!';     history.pushState({note: 'set result'}, '', 'result.html'); } </script>
 
單擊click-item元素時,瀏覽器頁面地址將會變為result.html,同時瀏覽器的歷史記錄里也 會出現此頁面的訪問記錄。
 

popstate事件的事件對象有一個state屬性,這個屬性就包含着當初以第一個參數傳遞給pushState()的狀態對象。

popstate事件發生后,事件對象中的狀態對象(event.state)是當前狀態。

EventUtil.addHandler(window, "popstate", function(event){
    var state = event.state;
    if (state){   //第一個頁面加載時state為空
        processState(state);
    }
});
 

得到這個狀態對象后,必須把頁面重置為狀態對象中的數據表示的狀態(因為瀏覽器不會自動為你做這些)。

記住,瀏覽器加載的第一個頁面沒有狀態,因此單擊“后退”按鈕返回瀏覽器加載的第一個頁面時,event.state值為null

 
 
【】

注意:頁面第一次加載的時候,在load事件發生后,Chrome和Safari瀏覽器(Webkit內核)會觸發popstate事件,而Firefox和IE瀏覽器不會。

 
 
 
 
 
 
 
 
 
 
 
 
 
 

**

 
 
 
 
 
 


免責聲明!

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



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