行走的范儿 發表於 2025-8-20 09:06:00

Web前端入门第 84 问:JavaScript sessionStorage 那些容易踩坑的地方

<p>sessionStorage 与 localStorage 差不多可以算作一对兄弟,它俩的暴露的 API 方法一模一样。</p>
<p>但两者也有不同点:</p>
<p>1、sessionStorage 存入的数据在页面关闭后,会自动清除。<br>
2、相同 URL 的每个 tab 页签的 sessionStorage 会被隔离,互不影响。也就是说相同的链接,在 A 标签页打开和在 B 标签打开,A 写入的 sessionStorage 数据,B 是<strong>无法读取</strong>的!!这里与 <code>会话 Cookie</code> 完全不一样。<br>
3、在页面中使用 <code>&lt;a target="_blank" rel="opener"&gt;</code> 和 <code>window.open</code> 打开新的标签页,sessionStorage 数据会<strong>复制</strong>,但之后的修改相互隔离。<br>
4、sessionStorage 存入的数据会在浏览器打开期间一直保留,刷新页面或使用 <code>ctrl + shift + t</code> 恢复页面时,数据不会丢失。</p>
<h2 id="api">API</h2>
<p><code>sessionStorage</code> 暴露的接口与 <code>localStorage</code> 一致:</p>
<pre><code class="language-js">// 只读属性,返回会话存储项的数目
sessionStorage.length

// 获取会话存储的第 n 个键名
sessionStorage.key(n)
// 获取会话存储的值
sessionStorage.getItem(key)
// 写入会话存储
sessionStorage.setItem(key, value)
// 删除会话存储
sessionStorage.removeItem(key)
// 清空所有会话存储
sessionStorage.clear()
</code></pre>
<p>API 使用示例:</p>
<pre><code class="language-js">(() =&gt; {
// 写入数据
sessionStorage.setItem('type', '公众号');
sessionStorage.setItem('name', '前端路引');

// 获取会话存储长度
console.log(sessionStorage.length);

// 循环打印会话存储
for (let i = 0; i &lt; sessionStorage.length; i++) {
    const key = sessionStorage.key(i);
    const value = sessionStorage.getItem(key);
    console.log(`${key}: ${value}`);
}
// 移除单个会话存储
sessionStorage.removeItem('name');
// 移除所有会话存储
sessionStorage.clear();
})()
</code></pre>
<h2 id="无法监听存储数据变化">无法监听存储数据变化</h2>
<p>不像 <code>localStorage</code>,sessionStorage 没有暴露 <code>onchange</code> 事件,所以无法监听到数据变化,就算模拟自定义事件,也只能在当前页面中获得事件,无法跨页面通信。以下代码只能在本页面中监听 <code>sessionStorage</code> 数据改变:</p>
<pre><code class="language-js">(() =&gt; {
// 移除所有会话存储
sessionStorage.clear();

// 监听 storage 事件
window.addEventListener('storage', e =&gt; {
    console.log(e);
})

// 自定义写入函数,封装事件派发
function setItem (key, value) {
    // 模拟 storage 事件
    const ev = new StorageEvent('storage', {
      key,
      newValue: value,
      oldValue: sessionStorage.getItem(key),
      url: location.href,
    });
    window.dispatchEvent(ev);
    sessionStorage.setItem(key, value);
}

setItem('type', '公众号');
setItem('name', '前端路引');
})()
</code></pre>
<p>测试结果:</p>
<p><img src="https://img2024.cnblogs.com/blog/596097/202508/596097-20250820090509657-1693322787.png"></p>
<h2 id="新开页面复制-sessionstorage">新开页面复制 sessionStorage</h2>
<p>在 <code>a</code> 标签中添加 <code>rel="opener"</code> 可令新开的页面获得父页面中的 sessionStorage 数据(复制方式)。</p>
<p><code>window.open</code> 方法打开的页面也是一样的道理。</p>
<p>注意:此时获得数据仅仅是副本,不共享,所以在新页面或旧页面中修改数据时,两者互不影响。</p>
<p><code>a</code> 标签默认是 <code>noopener</code>,如果不显示设置 <code>rel="opener"</code>,无法获得数据副本!!</p>
<p><strong>测试代码:</strong></p>
<pre><code class="language-html">&lt;a
href="./example-84-3.html"
target="_blank"
&gt;a 标签打开本页面&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a
href="./example-84-3.html"
target="_blank"
rel="opener"
&gt;a 标签 opener 打开本页面&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a
href="./example-84-3.html"
target="_blank"
rel="noopener"
&gt;a 标签 noopener 打开本页面&lt;/a&gt;&lt;br&gt;&lt;br&gt;

&lt;button
onclick="window.open('./example-84-3.html')"
&gt;window.open 打开本页面&lt;/button&gt;&lt;br&gt;&lt;br&gt;
&lt;button
onclick="window.open('./example-84-3.html', '_blank', 'noopener')"
&gt;window.open noopener 打开本页面&lt;/button&gt;&lt;br&gt;&lt;br&gt;

