使用 Web Storage API

Web Storage API 提供了瀏覽器安全儲存鍵/值對的機制。

本文將介紹如何使用這項技術。

基本概念

Storage 物件是簡單的鍵/值儲存,類似於物件,但它們在頁面載入之間保持不變。鍵和值始終是字串(請注意,與物件一樣,整數鍵會自動轉換為字串)。你可以像訪問物件一樣訪問這些值,或者使用 Storage.getItem()Storage.setItem() 方法。這三行程式碼都設定了(相同的)colorSetting 條目。

js
localStorage.colorSetting = "#a4509b";
localStorage["colorSetting"] = "#a4509b";
localStorage.setItem("colorSetting", "#a4509b");

注意: 建議使用 Web Storage API(setItemgetItemremoveItemkeylength)來避免使用普通物件作為鍵/值儲存所帶來的 陷阱

Web Storage 中的兩種機制如下:

  • sessionStorage 為每個給定的源維護一個單獨的儲存區域,該區域在頁面會話期間(只要瀏覽器開啟,包括頁面重新載入和恢復)可用。
  • localStorage 執行相同的功能,但在瀏覽器關閉和重新開啟後仍會持久化。

這些機制可以透過 Window.sessionStorageWindow.localStorage 屬性訪問(更準確地說,在支援的瀏覽器中,Window 物件實現了 WindowLocalStorageWindowSessionStorage 物件,而 localStoragesessionStorage 屬性是這些物件的成員)——呼叫其中一個將建立一個 Storage 物件例項,透過該例項可以設定、檢索和刪除資料項。對於每個源的 sessionStoragelocalStorage 會使用不同的 Storage 物件——它們的功能和控制是分開的。

因此,例如,最初在文件上呼叫 localStorage 將返回一個 Storage 物件;在文件上呼叫 sessionStorage 將返回一個不同的 Storage 物件。兩者都可以用相同的方式進行操作,但彼此獨立。

檢測 localStorage 的支援情況

要能夠使用 localStorage,我們應該首先驗證它是否在當前瀏覽會話中受支援且可用。

測試可用性

支援 localStorage 的瀏覽器在 window 物件上有一個名為 localStorage 的屬性。但是,僅僅測試屬性是否存在,就像在正常的特性檢測中一樣,可能不足夠。各種瀏覽器提供了停用儲存 API 的設定,而不會隱藏全域性物件。因此,瀏覽器可能支援 localStorage,但不向頁面上的指令碼提供它。

例如,對於在瀏覽器隱私瀏覽模式下檢視的文件,某些瀏覽器可能會提供一個配額為零的空 localStorage 物件,實際上使其無法使用。反之,我們也可能會收到一個合法的 QuotaExceededError,這意味著我們已經用完了所有可用的儲存空間,但儲存確實可用。我們的特性檢測應該考慮到這些情況。

這是一個檢測 localStorage 是否被支援且可用的函式:

js
function storageAvailable(type) {
  let storage;
  try {
    storage = window[type];
    const x = "__storage_test__";
    storage.setItem(x, x);
    storage.removeItem(x);
    return true;
  } catch (e) {
    return (
      e instanceof DOMException &&
      e.name === "QuotaExceededError" &&
      // acknowledge QuotaExceededError only if there's something already stored
      storage &&
      storage.length !== 0
    );
  }
}

以下是如何使用它:

js
if (storageAvailable("localStorage")) {
  // Yippee! We can use localStorage awesomeness
} else {
  // Too bad, no localStorage for us
}

你可以透過呼叫 storageAvailable("sessionStorage") 來改用 sessionStorage 進行測試。

示例

為了說明一些典型的 Web Storage 用法,我們建立了一個名為“Web Storage Demo”的示例。該 主頁 提供了用於自定義顏色、字型和裝飾影像的控制元件。

Web storage example with text box to choose the color by entering a hex value, and two dropdown menus to choose the font style, and decorative image.

當您選擇不同的選項時,頁面會立即更新;此外,您的選擇會儲存在 localStorage 中,因此當您離開頁面並稍後重新載入它時,您的選擇會被記住。

我們還提供了一個 事件輸出頁面 — 如果您在另一個標籤頁中載入此頁面,然後更改主頁中的選擇,您將看到更新的儲存資訊作為 StorageEvent 觸發的輸出。

Event output page

注意: 除了透過上面的連結即時檢視示例頁面外,您還可以 檢視原始碼

測試您的儲存是否已填充

首先,在 main.js 中,我們測試儲存物件是否已填充(即,頁面之前已被訪問)。

js
if (!localStorage.getItem("bgcolor")) {
  populateStorage();
} else {
  setStyles();
}

