You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在React JS中如何禁止用户打开同一网站的多个标签页

限制网站单实例运行解决多标签页账号信息错乱问题

问题本质

同域下的localStorage是所有标签页共享的,当用户在多个标签页登录不同账号时,后写入的用户信息会覆盖已有的存储内容,导致各标签页读取的用户信息不匹配,出现业务逻辑错乱。

实现方案

我们可以通过全局实例锁+storage事件监听的机制实现单实例限制,具体实现逻辑如下:

基础实现步骤

  • 页面初始化时生成当前实例的唯一ID:const currentInstanceId = Math.random().toString(36).slice(2)
  • 读取localStorage中存储的全局运行实例标识SITE_RUNNING_INSTANCE_ID:
    • 如果标识为空,说明当前无运行实例,将自身ID写入该字段,完成实例锁占用
    • 如果标识不为空且不等于当前实例ID,说明已有其他实例运行,直接提示用户「当前网站仅允许同时打开一个标签页」,并调用window.close()关闭当前页面
  • 监听全局storage事件,当检测到其他页面尝试修改SITE_RUNNING_INSTANCE_ID时,若当前页面是持有锁的实例,立即将该字段的值改回自身ID,拦截新实例的启动请求
  • 监听页面beforeunload事件,当前持锁实例关闭时,删除SITE_RUNNING_INSTANCE_ID字段释放锁,允许后续新实例启动

代码示例

// 初始化实例ID
const currentInstanceId = Math.random().toString(36).slice(2);
const INSTANCE_KEY = 'SITE_RUNNING_INSTANCE_ID';

// 检查是否已有运行实例
const existedInstanceId = localStorage.getItem(INSTANCE_KEY);
if (existedInstanceId && existedInstanceId !== currentInstanceId) {
  alert('当前网站仅允许同时打开一个标签页');
  window.close();
  // 防止close被浏览器拦截的兜底逻辑,可以跳转到空白提示页
  // window.location.href = 'about:blank';
}

// 占用实例锁
localStorage.setItem(INSTANCE_KEY, currentInstanceId);

// 监听其他实例的启动请求,拦截抢占
window.addEventListener('storage', (e) => {
  if (e.key === INSTANCE_KEY && e.newValue !== currentInstanceId) {
    localStorage.setItem(INSTANCE_KEY, currentInstanceId);
  }
});

// 页面关闭时释放锁
window.addEventListener('beforeunload', () => {
  if (localStorage.getItem(INSTANCE_KEY) === currentInstanceId) {
    localStorage.removeItem(INSTANCE_KEY);
  }
});

异常兼容优化

如果遇到页面崩溃、进程被强制杀死等极端情况,beforeunload事件不会触发,会导致实例锁一直被占用无法启动新实例,可以增加心跳机制解决:

  • 持锁实例每隔10s往localStorage写入SITE_INSTANCE_HEARTBEAT时间戳
  • 新实例启动时如果发现存在实例锁,但心跳时间距离当前超过30s,判定旧实例已失效,直接抢占实例锁即可

可选替代方案

如果你的业务场景不需要严格限制单实例,只是要解决多账号登录信息不冲突的问题,可以将用户敏感信息存储到仅当前标签页生效的sessionStorage中,也可以避免跨标签页的信息覆盖问题。

内容的提问来源于stack exchange,提问作者Anjali Shah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 20:06:03