pin_drop当前位置:知识文库 ❯ 图文
HTML5 API:HTML5 SessionStorage - 完整教程与代码示例
一、教程简介
SessionStorage 是 Web Storage API 的一部分,提供了一种会话级别的键值对存储机制。与 localStorage 的持久化存储不同,sessionStorage 中存储的数据仅在当前浏览器标签页(或窗口)的生命周期内有效,当标签页关闭后数据即被清除。这种特性使 sessionStorage 特别适合存储临时性、会话性的数据,如多步骤表单的中间状态、一次性令牌、页面间的临时参数传递等。
二、核心概念
会话生命周期
代码示例
标签页打开 → sessionStorage 创建
│
├── 页面刷新 → 数据保留
├── 页面导航 → 数据保留(同源)
├── 恢复页面 → 数据保留(部分浏览器)
│
└── 标签页关闭 → 数据清除标签页隔离
sessionStorage 最重要的特性是标签页隔离:
-
每个标签页拥有独立的 sessionStorage 实例
-
即使是同一 URL 打开的多个标签页,也各自拥有独立的数据
-
标签页之间无法共享 sessionStorage 数据
-
通过
window.open或<a target="_blank">打开的新标签页会复制一份当前标签页的 sessionStorage 快照
与 localStorage 的区别
API 接口
代码示例
// 设置数据
sessionStorage.setItem(key, value);
// 读取数据
const value = sessionStorage.getItem(key);
// 删除指定键
sessionStorage.removeItem(key);
// 清空所有数据
sessionStorage.clear();
// 按索引获取键名
const key = sessionStorage.key(index);
// 获取存储条目数量
const length = sessionStorage.length;三、语法与用法
基本操作
代码示例
// 存储
sessionStorage.setItem('tempData', '临时数据');
sessionStorage.setItem('step', '2');
// 读取
const data = sessionStorage.getItem('tempData'); // '临时数据'
const step = sessionStorage.getItem('step'); // '2'(字符串)
// 删除
sessionStorage.removeItem('tempData');
// 清空
sessionStorage.clear();
// 遍历
for (let i = 0; i < sessionStorage.length; i++) {
console.log(sessionStorage.key(i), sessionStorage.getItem(sessionStorage.key(i)));
}属性访问方式
代码示例
// 等价于 setItem / getItem
sessionStorage.username = '张三';
console.log(sessionStorage.username); // '张三'
// 注意:如果键名与 Storage 原型方法同名,属性访问会出问题
sessionStorage.setItem = 'test'; // 不要这样做!
// 应该始终使用方法调用存储复杂数据
代码示例
// 存储对象
const formData = {
name: '张三',
email: 'zhangsan@example.com',
preferences: { theme: 'dark', language: 'zh-CN' }
};
sessionStorage.setItem('formData', JSON.stringify(formData));
// 读取对象
const saved = JSON.parse(sessionStorage.getItem('formData'));四、代码示例
示例一:多步骤表单数据保存
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SessionStorage - 多步骤表单</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh; display: flex; justify-content: center;
align-items: center; padding: 20px;
}
.container {
background: #fff; border-radius: 16px; padding: 40px;
max-width: 520px; width: 100%;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}
.progress-bar {
display: flex; justify-content: space-between;
margin-bottom: 32px; position: relative;
}
.step {
width: 32px; height: 32px; border-radius: 50%;
background: #e0e0e0; color: #999;
display: flex; align-items: center; justify-content: center;
font-size: 14px; font-weight: 700;
transition: all 0.3s;
}
.step.active { background: #667eea; color: #fff; }
.step.done { background: #00b894; color: #fff; }
h2 { font-size: 20px; color: #333; margin-bottom: 24px; }
.form-group { margin-bottom: 18px; }
label {
display: block; font-size: 13px; color: #666;
margin-bottom: 6px; font-weight: 500;
}
input, select {
width: 100%; padding: 10px 14px;
border: 1px solid #ddd; border-radius: 8px;
font-size: 14px; outline: none;
}
input:focus, select:focus { border-color: #667eea; }
.btn-group { display: flex; gap: 12px; margin-top: 24px; }
button {
flex: 1; padding: 12px; border: none;
border-radius: 8px; font-size: 15px;
font-weight: 600; cursor: pointer;
}
.btn-next { background: #667eea; color: #fff; }
.btn-prev { background: #f0f0f0; color: #555; }
.btn-submit { background: #00b894; color: #fff; }
.step-content { display: none; }
.step-content.active { display: block; }
</style>
</head>
<body>
<div class="container">
<div class="progress-bar">
<div class="step active" id="step1">1</div>
<div class="step" id="step2">2</div>
<div class="step" id="step3">3</div>
</div>
<div class="step-content active" id="stepContent1">
<h2>基本信息</h2>
<div class="form-group">
<label>姓名</label>
<input type="text" id="name" placeholder="请输入姓名">
</div>
<div class="form-group">
<label>邮箱</label>
<input type="email" id="email" placeholder="请输入邮箱">
</div>
<div class="btn-group">
<button class="btn-next" onclick="nextStep(1)">下一步</button>
</div>
</div>
<div class="step-content" id="stepContent2">
<h2>偏好设置</h2>
<div class="form-group">
<label>主题</label>
<select id="theme">
<option value="light">浅色模式</option>
<option value="dark">深色模式</option>
</select>
</div>
<div class="btn-group">
<button class="btn-prev" onclick="prevStep(2)">上一步</button>
<button class="btn-next" onclick="nextStep(2)">下一步</button>
</div>
</div>
<div class="step-content" id="stepContent3">
<h2>确认信息</h2>
<div class="btn-group">
<button class="btn-prev" onclick="prevStep(3)">上一步</button>
<button class="btn-submit" onclick="submitForm()">提交</button>
</div>
</div>
</div>
<script>
const STORAGE_KEY = 'multiStepForm';
function loadFormData() {
const saved = sessionStorage.getItem(STORAGE_KEY);
if (saved) {
try {
const data = JSON.parse(saved);
if (data.name) document.getElementById('name').value = data.name;
if (data.email) document.getElementById('email').value = data.email;
if (data.theme) document.getElementById('theme').value = data.theme;
if (data.currentStep) showStep(data.currentStep);
} catch (e) { console.error('数据恢复失败:', e); }
}
}
function saveStepData(step) {
const saved = sessionStorage.getItem(STORAGE_KEY);
let data = saved ? JSON.parse(saved) : {};
if (step === 1) {
data.name = document.getElementById('name').value;
data.email = document.getElementById('email').value;
} else if (step === 2) {
data.theme = document.getElementById('theme').value;
}
data.currentStep = step;
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(data));
}
function showStep(step) {
document.querySelectorAll('.step-content').forEach(el => el.classList.remove('active'));
document.getElementById('stepContent' + step).classList.add('active');
for (let i = 1; i <= 3; i++) {
const stepEl = document.getElementById('step' + i);
stepEl.className = 'step';
if (i < step) stepEl.classList.add('done');
else if (i === step) stepEl.classList.add('active');
}
}
function nextStep(currentStep) {
saveStepData(currentStep);
showStep(currentStep + 1);
}
function prevStep(currentStep) {
saveStepData(currentStep);
showStep(currentStep - 1);
}
function submitForm() {
const data = JSON.parse(sessionStorage.getItem(STORAGE_KEY));
console.log('提交数据:', data);
sessionStorage.removeItem(STORAGE_KEY);
alert('提交成功!');
}
loadFormData();
</script>
</body>
</html>示例二:页面状态保持与恢复
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SessionStorage - 页面状态保持</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background: #f5f7fa; min-height: 100vh; padding: 30px 20px;
}
.container { max-width: 640px; margin: 0 auto; }
h1 { font-size: 24px; color: #2d3436; margin-bottom: 8px; }
.desc { color: #636e72; font-size: 14px; margin-bottom: 24px; }
.card {
background: #fff; border-radius: 12px; padding: 24px;
margin-bottom: 16px; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
}
.card h2 { font-size: 16px; color: #2d3436; margin-bottom: 16px; }
.tabs {
display: flex; gap: 4px; background: #f0f0f0;
border-radius: 8px; padding: 4px; margin-bottom: 16px;
}
.tab {
flex: 1; padding: 8px; text-align: center;
border-radius: 6px; font-size: 13px; font-weight: 600;
cursor: pointer; color: #666;
}
.tab.active {
background: #fff; color: #0984e3;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
}
.tab-content { display: none; }
.tab-content.active { display: block; }
</style>
</head>
<body>
<div class="container">
<h1>页面状态保持与恢复</h1>
<p class="desc">使用 sessionStorage 保存页面状态,刷新页面后自动恢复。</p>
<div class="card">
<h2>标签页状态</h2>
<div class="tabs" id="tabs">
<div class="tab active" data-tab="tab1" onclick="switchTab('tab1')">推荐</div>
<div class="tab" data-tab="tab2" onclick="switchTab('tab2')">最新</div>
<div class="tab" data-tab="tab3" onclick="switchTab('tab3')">热门</div>
</div>
<div class="tab-content active" id="tab1">
<p style="color:#666;font-size:14px;">推荐内容区域</p>
</div>
<div class="tab-content" id="tab2">
<p style="color:#666;font-size:14px;">最新内容区域</p>
</div>
<div class="tab-content" id="tab3">
<p style="color:#666;font-size:14px;">热门内容区域</p>
</div>
</div>
</div>
<script>
const STATE_KEY = 'pageState';
function getSavedState() {
try {
const saved = sessionStorage.getItem(STATE_KEY);
return saved ? JSON.parse(saved) : {};
} catch (e) { return {}; }
}
function saveState(key, value) {
const state = getSavedState();
state[key] = value;
sessionStorage.setItem(STATE_KEY, JSON.stringify(state));
}
function switchTab(tabId) {
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
document.querySelector('.tab[data-tab="' + tabId + '"]').classList.add('active');
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
document.getElementById(tabId).classList.add('active');
saveState('activeTab', tabId);
}
function restoreState() {
const state = getSavedState();
if (state.activeTab) switchTab(state.activeTab);
}
restoreState();
</script>
</body>
</html>五、浏览器兼容性
六、注意事项与最佳实践
1. 数据生命周期
-
标签页关闭即丢失:不要存储需要跨会话持久化的数据
-
刷新不丢失:适合保存表单草稿等临时数据
-
新标签页独立:每个标签页有独立的 sessionStorage,不会互相干扰
2. 容量管理
代码示例
// 检查存储是否可用
function checkSessionStorage() {
try {
sessionStorage.setItem('__test__', '1');
sessionStorage.removeItem('__test__');
return true;
} catch (e) {
return false;
}
}
// 安全写入
function safeSessionSet(key, value) {
try {
sessionStorage.setItem(key, value);
return true;
} catch (e) {
console.warn('sessionStorage 写入失败:', e);
return false;
}
}3. 数据安全
-
sessionStorage 中的数据可被开发者工具直接查看和修改
-
不要存储密码、密钥等敏感信息
-
存储的数据在客户端,不要信任其完整性
4. 性能建议
-
避免存储过大的数据(建议不超过 1MB)
-
读写操作是同步的,大数据量会影响页面性能
-
频繁读写时考虑使用内存变量缓存
七、代码规范示例
代码示例
// 推荐:封装 SessionStorage 工具类
class SessionStore {
constructor(prefix = '') {
this.prefix = prefix;
this.available = this._checkAvailability();
}
_checkAvailability() {
try {
const key = '__ss_test__';
sessionStorage.setItem(key, '1');
sessionStorage.removeItem(key);
return true;
} catch (e) {
console.warn('sessionStorage 不可用');
return false;
}
}
_getKey(key) {
return this.prefix ? this.prefix + ':' + key : key;
}
set(key, value) {
if (!this.available) return false;
try {
sessionStorage.setItem(this._getKey(key), JSON.stringify(value));
return true;
} catch (e) {
return false;
}
}
get(key, defaultValue = null) {
if (!this.available) return defaultValue;
try {
const raw = sessionStorage.getItem(this._getKey(key));
return raw !== null ? JSON.parse(raw) : defaultValue;
} catch (e) {
return defaultValue;
}
}
remove(key) {
if (!this.available) return;
sessionStorage.removeItem(this._getKey(key));
}
clear() {
if (!this.available) return;
if (!this.prefix) {
sessionStorage.clear();
return;
}
const keys = [];
for (let i = 0; i < sessionStorage.length; i++) {
const k = sessionStorage.key(i);
if (k.startsWith(this.prefix + ':')) keys.push(k);
}
keys.forEach(k => sessionStorage.removeItem(k));
}
}
// 使用示例
const session = new SessionStore('myapp');
session.set('formDraft', { name: '张三', step: 2 });
const draft = session.get('formDraft', {});八、常见问题与解决方案
常见问题
window.open 打开的新标签页能访问父页面的 sessionStorage 吗?
新标签页会获得父标签页 sessionStorage 的一份快照副本,但之后两者互不影响。修改一方的数据不会反映到另一方。
如何实现跨标签页的临时数据共享?
sessionStorage 本身不支持跨标签页共享。如需跨标签页通信,可使用:localStorage + storage 事件、BroadcastChannel API 或 SharedWorker。
页面刷新后 sessionStorage 数据丢失?
原因:可能是浏览器隐私模式限制、代码中误调用了 sessionStorage.clear()、或浏览器设置中禁用了存储。
解决方案:检查隐私模式设置,排查代码中的 clear 调用。
如何检测 sessionStorage 是否被用户禁用?
解决方案:使用检测函数尝试写入和删除测试数据,捕获异常判断是否可用。
九、总结
SessionStorage 提供了会话级别的键值对存储,其标签页隔离特性使其非常适合存储临时性数据,如多步骤表单的中间状态、页面交互状态(标签页选中、筛选条件、勾选状态)、滚动位置等。使用时需注意其生命周期(标签页关闭即清除)、容量限制(5-10MB)和数据安全(不要存储敏感信息)。通过合理的封装和状态恢复机制,可以显著提升用户体验,避免因页面刷新导致的数据丢失。
本文涉及AI创作
内容由AI创作,请仔细甄别