【vue】封装一个可随时暂停启动无需担心副作用的定时器
【vue】封装一个可随时暂停启动无需担心副作用的定时器
- 现成轮子:VueUse 库的 useIntervalFn 方法
- 是什么?
- 为什么要用它?
- 怎么用?
- 分析源码 & 自己手写一个
- 源码
- 自己手写
现成轮子:VueUse 库的 useIntervalFn 方法
是什么?
创建定时器的组合式函数
为什么要用它?
- 定时执行回调(入参;回调函数、时间间隔、配置项)
- 控制定时器的行为(返回:开始、暂停定时器的方法)
- 响应式间隔(入参的时间间隔可以是一个 响应式引用ref 或者一个函数,当它的值改变,定时器会自动更新其间隔时间,无需手动重启定时器)
- 立即执行选项(入参 options.immediate 控制 是否在初始化时立即启动定时器;入参 options.immediateCallback 控制是否在调用resume方法猴立即执行一次回调函数)
怎么用?
官网有说怎么安装依赖,就不过多解释:https://vueuse.org/shared/useIntervalFn/
分析源码 & 自己手写一个
源码
https://github1s.com/vueuse/vueuse/blob/main/packages/shared/useIntervalFn/index.ts
自己手写
安装vue-demi
依赖后,就可以开始手写啦~
import type { ComputedRef, Ref, ShallowRef, WritableComputedRef } from 'vue-demi'
import { getCurrentScope, isRef, onScopeDispose, ref, unref, watch } from 'vue-demi'
/**
* Void函数
*/
export type Fn = () => void
/**
* 任意函数
*/
export type AnyFn = (...args: any[]) => any
/**
* 它可能是一个 ref 对象,或者一个普通的值
*/
export type MaybeRef<T = any> =
| T
| Ref<T>
| ShallowRef<T>
| WritableComputedRef<T>
/**
* 它可能是一个 ref 对象,或者一个普通的值,或者一个 getter 函数
* @param cb
* @param interval
*/
export type MaybeRefOrGetter<T = any> = MaybeRef<T> | ComputedRef<T> | (() => T)
/**
* 获取值、ref 或 getter 的实际值
*/
export function toValue<T>(r: MaybeRefOrGetter<T>): T {
return typeof r === 'function' ? (r as AnyFn)() : unref(r)
}
/***
* 是否为客户端
*/
export const isClient = typeof window !== 'undefined' && typeof document !== 'undefined'
/**
* 是否处于一个 Vue 3 的响应式 effect 生命周期的作用域内。如果是的话,它会注册一个清理函数(fn 参数),该函数会在作用域结束时执行;如果不是在这样的作用域内,那么它将不做任何操作。
* @param fn
*/
export function tryOnScopeDispose(fn: Fn) {
if (getCurrentScope()) {
onScopeDispose(fn)
return true
}
return false
}
export interface UseIntervalOptions {
/**
* 立即执行这个定时器
*/
immediate?: boolean
/**
* 在调用 resume 函数后,立即执行回调函数
*/
immediateCallback?: boolean
}
export interface Pausable {
/**
* 一个 ref 表示 pausable 实例是否处于活动状态
*/
isActive: Readonly<Ref<boolean>>
/**
* 暂停定时器
*/
pause: Fn
/**
* 恢复定时器
*/
resume: Fn
}
export function useIntervalFn(cb: Fn, interval: MaybeRefOrGetter<number> = 1000, options: UseIntervalOptions = {}): Pausable {
const {
immediate = true,
immediateCallback = true
} = options
let timer: ReturnType<typeof setInterval> | null = null
const isActive = ref(false)
function clean() {
if (timer) {
clearInterval(timer)
timer = null
}
}
function pause() {
isActive.value = false
clean()
}
function resume() {
const intervalValue = toValue(interval)
if (intervalValue <= 0) {
return
}
isActive.value = true
if (immediateCallback){
cb()
}
clean()
if (isActive.value) {
timer = setInterval(cb, intervalValue)
}
}
if (immediate && isClient) {
resume()
}
if (isRef(interval) || typeof interval === 'function') {
const stopWatch = watch(interval, () => {
if (isActive.value && isClient) {
resume()
}
})
tryOnScopeDispose(stopWatch)
}
tryOnScopeDispose(pause)
return {
isActive,
pause,
resume
}
}