将React二叉树动画迁移到Vue,是否可以在watcher中使用setInterval?
问题根因
你当前的实现出现异常确实和递归触发watch以及定时器滥用直接相关,核心问题有三个:
- 你在
time的监听回调中修改time的值,每次修改都会再次触发watch,进而源源不断创建新的setInterval实例,多个定时器同时累加time,自然会导致动画速度失控,和DELAY_IN_MS配置无关 - 你没有对创建的定时器做清理逻辑,即便
isUpdating变为false,之前创建的所有定时器依然会持续运行 - 当
isUpdating为false时,你给setInterval传入null作为间隔值,浏览器会自动使用最小延时(通常为4ms),进一步加快了time的累加速度
正确实现方案
你不需要监听time的变化,改为监听isUpdating状态来启停定时器即可,同时注意保存定时器ID方便清理:
Vue2 选项式API实现
data() { return { time: 0, isUpdating: false, timerId: null, // 保存定时器ID // 其余业务字段 DELAY_IN_MS: 1000, maxTimes: 10, animate: true } }, watch: { isUpdating(newVal) { // 状态变化时先清理旧定时器 if (this.timerId) { clearInterval(this.timerId) this.timerId = null } if (newVal) { // 启动新定时器 this.timerId = setInterval(() => { if (this.time >= this.maxTimes) { this.isUpdating = false return } this.time = this.animate ? Math.min(this.time + 1, this.maxTimes) : this.maxTimes }, this.DELAY_IN_MS) } } }, // 组件卸载时清理定时器,避免内存泄漏 beforeDestroy() { if (this.timerId) { clearInterval(this.timerId) } }
Vue3 组合式API实现(供参考)
import { ref, watch, onUnmounted } from 'vue' const time = ref(0) const isUpdating = ref(false) const maxTimes = ref(10) const animate = ref(true) const DELAY_IN_MS = 1000 let timerId = null watch(isUpdating, (newVal) => { if (timerId) { clearInterval(timerId) timerId = null } if (newVal) { timerId = setInterval(() => { if (time.value >= maxTimes.value) { isUpdating.value = false return } time.value = animate.value ? Math.min(time.value + 1, maxTimes.value) : maxTimes.value }, DELAY_IN_MS) } }) onUnmounted(() => { if (timerId) clearInterval(timerId) })
内容的提问来源于stack exchange,提问作者djangodev
相关产品推荐
相关产品推荐

