Vue.js中如何监听当前时间变化实现token过期自动登出功能
问题根源
Date.now()不属于Vue的响应式依赖项,你通过computed定义的currentTime没有可检测的响应式依赖变化,会一直返回缓存的计算结果,值不会自动更新,对应的watcher自然无法触发。
解决方案
1. 将currentTime改为响应式状态变量并定时更新
不要用computed定义currentTime,改为在响应式状态中声明,通过定时器定期更新它的值,你需求的最小提醒粒度为1分钟,设置30秒的更新间隔足够覆盖所有场景,不会产生多余性能开销。
Vue3 组合式API示例
import { ref, onMounted, onUnmounted, watch } from 'vue' import { useStore } from 'vuex' // 用Pinia同理导入对应store即可 const store = useStore() const currentTime = ref(Date.now()) let timeUpdateTimer = null // 标记已弹出过的提醒,避免重复触发 const notifiedIntervals = ref([]) onMounted(() => { // 每30秒更新一次当前时间 timeUpdateTimer = setInterval(() => { currentTime.value = Date.now() }, 30 * 1000) }) onUnmounted(() => { // 组件卸载时清除定时器,避免内存泄漏 if (timeUpdateTimer) clearInterval(timeUpdateTimer) })
Vue2/选项式API示例
export default { data() { return { currentTime: Date.now(), timeUpdateTimer: null, notifiedIntervals: [] } }, mounted() { this.timeUpdateTimer = setInterval(() => { this.currentTime = Date.now() }, 30 * 1000) }, beforeDestroy() { if (this.timeUpdateTimer) clearInterval(this.timeUpdateTimer) } }
2. 调整watcher逻辑避免重复提醒
原有watcher逻辑可以正常复用,建议增加提醒标记逻辑,避免同一提醒被重复触发:
// 以Vue3为例,选项式写法逻辑完全一致 watch(currentTime, (newVal) => { const expiryTime = localStorage.getItem('scatTokenExpiryTime') if (!expiryTime) return const expiryTimestamp = Number(expiryTime) const remainSeconds = (expiryTimestamp - newVal) / 1000 // 过期直接登出 if (remainSeconds <= 0) { store.dispatch('logoutUser') // 登出后清除定时器和提醒标记 if (timeUpdateTimer) clearInterval(timeUpdateTimer) notifiedIntervals.value = [] return } // 对应分钟数转秒数判断,避免重复弹窗 const checkIntervals = [30*60, 5*60, 1*60] checkIntervals.forEach(interval => { if (remainSeconds <= interval && remainSeconds > interval - 30 && !notifiedIntervals.value.includes(interval)) { handleDialog(`${interval/60}分钟后登录状态将过期,请及时操作`) notifiedIntervals.value.push(interval) } }) })
额外注意
如果该token校验逻辑需要全局生效,建议把上述代码放在根组件App.vue中实现,避免页面切换时组件销毁导致定时器被清除,逻辑失效。
内容的提问来源于stack exchange,提问作者rhythmo
相关产品推荐
相关产品推荐

