如何区分单页应用的页面导航与刷新并按需清理缓存
我开发的单页应用采用URL格式:https://hostname/{organizationIdentifier}/#{pagePath},基于sessionStorage实现了缓存机制。当用户切换组织上下文(URL中organizationIdentifier变更)时,我希望触发缓存清理。为此我实现了window.addEventListener("beforeunload", cleanCache),也尝试过navigation.addEventListener("navigate", navigateAction)但未成功。但目前页面刷新时cleanCache也会被触发,请问如何检测卸载后将加载同URL的情况?如何仅在离开应用上下文或切换组织上下文时触发cleanCache?
核心思路
刷新页面时,浏览器会加载与当前完全一致的URL(包括organizationIdentifier和哈希路由);而离开应用或切换组织时,目标URL要么是外部域名,要么是同域名但organizationIdentifier不同。我们可以通过对比当前URL与跳转目标URL,结合页面加载/卸载的状态判断,精准触发缓存清理。
具体实现方法
1. 处理SPA内的组织切换
SPA的哈希路由变化不会触发beforeunload,需要单独监听哈希变化,结合存储的历史组织标识判断:
// 页面初始化时记录当前组织标识 window.addEventListener('load', () => { const currentOrg = window.location.pathname.split('/')[1]; sessionStorage.setItem('currentOrganization', currentOrg); }); // 监听SPA哈希路由变化 window.addEventListener('hashchange', () => { const currentOrg = window.location.pathname.split('/')[1]; const prevOrg = sessionStorage.getItem('currentOrganization'); if (prevOrg && prevOrg !== currentOrg) { // 组织标识变更,清理缓存 cleanCache(); } // 更新存储的组织标识 sessionStorage.setItem('currentOrganization', currentOrg); });
2. 区分页面刷新与离开/跨组织跳转
beforeunload中无法直接获取目标URL,需要提前监听用户操作记录跳转目标,再结合导航类型判断:
let targetUrl = null; // 提前记录用户点击的链接目标 document.addEventListener('mousedown', (e) => { const link = e.target.closest('a'); if (link) { targetUrl = link.href; } }); // 监听页面卸载 window.addEventListener('beforeunload', () => { const currentOrg = window.location.pathname.split('/')[1]; const navigationType = performance.getEntriesByType('navigation')[0]?.type; const isRefresh = navigationType === 'reload'; if (isRefresh) { // 刷新操作,不清理缓存 return; } if (targetUrl) { const url = new URL(targetUrl); if (url.host !== window.location.host) { // 跳转到外部域名,清理缓存 cleanCache(); } else { const targetOrg = url.pathname.split('/')[1]; if (targetOrg !== currentOrg) { // 同域名但组织变更,清理缓存 cleanCache(); } } } else { // 无跳转目标(关闭标签页/窗口),清理缓存 cleanCache(); } // 重置目标URL targetUrl = null; });
3. 框架路由兼容(可选)
如果使用React、Vue等框架,可以直接利用框架的路由钩子监听组织标识变化,比如React:
import { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; function useOrgCacheCleanup() { const location = useLocation(); useEffect(() => { const currentOrg = location.pathname.split('/')[1]; const prevOrg = sessionStorage.getItem('currentOrganization'); if (prevOrg && prevOrg !== currentOrg) { cleanCache(); } sessionStorage.setItem('currentOrganization', currentOrg); }, [location.pathname]); }
关键注意事项
- 不要依赖已废弃的
performance.navigation,改用performance.getEntriesByType('navigation')[0].type判断刷新状态。 - SPA内的路由切换不会触发
beforeunload,必须单独监听哈希变化或框架路由钩子。 - 对于非链接触发的跳转(比如JS跳转),需要额外监听
window.location.href的变化,或在跳转逻辑中主动判断组织标识并清理缓存。
内容的提问来源于stack exchange,提问作者Jan Stanicek

