一篇文章圖文並茂地帶你輕鬆學會 HTML5 storage

Huro~發表於2021-02-13

html5 storage api

localStoragesessionStoragehtml5 新增的用來儲存資料的物件,他們讓我們可以以鍵值對的形式儲存資訊。

為什麼要有 storage ?

我們已經有了 session 可以幫助我們儲存資訊,為何還需要 storage 呢?

  1. 各個瀏覽器的 cookie 長度大概只能在 4kb 左右,而 storage 大概能達到 5M,這意味著可以儲存更多的資訊
  2. cookie 可以被後端更改,在每次進行網路請求的時候都會被髮送給伺服器,而 storage 不會,這意味著這個儲存是完全受控於前端(JavaScript)的。

storage 型別

storage 一共有兩種

  1. localStorage

    這個儲存物件的儲存和 origin 有關,即只要是同域名同協議同埠,儲存是共享的。儘管關機了,或是關掉瀏覽器了,只要開啟同源網站,儲存的資料會依然存在,資料不會過期消失。

  2. sessionStorage

    這個儲存物件的儲存是暫時的,只保持在當前會話中,簡單來說就是和瀏覽器的一個 tab 有關,只要 tab 關掉了再開啟資料就沒了,但是在當前介面重新整理的話,資料就還在(這個時候認為是一個 tab)。

兩個 storageapi 很相似,下面以 localStorage 為例

localStorage 演示

基礎 api

localStorage.setItem("name", "huro"); // 設定鍵值對

可以在 chrome 瀏覽器的控制檯進行觀察,這裡已經設定上去了。下面也可以做相應的測試。

localStorage.getItem("name"); // huro
localStorage.removeItem("name"); // 刪除某個鍵
localStorage.clear(); // 刪除所有鍵值對
localStorage.key(0); // 獲得索引為 0 的key
localStorage.length; // 獲得 `localStroage` 的鍵的個數

以上是 storageapi

唯一需要注意的是 key(index) 這個 apikey 被設定的先後是沒有關係的。

類物件操作

也可以用類物件的方法操作

localStorage.name = "huro";
console.log(localStorage.name); // huro
delete localStorage.name; // 刪除鍵

但是上面的做法不推薦,如果用的是某些特殊的 key 例如 length 就會報錯,因為原先 localStorage.length 表示獲得鍵值對長度,理應是不能修改的。

localStorage["length"] = 4; // 修改無效

因此不推薦用這個做法修改 storage

遍歷鍵值

由於 storage 並沒有 Symbol.iterator 屬性,這意味著 storage 不能用 for of迴圈遍歷。以下有三種遍歷方式。

假設我們只有一個鍵值對 name: huro

  1. for in 迴圈
for (let key in localStorage) {
    console.log(key);
}

上述的寫法是錯誤的,因為 for in 迴圈會遍歷原型鏈上的屬性和方法,因此需要稍作改善。

for (let key in localStorage) {
  if (!localStorage.hasOwnProperty(key)) {
    continue;
  }
  console.log(key);
}

這個時候就能正確的只列印出鍵 name

  1. 簡單 for 迴圈
for(let i = 0; i < localStorage.length; i+= 1) {
  let key = localStorage.key(i);
  console.log(key);
}

這個時候能正確的只列印出鍵 name

  1. Object.keys()

這個方法會獲得某個物件自身的 key,而不會管原型鏈上的

const keys = Object.keys(localStorage);
for(let key of keys) {
  alert(key);
}

而且獲得的 key 是陣列,具有 iterator 因此可以用 for of 遍歷

這個時候能正確的只列印出鍵 name

只能是 string

storage 被設計出來比較不足的地方是,鍵和值都只能是 string 型別的,如果不是的話,會自動轉換成 string

由於是隱式轉換,初學者往往不知道,這意味著可能帶來一些 bug

localStorage.user = { name: "huro" };
console.log(localStorage.user); // [object Object]

上述程式碼在儲存 user 的時候,被自動呼叫 toString 方法,轉化為了 [object Object]

storage 事件

storage 事件返回一個物件,裡面包含幾個引數

  1. key 改變的鍵
  2. oldValue => 舊值 || null
  3. newValue => 新值 || null
  4. url 觸發這個事件的 url 地址
  5. storageArea 要麼是 localStorage 要麼是 sessionStorage 取決與是更改哪個storage
// 1.html
window.addEventListener("storage", (state) => {
    console.log(state.key, state.value, state.url); // name huro ./2.html(實際 url 是絕對路徑)
})

// 2.html
localStorage.setItem("name", "huro");

還記得我們之前說過, localStorage 只要是同源都可以分享嗎,這意味如果我們開啟了兩個視窗,只要他們是同源的,我們可以用上述的監聽事件,監聽另一個埠修改 storage,也就是可以實現不同的視窗之間的資料共享。

注意: 經測試,chrome edge 等現代瀏覽器不會觸發自身檔案或同檔案的 storage 事件,即必須是兩個不同的 html 才會互相觸發。

例如 test1.htmltest2.html 都設定了 storage 監聽事件,且同源。

test1.htmlstorageapi 事件會觸發 test2.html 的,但是不能觸發本身的 storage 監聽事件。

另外這裡的 api 事件也有限制,經過筆者測試,似乎只有

  1. setItem
  2. getItem
  3. removeItem

有效果,而 clear 事件是沒有效果的。
上面全程用 localStorage 演示,

sessionStorage 也是類似的,讀者有興趣可以自行碼一下程式碼。

總結

storage 是很好的一個 html5 特性,讓我們方便快捷的儲存資料,美中不足的是隻能儲存字元型資料,不過也很容易解決這個問題。同時利用監聽事件,也可以實現不同視窗之間的廣播機制。是非常實用的一個特性。

相關文章