Skip to content

HTML5 - Web 存储

HTML5 Web Storage(网络存储)提供了机制,使 Web 应用程序能够在用户浏览器内本地存储数据。这允许应用程序保留用户偏好设置、离线数据,并通过缓存资源提高性能。

Web Storage 相对于传统 cookie 具有优势:

  • 更大的存储容量:浏览器通常为每个源(origin)分配 5-10MB 的 Web Storage 空间,远超 cookie 的 4KB 限制。
  • 不随 HTTP 请求发送:存储的数据不会随每个 HTTP 请求自动发送,从而减少网络开销并提高安全性。
  • 客户端接口:提供一个简单的同步 JavaScript API,用于设置、检索和移除数据。

Web Storage 主要有两种类型:localStorage 和 sessionStorage。

所有现代浏览器,包括桌面和移动版本,都支持 Web Storage。

sessionStorage 为每个给定的源(origin)维护一个单独的存储区域,该区域的可用性持续整个页面会话(只要浏览器标签页或窗口保持打开,包括页面重载和恢复)。

存储在 sessionStorage 中的数据特定于创建它的窗口或标签页。如果用户在新的标签页或窗口中打开同一个网页,会创建一个新的会话和单独的存储区域。

  • 在多步表单中存储临时用户输入。
  • 跟踪单个会话中的用户活动(例如,查看过的项目)。
  • 维护特定于单个浏览器标签页的应用程序状态。

以下代码在同一会话中每次页面加载时增加一个计数器:

<!DOCTYPE html>
<html>
<head>
<title>Session Storage Example</title>
</head>
<body>
<h1>Session Storage Page Counter</h1>
<p id="hitCount"></p>
<script>
// 检查 sessionStorage 是否受支持
if (typeof(Storage) !== "undefined") {
// 从 sessionStorage 中检索当前访问计数
let hits = sessionStorage.getItem('pageHits');
// 如果不存在,初始化为 1,否则增加
if (hits) {
hits = Number(hits) + 1;
} else {
hits = 1;
}
// 将更新后的计数存回 sessionStorage
sessionStorage.setItem('pageHits', hits);
// 在页面上显示计数
document.getElementById('hitCount').textContent = `Page loads this session: ${hits}`;
} else {
document.getElementById('hitCount').textContent = 'Sorry, your browser does not support Web Storage.';
}
</script>
<p>Refresh the page to increase the counter.</p>
<p>Close the tab/window and reopen the page to reset the counter.</p>
</body>
</html>

刷新页面以增加计数器。

关闭标签页/窗口并重新打开页面以重置计数器。

localStorage 的功能与 sessionStorage 相同,但即使浏览器关闭并重新打开后也会保留。对于同一源(origin),数据在不同会话、标签页和窗口之间仍然可用,直到用户或 Web 应用程序明确清除为止。

  • 存储用户偏好设置(例如,主题设置、语言选择)。
  • 在不同的浏览器会话中保持用户登录状态(尽管更安全的方法通常涉及服务器端会话)。
  • 缓存应用程序数据以供离线使用或加快启动速度。

此示例保存并检索用户的首选主题:

<!DOCTYPE html>
<html>
<head>
<title>Local Storage Example</title>
<style id="themeStyle"></style>
</head>
<body>
<h1>Local Storage Theme Preference</h1>
<label for="themeSelect">Choose Theme:</label>
<select id="themeSelect">
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
<script>
const themeSelect = document.getElementById('themeSelect');
const themeStyle = document.getElementById('themeStyle');
function applyTheme(theme) {
if (theme === 'dark') {
themeStyle.textContent = 'body { background-color: #333; color: #eee; } select, label { color: #eee; }';
} else {
themeStyle.textContent = 'body { background-color: #fff; color: #333; } select, label { color: #333; }';
}
themeSelect.value = theme;
}
function saveThemePreference(theme) {
if (typeof(Storage) !== "undefined") {
localStorage.setItem('userTheme', theme);
} else {
console.warn('localStorage not supported, cannot save theme preference.');
}
}
// 在页面加载时加载保存的主题
if (typeof(Storage) !== "undefined") {
const savedTheme = localStorage.getItem('userTheme') || 'light'; // 默认为浅色主题
applyTheme(savedTheme);
} else {
console.warn('localStorage not supported, using default theme.'); // localStorage 不受支持,使用默认主题。
applyTheme('light');
}
// 主题更改的事件监听器
themeSelect.addEventListener('change', (event) => {
const selectedTheme = event.target.value;
applyTheme(selectedTheme);
saveThemePreference(selectedTheme);
});
</script>
<p>Your theme preference will be saved even if you close the browser.</p>
</body>
</html>

你的主题偏好设置将会被保存,即使你关闭浏览器。

localStorage 和 sessionStorage 都共享相同的 API 方法:

  • setItem(key, value):添加或更新一个键值对(key-value pair)。key 和 value 都必须是字符串。
  • getItem(key):检索与 key 关联的值。如果 key 不存在,则返回 null。
  • removeItem(key):移除与 key 关联的键值对。
  • clear():移除该 origin 下的所有键值对。
  • key(index):返回指定数字索引处的 key 名称。
  • length:一个只读属性(read-only property),返回存储的键值对数量。

**重要提示:**Web Storage 只能存储字符串。如果你需要存储对象或数组,必须在保存前将它们序列化(例如,使用 JSON.stringify()),并在检索时反序列化(使用 JSON.parse())。

// 存储一个对象
const userPrefs = { theme: 'dark', fontSize: 16 };
localStorage.setItem('preferences', JSON.stringify(userPrefs));
// 检索对象
const storedPrefsString = localStorage.getItem('preferences');
const retrievedPrefs = storedPrefsString ? JSON.parse(storedPrefsString) : {};
console.log(retrievedPrefs.theme); // 输出: dark
  • **同步性:**API 操作是同步的,这意味着如果处理大量数据或慢速磁盘访问,调用可能会阻塞主浏览器线程。对于复杂或大规模存储,首选 IndexedDB。
  • **仅限字符串:**如前所述,只能直接存储字符串。
  • **存储限制:**虽然比 cookie 大,但 5-10MB 的限制对于某些应用程序仍然可能受限。
  • **安全性:**数据存储在客户端,可以被运行在同一 origin 的任何脚本访问或修改。不要在 Web Storage 中存储敏感信息(例如密码或令牌)。
  • **无查询功能:**Web Storage 是一个简单的键值存储。它缺乏 IndexedDB 等数据库中存在的索引或查询功能。

对于需要索引、事务或更大容量数据的更高级客户端存储需求,考虑使用 IndexedDB API。