Storage.getItem() 方法用於從儲存中獲取資料項;在這種情況下,我們正在測試 bgcolor 項是否存在;如果不存在,我們執行 populateStorage() 將現有的自定義值新增到儲存中。如果已經存在值,我們執行 setStyles() 以儲存的值更新頁面樣式。

注意: 您也可以使用 Storage.length 來測試儲存物件是否為空。

從儲存中獲取值

如上所述,可以使用 Storage.getItem() 從儲存中檢索值。它以資料項的鍵作為引數,並返回資料值。

例如

js
function setStyles() {
  const currentColor = localStorage.getItem("bgcolor");
  const currentFont = localStorage.getItem("font");
  const currentImage = localStorage.getItem("image");

  document.getElementById("bgcolor").value = currentColor;
  document.getElementById("font").value = currentFont;
  document.getElementById("image").value = currentImage;

  htmlElem.style.backgroundColor = `#${currentColor}`;
  pElem.style.fontFamily = currentFont;
  imgElem.setAttribute("src", currentImage);
}

這裡,前三行從本地儲存中獲取值。接下來,我們將表單元素中顯示的值設定為這些值,以便在重新載入頁面時保持同步。最後,我們更新頁面上的樣式/裝飾影像,以便在重新載入時再次顯示您的自定義選項。

將值設定到儲存中

Storage.setItem() 用於建立新資料項,以及(如果資料項已存在)更新現有值。它接受兩個引數——要建立/修改的資料項的鍵,以及要儲存的值。

js
function populateStorage() {
  localStorage.setItem("bgcolor", document.getElementById("bgcolor").value);
  localStorage.setItem("font", document.getElementById("font").value);
  localStorage.setItem("image", document.getElementById("image").value);

  setStyles();
}

populateStorage() 函式在本地儲存中設定三個項——背景顏色、字型和影像路徑。然後它執行 setStyles() 函式來更新頁面樣式等。

我們還在每個表單元素上包含了一個 onchange 處理程式,以便在更改表單值時更新資料和樣式。

js
bgcolorForm.onchange = populateStorage;
fontForm.onchange = populateStorage;
imageForm.onchange = populateStorage;

Storage 只支援儲存和檢索字串。如果你想儲存其他資料型別,你必須將它們轉換為字串。對於普通物件和陣列,可以使用 JSON.stringify()

js
const person = { name: "Alex" };
localStorage.setItem("user", person);
console.log(localStorage.getItem("user")); // "[object Object]"; not useful!
localStorage.setItem("user", JSON.stringify(person));
console.log(JSON.parse(localStorage.getItem("user"))); // { name: "Alex" }

然而,沒有通用的方法可以儲存任意資料型別。此外,檢索到的物件是原始物件的深複製,對它的修改不會影響原始物件。

使用 StorageEvent 響應儲存更改

當共享相同儲存空間的另一個文件的 Storage 物件發生更改時,將觸發 storage 事件。這在進行更改的同一頁面上不起作用——它實際上是一種讓使用該儲存的其他頁面同步所做更改的方式。其他來源的頁面無法訪問相同的儲存物件。

對於 localStorage,儲存空間由同一來源的所有選項卡共享。對於 sessionStorage,儲存空間僅在選項卡內共享, among all iframes from the same origin(在同一來源的所有 iframe 之間共享)。

在事件頁面(參見 events.js)上,唯一的 JavaScript 如下:

js
window.addEventListener("storage", (e) => {
  document.querySelector(".my-key").textContent = e.key;
  document.querySelector(".my-old").textContent = e.oldValue;
  document.querySelector(".my-new").textContent = e.newValue;
  document.querySelector(".my-url").textContent = e.url;
  document.querySelector(".my-storage").textContent = JSON.stringify(
    e.storageArea,
  );
});

這裡我們向 window 物件添加了一個事件監聽器,當與當前來源相關的 Storage 物件發生更改時觸發。如上所示,與此事件關聯的事件物件具有許多包含有用資訊的屬性——更改的資料的鍵,更改前的值,更改後的新值,更改儲存的文件的 URL,以及儲存物件本身(我們已將其字串化,以便您可以看到其內容)。

刪除資料記錄

Web Storage 還提供了一些簡單的刪除資料的方法。我們在演示中沒有使用它們,但將它們新增到您的專案中非常簡單。

  • Storage.removeItem() 接受一個引數——您要刪除的資料項的鍵——並將其從該來源的儲存物件中刪除。
  • Storage.clear() 不接受任何引數,並清空該來源的整個儲存物件。

規範

規範
HTML
# dom-localstorage-dev
HTML
# dom-sessionstorage-dev

瀏覽器相容性

api.Window.localStorage

api.Window.sessionStorage

另見