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
相关产品推荐
相关产品推荐

