路由守卫不直接清理定时器,因其仅在路由跳转时触发,而页面刷新、关闭等场景不执行;必须以onBeforeUnmount/onDeactivated为主清理入口,路由守卫仅作补充检查。

Vue 路由守卫本身不直接负责清除定时器,它只做“跳转前拦截”;真正清理资源必须靠生命周期钩子(如 onUnmounted 或 onDeactivated)。但你可以把路由守卫和清理逻辑配合使用:在守卫中提前触发清理动作,或作为兜底检查环节。
为什么不能只靠路由守卫清理定时器
路由守卫(如 beforeRouteLeave)只在**路由跳转时触发**,而定时器泄漏发生在组件卸载后仍运行。如果用户是刷新页面、关闭标签页、输入新 URL,这些场景根本不会走 Vue Router 守卫——beforeRouteLeave 压根不执行。所以单靠它清理,漏掉 70% 以上泄漏风险。
正确做法:以生命周期为主,路由守卫为辅
定时器必须在组件真正退出生命周期时销毁。推荐组合使用:
将静态 Vue 页面(index.vue)改造为动态页面(Custom.vue);稿源仅限 index.vue、其引用的 CSS 与资源路径,禁止参考仓库内其他文件。Invoke when user wants to transform a static Vue page into a dynamic data-driven page with Element UI components.
-
onMounted:启动定时器,并用
ref存储 ID(避免闭包引用丢失) -
onBeforeUnmount(或 onUnmounted):主动
clearInterval/clearTimeout,这是主清理入口 - beforeRouteLeave:作为补充,在跳转前再检查一次是否已清理;若未清,可手动补救(比如调用一个清理函数)
具体写法示例(Vue 3 + Composition API)
下面是一个安全可靠的结构:
立即学习“前端免费学习笔记(深入)”;
import { ref, onMounted, onBeforeUnmount, onActivated, onDeactivated } from 'vue'
import { useRoute, useRouter } from 'vue-router'
export default {
setup() {
const timer = ref(null)
const route = useRoute()
const router = useRouter()
const startTimer = () => {
timer.value = setInterval(() => {
console.log('running...')
}, 3000)
}
const clearTimer = () => {
if (timer.value) {
clearInterval(timer.value)
timer.value = null
}
}
onMounted(() => {
startTimer()
})
// 主清理:组件卸载时必执行
onBeforeUnmount(() => {
clearTimer()
})
// 补充:路由离开前再确认一遍(防 keep-alive 场景下 onBeforeUnmount 不触发)
router.beforeEach((to, from, next) => {
if (from.name === route.name) {
clearTimer()
}
next()
})
// 如果用了 keep-alive,还需配合 onDeactivated/onActivated
onDeactivated(() => {
clearTimer()
})
onActivated(() => {
startTimer()
})
return {}
}
}
特别注意 keep-alive 场景
若页面被 <keep-alive></keep-alive> 缓存(如若依后台),onBeforeUnmount 可能完全不触发。此时必须依赖:
- onDeactivated:页面隐藏时立刻停掉定时器
- onActivated:页面重新显示时再启动(不要重复启动,先判断 timer 是否为空)
- 避免在
watch或轮询逻辑里无条件重设定时器,否则会叠加多个实例


















