【譯】使用 HTML5 History API 控制瀏覽器位址列 URL

weixin_34321977發表於2016-08-13

原文:抱歉找不到了

HTML5 的 History API 可以讓開發者不重新整理整個頁面就可以修改網站的 URL。這在使用 JavaScript 載入一個頁面的一部分的時候尤其有用,用 JavaScript 新載入的這一部分內容是明顯不同的, 因而有必要使用一個新的 URL(原文: This is particularly useful for loading portions of a page with JavaScript, such that the content is significantly different and warrants a new URL.)。

這裡有一個例子,我們假設一個人從一個網站的 Homepage 前往訪問 Help 頁面。我們使用 Ajax 載入 Help 頁面的內容。那個使用者隨後又訪問 Product 頁面,而我們還是用 Ajax 載入並替換內容。然後,使用者想分享這個頁面(即 Product 頁面)的 URL。通過 History API,我們本可以(we could have been)隨著使用者的訪問而正確地修改頁面的 URL,所以他們看見(或分享或儲存)的 URL 是相關的並且正確的。

基礎原理

要檢視這個 API 的特徵,只需要開啟 the Developer Tools(即瀏覽器的開發者工具),在控制檯輸入(type into)history。如果你選擇的瀏覽器支援這個 API,那麼我們將會看到許多隸屬於這個物件的方法(a host of methods attached to this object):

History {length: 2, state: null, scrollRestoration: "auto"}
    length:2
    scrollRestoration:"auto"
    state:null
    __proto__:History
        back:back()
        constructor:History()
        forward:forward()
        go:go()
        length:(...)
        get length:()
        pushState:pushState()
        replaceState:replaceState()
        scrollRestoration:(...)
        get scrollRestoration:()
        set scrollRestoration:()
        state:(...)
        get state:()
        Symbol(Symbol.toStringTag):"History"
        __proto__:Object

我們只對說明中的pushStatereplaceState感興趣。回到控制檯,我們可以試驗一下這些方法並看看當我們使用這些方法的時候 URL 發生什麼變化。我們稍後將覆蓋其他引數,但現在我們所要使用的是最後的這個引數:

history.replaceState(null, null, 'hello');

儘管沒有請求資源,視窗也保持著同一個頁面,但上面的replaceState方法用/hello作為位址列中 URL 的結尾(原文:The replaceState method above switches out the URL in the address bar with '/hello' despite no assets being requested and the window remaining on the same page. )。這裡還有一個問題。當點選瀏覽器上的返回按鈕的時候,我們會發現我們並沒有返回到這篇文章的 URL ,而是回到我們之前所停留的頁面。這是因為replaceState沒有處理瀏覽器的歷史,它只是簡單地替換位址列中當前的 URL。

要解決(fix)這個問題,我們需要使用pushState方法來代替:

history.pushState(null, null, 'hello');

現在,如果我們點選瀏覽器的返回按鈕,我們會發現它會像我們所希望的一樣執行,因為pushState已經修改了我們的歷史(記錄)以包含我們剛剛所傳遞進去的 URL。這很有趣,但如果我們做一些不那麼直接的嘗試並且假裝當前的 URL 一直都不是“css-tricks.com”而是完完全全是另一個網站,之後會發生什麼呢?

history.pushState(null, null, 'https://twitter.com/hello');

這會丟擲一個異常,因為 URL 必須與當前的 URL 同源(has to be of the same origin as the current one),否則,我們可能冒著重大的安全漏洞風險(原文:we might risk major security flaws )並且是開發者能夠欺騙人們讓他們完全相信自己是在一個不同的網站(give developers the ability to fool people into believing they were on a different website altogether)。

回頭看看被傳入到這個函式中的其他引數,我們可以總結如下:

history.pushState([data], [title], [url]);
  1. 如果網頁的狀態改變了,例如:每當有人按下瀏覽器中的返回或前進按鈕,我們將需要的資料就是第一個引數。需要注意的是:在 Firefox 中,這個資料被限制為 640k 個字元。
  2. title是第二個引數,他可以是一個字串,但截至本文寫作時間(2015年3月9日),所有瀏覽器都簡單地忽略它。
  3. 最後的這個引數就是我們希望出現在位址列的 URL。

簡史(A Quick History)

這些 history API 最值得注意的是,它們不會重新載入頁面。在過去,改變 URL 的唯一方法是window.locaton,但它總是會重新載入頁面。 除非,如果你所改變的只是hash(就像 點選<a href="#target">link</a>不會重新載入頁面 一樣)(原文:Except, if all you changed was the hash)。

這與舊的 hashbang 方法相通,hashbang 方法可以改變 URL 而不重新整理整個頁面。總所周知,Twitter 曾經這樣子做並因此而在很大程度上收到了批評(hash 不是一個真的資源地址)。

Twitter 放棄了使用這個方法,並且成為 history API 最早的支持者之一。

8188-01540cfb0dcd3a44.png
Paste_Image.png

相關文章