使用 Web 存储 API

Web 存储 API 提供了浏览器可以安全存储键值对的机制。

本文介绍了如何使用此技术。

基本概念

存储对象是简单的键值存储,类似于对象,但它们在页面加载时保持完整。键和值始终是字符串(请注意,与对象一样,整数键将自动转换为字符串)。您可以像访问对象一样访问这些值,或者使用 Storage.getItem()Storage.setItem() 方法。以下三行都设置了(相同)colorSetting 条目

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

注意:建议使用 Web 存储 API (setItemgetItemremoveItemkeylength) 来防止使用普通对象作为键值存储所带来的 陷阱

Web 存储中的两种机制如下

  • sessionStorage 为每个给定来源维护一个单独的存储区域,该区域在页面会话期间可用(只要浏览器处于打开状态,包括页面重新加载和恢复)。
  • localStorage 做同样的事情,但即使在浏览器关闭并重新打开后也会保持。

这些机制可以通过 Window.sessionStorageWindow.localStorage 属性来访问(更准确地说,在支持的浏览器中,Window 对象实现了 WindowLocalStorageWindowSessionStorage 对象,localStoragesessionStorage 属性是这两个对象的成员)——调用其中一个将创建一个 Storage 对象的实例,通过该实例可以设置、检索和删除数据项。sessionStoragelocalStorage 每个来源使用不同的存储对象——它们的功能和控制是独立的。

因此,例如,最初在文档上调用 localStorage 将返回一个 Storage 对象;在文档上调用 sessionStorage 将返回一个不同的 Storage 对象。这两个对象都可以以相同的方式操作,但它们是独立的。

功能检测 localStorage

为了能够使用 localStorage,我们应该首先验证它是否在当前浏览器会话中受支持并可用。

测试可用性

注意:此 API 在所有主要浏览器的当前版本中都可用。仅当您必须支持非常旧的浏览器或在下面描述的有限情况下,才需要测试可用性。

支持 localStorage 的浏览器在 window 对象上有一个名为 localStorage 的属性。但是,仅仅断言属性存在可能会引发异常。如果 localStorage 对象确实存在,仍然不能保证 localStorage API 实际可用,因为各种浏览器提供了禁用 localStorage 的设置。因此,浏览器可能支持 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。

请参见 关于功能检测 localStorage 的简要历史

示例

为了说明一些典型的 Web 存储用法,我们创建了一个示例,想象力丰富地称为 Web 存储演示登录页面 提供了可用于自定义颜色、字体和装饰图像的控件

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 对象进行更改时,就会触发 StorageEvent(请注意,此事件不会针对 sessionStorage 更改触发)。这在进行更改的同一页面上不会起作用——它实际上是让同一域上的其他页面使用存储来同步所做的任何更改的一种方式。其他域上的页面无法访问相同的存储对象。

在事件页面上(参见 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.removeItem() 接受一个参数——要删除的数据项的键——并将其从该域的存储对象中删除。
  • Storage.clear() 不接受任何参数,并清空该域的整个存储对象。

规范

规范
HTML 标准
# dom-localstorage-dev
HTML 标准
# dom-sessionstorage-dev

浏览器兼容性

api.Window.localStorage

BCD 表格仅在浏览器中加载

api.Window.sessionStorage

BCD 表格仅在浏览器中加载

另请参见