绝大多数人清除定时器的方法
<script> export default { data() { return { timer: null } }, mounted() { this.timer = setInterval(() => { console.log('我是定时器') }, 1000) }, beforeDestroy() { clearInterval(this.timer) } } </script>
这样写的缺点
上面是一段常见的代码 至少我身边的好几个小伙伴都是这么写的,这里存在3个不优雅的问题: 第1个:clearInterval 后没有清空 timer 为 null。 第2个:开启定时器和清除定时器的代码分散开在两个地方,可读性/维护性下降. 第3个:timer 被定义在 data 里,实际上 timer 不需要什么响应式操作,定义在 data 里是没必要的,反而造成性能浪费。
使用 hook 监听 beforeDestroy 生命
export default { data() { return { } }, mounted() { let timer = setInterval(() => { console.log('---定时器在触发---') }, 1000) this.$once('hook:beforeDestroy', () => { console.log('这里使用 hook 监听 beforeDestroy 生命') clearInterval(timer) timer = null }) }, methods: { backPage() { this.$router.back() } } } </script>
这里使用 hook 监听 beforeDestroy 生命周期. 这样 timer 只需被定义在生命周期里,以上的问题就全部解决了。 ps: hook 是可以监听vue的生命周期的。
如果项目中使用了-- keep-alive 如何解决
在后台系统中,我们常常会设置页面缓存。 而当路由被 keep-alive 缓存时是不走 beforeDestroy 生命周期的。 此时将不能清除定时器。这时候我们需要借助 activated 和 deactivated 这两个生钩子: activated 是进入页面的时候被触发 deactivated 是离开页面的时候会被触发,我们将在这个页面清除定时器
<script> export default { mounted() { // 开启定时器 let timer = setInterval(() => { console.log('---定时器在触发---') }, 1000) //这下面的代码不可以省略 this.$on('hook:activated', () => { if (timer === null) { // 避免重复开启定时器 timer = setInterval(() => { console.log('setInterval') }, 1000) } }) this.$on('hook:deactivated', () => { clearInterval(timer) timer = null }) } } <script>
这里需要注意一下,由于缓存原因. 所以需要用 $on 而不是 $once 因此$once 只会触发一次的哈
$on 和 $once 的区别
Api 中的解释: $on(eventName:string|Array, callback) 监听事件 监听当前实例上的自定义事件。事件可以由 vm.$emit 触发。 回调函数会接收所有传入事件触发函数的额外参数。 $once(eventName: string, callback) 监听事件 监听一个自定义事件,但是只触发一次。一旦触发之后,监听器就会被移除。
vue3中如何使用
在vue3中 $on进行监听,$off取消监听 和 $once 实例方法已被移除. 所以无法优雅的清除定时器了。