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

Vue3 + TypeScript下实现EventBus式会话超时自动登出方案求助

Vue3 复刻会话丢失监听与自动登出实现方案

1. 实现类型安全的事件总线(基于tiny-typed-emitter)

先定义事件类型接口,确保TypeScript类型校验:

// src/utils/eventBus.ts
import { TypedEmitter } from 'tiny-typed-emitter';

// 定义所有事件类型
interface SessionEvents {
  LostSession: () => void;
  ResetIdleTimer: () => void;
}

// 创建事件总线实例
export const eventBus = new TypedEmitter<SessionEvents>();

2. 封装空闲监听的Composable

把空闲计时器逻辑封装成可复用的composable,方便组件调用:

// src/composables/useIdleSession.ts
import { onMounted, onUnmounted } from 'vue';
import { eventBus } from '@/utils/eventBus';

// 配置超时时间(示例为30分钟,单位毫秒)
const IDLE_TIMEOUT = 30 * 60 * 1000;
let idleTimer: NodeJS.Timeout | null = null;

// 重置空闲计时器的方法
const resetIdleTimer = () => {
  if (idleTimer) clearTimeout(idleTimer);
  idleTimer = setTimeout(() => {
    // 超时触发会话丢失事件
    eventBus.emit('LostSession');
  }, IDLE_TIMEOUT);
};

// 绑定用户输入事件
const bindUserEvents = () => {
  // 监听鼠标移动、点击、键盘输入
  window.addEventListener('mousemove', resetIdleTimer);
  window.addEventListener('click', resetIdleTimer);
  window.addEventListener('keydown', resetIdleTimer);
};

// 解绑用户输入事件
const unbindUserEvents = () => {
  window.removeEventListener('mousemove', resetIdleTimer);
  window.removeEventListener('click', resetIdleTimer);
  window.removeEventListener('keydown', resetIdleTimer);
  if (idleTimer) clearTimeout(idleTimer);
};

export const useIdleSession = () => {
  onMounted(() => {
    // 初始化时启动计时器
    resetIdleTimer();
    bindUserEvents();
    // 监听外部的重置计时器事件(比如用户主动操作后手动触发)
    eventBus.on('ResetIdleTimer', resetIdleTimer);
  });

  onUnmounted(() => {
    unbindUserEvents();
    eventBus.off('ResetIdleTimer', resetIdleTimer);
  });

  return { resetIdleTimer };
};

3. 在组件中使用(以根组件App.vue为例)

在需要监听会话的组件中,引入composable并监听LostSession事件:

<!-- src/App.vue -->
<template>
  <!-- 应用内容 -->
</template>

<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue';
import { eventBus } from '@/utils/eventBus';
import { useIdleSession } from '@/composables/useIdleSession';

// 启用空闲会话监听
useIdleSession();

// 监听会话丢失事件,执行登出逻辑
const handleLostSession = () => {
  // 替换为实际登出逻辑:清除token、跳转登录页等
  console.log('会话超时,自动登出');
  // router.push('/login');
};

onMounted(() => {
  eventBus.on('LostSession', handleLostSession);
});

onUnmounted(() => {
  eventBus.off('LostSession', handleLostSession);
});
</script>

适配emittery的替代方案

如果用emittery实现事件总线,只需调整事件总线代码,逻辑一致:

// src/utils/eventBus.ts
import Emittery from 'emittery';

type SessionEvents = {
  LostSession: void;
  ResetIdleTimer: void;
};

export const eventBus = new Emittery<SessionEvents>();

调用时依旧用eventBus.emit('LostSession')和eventBus.on('LostSession', handleLostSession)即可。

关键注意事项

  • 组件卸载时必须移除所有事件监听和计时器,避免内存泄漏。
  • 若需手动重置计时器(如用户提交表单后),直接调用eventBus.emit('ResetIdleTimer')即可。

内容的提问来源于stack exchange,提问作者D Miller

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 11:52:15