pin_drop当前位置:知识文库 ❯ 图文
HTML5 API:HTML5 Web Storage API - 完整教程与代码示例
一、教程简介
Web Storage API 是 HTML5 提供的浏览器端键值对存储机制,包含 localStorage 和 sessionStorage 两个存储对象。与传统的 Cookie 相比,Web Storage 提供了更大的存储容量(通常为 5-10MB)、更简洁的 API 和更安全的数据隔离,是现代 Web 应用中客户端数据持久化的首选方案。本教程将概述 Web Storage API 的整体架构、核心概念和基本用法,后续教程将分别深入讲解 sessionStorage 和 localStorage。
二、核心概念
Web Storage 与 Cookie 对比
存储机制
代码示例
浏览器存储层次:
├── Cookie(4KB,自动发送)
├── Web Storage
│ ├── localStorage(持久化,同源共享)
│ └── sessionStorage(会话级,标签页隔离)
├── IndexedDB(大容量,结构化数据)
└── Cache API(请求/响应缓存)同源策略
Web Storage 遵循同源策略,只有相同协议(protocol)、域名(host)和端口(port)的页面才能访问相同的存储数据:
代码示例
https://example.com/page1 ──┐
https://example.com/page2 ──┤── 共享同一份 localStorage
https://example.com:443/a ──┘
http://example.com ────── 不同源,无法访问
https://api.example.com ────── 不同源,无法访问
https://example.com:8080 ────── 不同源,无法访问Storage 事件
当同源的其他页面修改了 localStorage 时,当前页面会触发 storage 事件:
代码示例
window.addEventListener('storage', function(e) {
console.log('变化的键:', e.key);
console.log('旧值:', e.oldValue);
console.log('新值:', e.newValue);
console.log('存储对象URL:', e.url);
console.log('存储区域:', e.storageArea);
});三、语法与用法
共用 API
localStorage 和 sessionStorage 拥有完全相同的 API 接口:
代码示例
// 存储数据
storage.setItem(key, value);
// 读取数据
const value = storage.getItem(key);
// 删除指定键
storage.removeItem(key);
// 清空所有数据
storage.clear();
// 按索引获取键名
const key = storage.key(index);
// 获取存储条目数量
const length = storage.length;基本用法示例
代码示例
// 设置数据
localStorage.setItem('username', '张三');
localStorage.setItem('age', '25');
// 读取数据
const username = localStorage.getItem('username'); // '张三'
const age = localStorage.getItem('age'); // '25'(字符串)
// 删除单条数据
localStorage.removeItem('username');
// 清空所有数据
localStorage.clear();
// 遍历所有数据
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
const value = localStorage.getItem(key);
console.log(key + ': ' + value);
}存储复杂数据
Web Storage 只能存储字符串,复杂数据需要序列化:
代码示例
// 存储对象
const user = { name: '张三', age: 25, hobbies: ['阅读', '编程'] };
localStorage.setItem('user', JSON.stringify(user));
// 读取对象
const storedUser = JSON.parse(localStorage.getItem('user'));
console.log(storedUser.name); // '张三'
// 存储数组
const tasks = [
{ id: 1, text: '学习 HTML5', done: false },
{ id: 2, text: '练习 CSS3', done: true }
];
localStorage.setItem('tasks', JSON.stringify(tasks));
// 读取数组
const storedTasks = JSON.parse(localStorage.getItem('tasks'));四、代码示例
示例一:Web Storage 通用工具类
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web Storage API - 通用工具类</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background: #f0f2f5; min-height: 100vh; padding: 40px 20px;
}
.container { max-width: 720px; margin: 0 auto; }
h1 { font-size: 26px; color: #1a1a2e; margin-bottom: 8px; }
.desc { color: #666; font-size: 14px; margin-bottom: 28px; line-height: 1.6; }
.card {
background: #fff; border-radius: 12px; padding: 24px;
margin-bottom: 20px; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
}
.card h2 { font-size: 17px; color: #333; margin-bottom: 16px; }
.btn-group { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; }
button {
padding: 8px 18px; border: none; border-radius: 6px;
font-size: 13px; font-weight: 600; cursor: pointer; transition: all 0.2s;
}
.btn-primary { background: #4285f4; color: #fff; }
.btn-success { background: #34a853; color: #fff; }
.btn-danger { background: #ea4335; color: #fff; }
.input-row { display: flex; gap: 10px; margin-bottom: 12px; }
input {
flex: 1; padding: 8px 12px; border: 1px solid #ddd;
border-radius: 6px; font-size: 14px; outline: none;
}
input:focus { border-color: #4285f4; }
</style>
</head>
<body>
<div class="container">
<h1>Web Storage 通用工具</h1>
<p class="desc">体验 localStorage 和 sessionStorage 的基本操作</p>
<div class="card">
<h2>数据操作</h2>
<div class="input-row">
<input type="text" id="keyInput" placeholder="键名(Key)">
<input type="text" id="valueInput" placeholder="值(Value)">
</div>
<div class="btn-group">
<button class="btn-primary" onclick="setStorage('local')">存入 localStorage</button>
<button class="btn-success" onclick="setStorage('session')">存入 sessionStorage</button>
<button class="btn-danger" onclick="removeStorage()">删除数据</button>
</div>
</div>
</div>
<script>
function setStorage(type) {
const key = document.getElementById('keyInput').value.trim();
const value = document.getElementById('valueInput').value.trim();
if (!key) { alert('请输入键名'); return; }
const storage = type === 'local' ? localStorage : sessionStorage;
storage.setItem(key, value);
alert('已存入 ' + type + 'Storage');
}
function removeStorage() {
const key = document.getElementById('keyInput').value.trim();
if (!key) { alert('请输入键名'); return; }
localStorage.removeItem(key);
sessionStorage.removeItem(key);
alert('已删除键: ' + key);
}
</script>
</body>
</html>示例二:Storage 事件跨标签页通信
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web Storage - 跨标签页通信</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background: #2d3436; min-height: 100vh;
display: flex; justify-content: center; align-items: center; padding: 20px;
}
.container {
background: #fff; border-radius: 16px; padding: 36px;
max-width: 500px; width: 100%;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}
h1 { font-size: 22px; color: #2d3436; margin-bottom: 6px; }
.desc { color: #636e72; font-size: 13px; margin-bottom: 24px; line-height: 1.6; }
.chat-area {
background: #f8f9fa; border-radius: 10px; padding: 16px;
height: 300px; overflow-y: auto; margin-bottom: 16px;
}
.message {
margin-bottom: 10px; padding: 8px 14px;
border-radius: 10px; max-width: 80%; font-size: 14px; line-height: 1.5;
}
.message.sent { background: #0984e3; color: #fff; margin-left: auto; }
.message.received { background: #dfe6e9; color: #2d3436; }
.input-area { display: flex; gap: 10px; }
input {
flex: 1; padding: 10px 14px; border: 1px solid #ddd;
border-radius: 8px; font-size: 14px; outline: none;
}
input:focus { border-color: #0984e3; }
button {
padding: 10px 20px; background: #0984e3; color: #fff;
border: none; border-radius: 8px; font-size: 14px; font-weight: 600; cursor: pointer;
}
button:hover { background: #0770c2; }
</style>
</head>
<body>
<div class="container">
<h1>跨标签页通信</h1>
<p class="desc">在多个标签页中打开此页面,通过 localStorage 的 storage 事件实现消息同步。</p>
<div class="chat-area" id="chatArea"></div>
<div class="input-area">
<input type="text" id="msgInput" placeholder="输入消息..." onkeydown="if(event.key==='Enter')sendMessage()">
<button onclick="sendMessage()">发送</button>
</div>
</div>
<script>
const chatArea = document.getElementById('chatArea');
const msgInput = document.getElementById('msgInput');
const tabId = 'tab_' + Date.now() + '_' + Math.random().toString(36).substr(2, 6);
function sendMessage() {
const text = msgInput.value.trim();
if (!text) return;
const message = {
id: Date.now(), tabId: tabId, text: text,
time: new Date().toLocaleTimeString('zh-CN')
};
localStorage.setItem('chat_message', JSON.stringify(message));
appendMessage(message, 'sent');
msgInput.value = '';
}
window.addEventListener('storage', function (e) {
if (e.key === 'chat_message' && e.newValue) {
try {
const message = JSON.parse(e.newValue);
if (message.tabId !== tabId) appendMessage(message, 'received');
} catch (err) { console.error('消息解析失败:', err); }
}
});
function appendMessage(message, type) {
const div = document.createElement('div');
div.className = 'message ' + type;
div.innerHTML = '<div>' + message.text + '</div><div style="font-size:11px;opacity:0.7;margin-top:4px;">' + message.time + '</div>';
chatArea.appendChild(div);
chatArea.scrollTop = chatArea.scrollHeight;
}
</script>
</body>
</html>五、浏览器兼容性
六、注意事项与最佳实践
1. 数据安全
-
不要存储敏感信息:Web Storage 数据可被同源页面和浏览器开发者工具直接查看
-
防范 XSS 攻击:存储的数据如果直接插入 DOM,必须进行转义处理
-
设置合理的存储策略:定期清理过期数据,避免存储无限增长
2. 存储限制
-
容量有限:通常为 5-10MB,超出会抛出
QuotaExceededError -
写入可能失败:隐私模式下某些浏览器会限制或禁用 Web Storage
-
及时捕获异常:写入操作应包裹在 try-catch 中
代码示例
function safeSetItem(key, value) {
try {
localStorage.setItem(key, value);
} catch (e) {
if (e.name === 'QuotaExceededError' ||
e.name === 'NS_ERROR_DOM_QUOTA_REACHED') {
console.error('存储空间已满');
// 降级处理:清理旧数据或提示用户
}
}
}3. 数据类型处理
-
所有值都是字符串:存储数字、布尔值时注意类型转换
-
使用 JSON 序列化:存储对象和数组时使用
JSON.stringify/JSON.parse -
处理 null 和 undefined:
getItem返回null表示键不存在
4. 性能考虑
-
避免频繁读写:Web Storage 是同步操作,会阻塞主线程
-
大数据使用 IndexedDB:超过 1MB 的数据建议使用 IndexedDB
-
批量操作优化:多次操作可合并为一次 JSON 序列化
七、代码规范示例
代码示例
// 推荐:封装 Web Storage 工具类
class StorageManager {
constructor(type = 'local', prefix = '') {
this.storage = type === 'local' ? localStorage : sessionStorage;
this.prefix = prefix;
}
_getKey(key) {
return this.prefix ? this.prefix + '_' + key : key;
}
set(key, value, expireMs = null) {
const data = {
value: value,
timestamp: Date.now(),
expire: expireMs ? Date.now() + expireMs : null
};
try {
this.storage.setItem(this._getKey(key), JSON.stringify(data));
return true;
} catch (e) {
console.error('Storage setItem 失败:', e);
return false;
}
}
get(key, defaultValue = null) {
try {
const raw = this.storage.getItem(this._getKey(key));
if (raw === null) return defaultValue;
const data = JSON.parse(raw);
if (data.expire && Date.now() > data.expire) {
this.remove(key);
return defaultValue;
}
return data.value;
} catch (e) {
console.error('Storage getItem 失败:', e);
return defaultValue;
}
}
remove(key) {
this.storage.removeItem(this._getKey(key));
}
has(key) {
return this.get(key) !== null;
}
clear() {
if (!this.prefix) {
this.storage.clear();
return;
}
const keysToRemove = [];
for (let i = 0; i < this.storage.length; i++) {
const k = this.storage.key(i);
if (k.startsWith(this.prefix + '_')) keysToRemove.push(k);
}
keysToRemove.forEach(k => this.storage.removeItem(k));
}
getSize() {
let total = 0;
for (let i = 0; i < this.storage.length; i++) {
const key = this.storage.key(i);
const value = this.storage.getItem(key);
total += key.length + value.length;
}
return (total * 2 / 1024).toFixed(2) + ' KB';
}
}
// 使用示例
const store = new StorageManager('local', 'myapp');
store.set('user', { name: '张三', age: 25 });
store.set('token', 'abc123', 3600000); // 1小时过期
console.log(store.get('user'));
console.log(store.getSize());八、常见问题与解决方案
常见问题
隐私模式下 Web Storage 不可用?
原因:部分浏览器在隐私模式下限制或禁用 Web Storage。
解决方案:使用检测函数判断存储是否可用,不可用时降级到内存对象或 Cookie。
存储空间超出限制怎么办?
解决方案:实现数据淘汰策略(如 LRU)、定期清理过期数据、压缩存储数据、大数据迁移到 IndexedDB。
JSON.parse 解析失败?
原因:存储的数据可能被手动修改或损坏。
解决方案:使用安全的 JSON 解析函数,捕获异常并返回默认值。
如何实现数据过期机制?
解决方案:在存储数据时附带时间戳和过期时间,读取时检查是否过期。可以使用封装的工具类自动处理过期逻辑。
九、总结
Web Storage API 提供了简洁高效的客户端键值对存储方案。localStorage 适合持久化数据(如用户偏好设置),sessionStorage 适合临时会话数据(如表单临时保存)。使用时需注意存储容量限制、数据安全(防范 XSS)、类型转换(所有值为字符串)和异常处理。通过封装工具类可以实现过期机制、前缀隔离、安全读写等高级功能,让 Web Storage 在实际项目中更加可靠易用。
本文涉及AI创作
内容由AI创作,请仔细甄别