display: none 切换标签页仍触发重复请求,因其仅隐藏DOM而不暂停子资源(如iframe、video),且第三方组件无法自动恢复状态;hidden属性可真正暂停资源加载,配合JS缓存才能避免重复请求。

为什么 display: none 切换标签页还会触发重复请求
视觉上隐藏的 DOM 节点(如用 display: none)确实保留在内存里,但它的子资源不会被暂停:iframe 仍在加载、video 可能继续缓冲、fetch 或 XMLHttpRequest 请求若在组件 mounted 后发起,每次切换回来都会重新执行。更隐蔽的问题是第三方库(比如 ECharts、Quill)常依赖 resize 或 visibilitychange 事件初始化,display: none 后再显示,它们往往无法自动恢复状态,开发者只能手动重绘——这本质上还是新请求。
用 hidden 属性 + JS 状态管理才是真缓存
hidden 是原生 HTML 属性,浏览器会真正暂停其内部资源加载:video 暂停播放、iframe 卸载、audio 停止解码。配合 JS 缓存关键数据,才能避免重复请求:
- 切换前把表单值、滚动位置、选中项存进
sessionStorage或Map实例(注意同域限制) - 切换回该标签页时,先检查缓存是否存在,再还原 DOM 状态,而非重新
fetch - 对富文本编辑器等复杂组件,用
hidden触发其beforeunload类似逻辑,再显式调用editor.restore()而非重建实例
示例逻辑:
const tabCache = new Map();
function hideTab(tabId) {
const el = document.getElementById(tabId);
el.hidden = true;
tabCache.set(tabId, {
scrollTop: el.scrollTop,
formData: new FormData(el.querySelector('form')),
});
}
function showTab(tabId) {
const el = document.getElementById(tabId);
el.hidden = false;
const cache = tabCache.get(tabId);
if (cache) {
el.scrollTop = cache.scrollTop;
// 还原输入框值,不重发请求
}
}
SPA 中路由级缓存必须绕开 v-if
Vue/React 的条件渲染指令(如 v-if、useState 配合条件返回 JSX)会在标签页切换时销毁组件实例,再次进入就重新 mount —— 所有副作用(API 请求、定时器、Observer)全重来。正确做法是:
立即学习“前端免费学习笔记(深入)”;
- 用
v-show替代v-if控制显隐(前提是 DOM 节点数量可控) - 在组件内部用
useEffect/onMounted加守卫:只在首次加载时请求,后续复用缓存数据 - 对列表类页面,把分页参数、筛选条件作为缓存 key 存入
sessionStorage,避免切回来又拉第 1 页
服务端模板碎片缓存不能漏掉可变维度
如果后端做了 SSR 模板缓存(比如缓存了用户头像栏),但 key 没包含 user_id 或 locale,多个用户可能拿到同一份缓存 HTML,导致 A 用户看到 B 用户的订单数或未读消息。必须确保:
- 缓存 key 包含所有影响输出的变量:URL query、用户身份、设备类型(
isMobile)、AB 测试分组 - 含内联
<script></script>的模板片段禁止缓存——SSR 渲染后脚本已执行,客户端再 hydrate 会重复执行 - 缓存失效不靠
max-age=3600,而靠明确信号:CMS 更新事件、构建 hash 变更、数据库行变更通知
最易被忽略的是:前端以为自己“缓存了状态”,其实后端模板缓存 key 写死了,结果用户切标签页再回来,看到的是别人的数据。



