&lt;button id="set"&gt;写入新的 sessionStorage&lt;/button&gt;&lt;br&gt;&lt;br&gt;
&lt;button id="get"&gt;获取 sessionStorage&lt;/button&gt;&lt;br&gt;&lt;br&gt;

&lt;div id="output"&gt;&lt;/div&gt;

&lt;script&gt;
(() =&gt; {
    const output = document.querySelector('#output');
    document.querySelector('#set').addEventListener('click', e =&gt; {
      sessionStorage.setItem('now', Date.now());
    })

    document.querySelector('#get').addEventListener('click', e =&gt; {
      const now = sessionStorage.getItem('now');
      output.innerText = now ?? '无';
    })
})()
&lt;/script&gt;
</code></pre>
<p>测试结果:</p>
<p><img src="https://img2024.cnblogs.com/blog/596097/202508/596097-20250820090518172-1311333789.gif"></p>
<h2 id="大小限制">大小限制</h2>
<p>与 <code>localStorage</code> 一样限制 <code>5MB</code> 大小(所有键值加在一起的长度),溢出后写入报错,此处推荐阅读前一篇文章:{%post_link 'wechat-web-front-end-83'%}</p>
<p>测试代码:</p>
<pre><code class="language-js">(() =&gt; {
// 移除所有会话存储
sessionStorage.clear();
const key = 'name';
const max = 5 * 1024 * 1024;
// 测试极限值
// const value = 'a'.repeat(max - key.length);
// 测试中文
// const value = '中'.repeat(max - key.length);
// 测试溢出
const value = 'a'.repeat(max - key.length + 1);
sessionStorage.setItem(key, value);
// 测试多个项溢出情况
// sessionStorage.setItem('key', '1');
// 测试与 localStorage 是否共用存储空间
// localStorage.setItem('key', '1');
})()
</code></pre>
<p>溢出结果:</p>
<p><img src="https://img2024.cnblogs.com/blog/596097/202508/596097-20250820090632875-1102484581.png"></p>
<p>结论:setItem 多个子项时,公用 <code>5MB</code> 存储空间(中英文计算方式一致),溢出时写入报错,并且与 <code>localStorage</code> <strong>不共用</strong>存储空间!使用 <code>rel="opener"</code> 打开链接时,会获得父页面的副本数据,所以新开的页面仅能写入 <strong>5MB - 副本数据</strong> 等到的剩下空间。</p>
<p>可使用以下代码判断是否拥有副本数据:</p>
<pre><code class="language-js">if (window.opener) {
// opener 存在表示拥有副本
// 极限情况再写入新的数据报错
sessionStorage.setItem('now', Date.now());
}
</code></pre>
<h2 id="刷新与恢复页面">刷新与恢复页面</h2>
<p>页面刷新时和关闭页面后再使用 <code>ctrl+shift+t</code> 恢复页面,<code>sessionStorage</code> 数据不会丢失。</p>
<p>测试代码:</p>
<pre><code class="language-html">&lt;button id="set"&gt;写入新的 sessionStorage&lt;/button&gt;&lt;br&gt;&lt;br&gt;
&lt;button id="get"&gt;获取 sessionStorage&lt;/button&gt;&lt;br&gt;&lt;br&gt;

&lt;div id="output"&gt;&lt;/div&gt;

&lt;script&gt;
(() =&gt; {
    const output = document.querySelector('#output');
    document.querySelector('#set').addEventListener('click', e =&gt; {
      sessionStorage.setItem('now', Date.now());
    })

    document.querySelector('#get').addEventListener('click', e =&gt; {
      const now = sessionStorage.getItem('now');
      output.innerText = now ?? '无';
    })
})()
&lt;/script&gt;
</code></pre>
<p>效果:</p>
<p><img src="https://img2024.cnblogs.com/blog/596097/202508/596097-20250820090639663-122760503.gif"></p>
<h2 id="写在最后">写在最后</h2>
<p>sessionStorage 仅支持字符串存储,所以 JS 中用的 JSON 数据需要格式化为字符串存储~~</p>
<p>sessionStorage 一般多用于临时数据存储,比如一些表单填写的临时数据,单页应用页面间的数据传递等。</p>
<p>其生命周期有点短暂,浏览器或标签页关闭就会消失,就像浮游一样,朝生暮死...</p>


</div>
<div id="MySignature" role="contentinfo">
    <p>&nbsp;</p>
<p style="font-size: 18px;font-weight: bold;">文章首发于微信公众号【<span style="color:rgb(255, 71, 87)">前端路引</span>】,欢迎 <span style="color:#4ec259">微信扫一扫</span> 查看更多文章。</p>
<p>
<img style="max-width: 320px;" src="https://images.cnblogs.com/cnblogs_com/linx/2447020/o_250228035031_%E5%85%AC%E4%BC%97%E5%8F%B7%E4%BA%8C%E7%BB%B4%E7%A0%81.png"/>
</p>
<p>本文来自博客园,作者:前端路引,转载请注明原文链接:https://www.cnblogs.com/linx/p/19047887</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/linx/p/19047887
頁: [1]
查看完整版本: Web前端入门第 84 问:JavaScript sessionStorage 那些容易踩坑的地方