在 vue 3 setup 中,应使用 onbeforeunmount 注册清理函数来清除定时器,定时器 id 需用 ref 存储以确保访问最新值;不可在顶层直接调用 clearinterval,避免因 timer 未启动导致无效清理。

在 Vue 3 的 setup 中,组件卸载时清理定时器,不能依赖传统的 beforeUnmount 或 onBeforeUnmount 的“回调注册”思维直接写在 setup 函数体顶层——因为定时器可能在组件创建后异步启动,且需要确保只在组件真正被卸载时才清除。
使用 onBeforeUnmount 注册清理函数
这是最标准、推荐的做法:在 setup 中调用 onBeforeUnmount,把清除定时器的逻辑传入。Vue 会自动在组件卸载前执行它。
注意:定时器 ID(如 setInterval 返回值)需定义为响应式或可变的变量(例如用 ref),以便在清理函数中访问到最新值。
import { ref, onBeforeUnmount } from 'vue'
export default {
setup() {
const timer = ref(null)
const startTimer = () => {
timer.value = setInterval(() => {
console.log('tick')
}, 1000)
}
const stopTimer = () => {
if (timer.value) {
clearInterval(timer.value)
timer.value = null
}
}
// 组件卸载前自动清理
onBeforeUnmount(() => {
stopTimer()
})
return {
startTimer,
stopTimer
}
}
}
避免在 setup 顶层直接调用 clearInterval
以下写法是错误的:
// ❌ 错误:setup 执行时 timer 还没启动,timer.value 是 null onBeforeUnmount(() => clearInterval(timer.value))
必须确保清理逻辑能读取到实际创建的定时器 ID。用 ref 包裹并配合条件判断是最稳妥的方式。
进阶:封装成可复用的定时器 Hook
如果多个组件都需要类似能力,可以抽成组合式函数(Hook):
// composables/useInterval.js
import { ref, onBeforeUnmount } from 'vue'
export function useInterval(callback, delay) {
const timer = ref(null)
const start = () => {
stop()
timer.value = setInterval(callback, delay)
}
const stop = () => {
if (timer.value) {
clearInterval(timer.value)
timer.value = null
}
}
onBeforeUnmount(stop)
return {
start,
stop,
isActive: () => !!timer.value
}
}
在组件中使用:
import { useInterval } from '@/composables/useInterval'
export default {
setup() {
const { start, stop } = useInterval(() => {
console.log('running...')
}, 2000)
return { start, stop }
}
}
补充说明:为什么不用 onUnmounted?
onUnmounted 在组件 DOM 已销毁、响应式系统已停止后触发,此时访问 ref 或调用某些副作用可能不安全。而 onBeforeUnmount 是清理资源(如定时器、事件监听、WebSocket 连接)的正确时机——它保证组件仍处于活跃状态,所有响应式数据和方法都可用。










