useDebouncedRefHistory 是 Vueuse 库中的一个自定义 Hook,它用于在 ref 对象值的修改后添加 debounced history 记录,并支持撤销和重做操作。这个 Hook 的实现与 useRefHistory 类似,但它提供了一个额外的 debounce 选项来设置记录更改的延迟时间。当值被改变时,debounce 选项会防止频繁记录历史,而是等待指定的时间后才记录历史。这样可以避免在值变化过于频繁的情况下,记录太多的历史。
useDebouncedRefHistory 函数接受两个参数:
source:要记录历史的 Ref 对象。options:可选参数对象,其中包含了除eventFilter以外的useRefHistoryOptions配置项,还包括debounce配置项,用于设置防抖时间。
函数返回值是一个 UseRefHistoryReturn 对象,其中包含了当前历史记录、撤销和重做方法等等。
用法示例:
import { ref } from 'vue'
import { useDebouncedRefHistory } from '@vueuse/core'
const counter = ref(0)
const { history, undo, redo } = useDebouncedRefHistory(counter, { deep: true, debounce: 1000 })
源码分析
源码地址:
import type { MaybeRefOrGetter } from '@vueuse/shared'
import { debounceFilter } from '@vueuse/shared'
import type { Ref } from 'vue-demi'
import type { UseRefHistoryOptions, UseRefHistoryReturn } from '../useRefHistory'
import { useRefHistory } from '../useRefHistory'
/**
* Shorthand for [useRefHistory](https://vueuse.org/useRefHistory) with debounce filter.
*
* @see https://vueuse.org/useDebouncedRefHistory
* @param source
* @param options
*/
export function useDebouncedRefHistory<Raw, Serialized = Raw>(
source: Ref<Raw>,
options: Omit<UseRefHistoryOptions<Raw, Serialized>, 'eventFilter'> & { debounce?: MaybeRefOrGetter<number> } = {},
): UseRefHistoryReturn<Raw, Serialized> {
const filter = options.debounce ? debounceFilter(options.debounce) : undefined
const history = useRefHistory(source, { ...options, eventFilter: filter })
return {
...history,
}
}
useDebouncedRefHistory 函数是对 useRefHistory 函数的封装,使用了防抖过滤器来延迟记录历史操作。
在函数内部,根据 options 中的 debounce 配置项是否存在,通过 debounceFilter 函数创建一个防抖过滤器 filter。然后,使用 useRefHistory 函数传入源 source 和配置项(包括防抖过滤器),得到历史记录对象 history。
export function debounceFilter(ms: MaybeRefOrGetter<number>, options: DebounceFilterOptions = {}) {
let timer: ReturnType<typeof setTimeout> | undefined
let maxTimer: ReturnType<typeof setTimeout> | undefined | null
let lastRejector: AnyFn = noop
const _clearTimeout = (timer: ReturnType<typeof setTimeout>) => {
clearTimeout(timer)
lastRejector()
lastRejector = noop
}
const filter: EventFilter = (invoke) => {
const duration = toValue(ms)
const maxDuration = toValue(options.maxWait)
if (timer)
_clearTimeout(timer)
if (duration <= 0 || (maxDuration !== undefined && maxDuration <= 0)) {
if (maxTimer) {
_clearTimeout(maxTimer)
maxTimer = null
}
return Promise.resolve(invoke())
}
return new Promise((resolve, reject) => {
lastRejector = options.rejectOnCancel ? reject : resolve
// Create the maxTimer. Clears the regular timer on invoke
if (maxDuration && !maxTimer) {
maxTimer = setTimeout(() => {
if (timer)
_clearTimeout(timer)
maxTimer = null
resolve(invoke())
}, maxDuration)
}
// Create the regular timer. Clears the max timer on invoke
timer = setTimeout(() => {
if (maxTimer)
_clearTimeout(maxTimer)
maxTimer = null
resolve(invoke())
}, duration)
})
}
return filter
}
debounceFilter 函数的作用是创建一个防抖过滤器,用于延迟执行回调函数并返回一个 Promise。
具体来说,函数的参数如下:
ms:防抖的时间间隔,可以是一个Ref对象或一个返回数字的函数。options:可选的配置对象,包括maxWait和rejectOnCancel。
函数内部定义了一些变量,包括 timer、maxTimer 和 lastRejector。
防抖过滤器的实现逻辑如下:
- 首先,将
ms和options.maxWait转换成实际的数值。 - 如果
timer存在(即已经存在一个定时器),则清除之前的定时器,并调用之前的lastRejector函数进行拒绝处理。 - 如果
duration(防抖间隔)小于等于 0,或者maxDuration(最大等待时间)存在且小于等于 0,则立即执行传入的invoke回调函数,并返回 Promise 对象解决。 - 否则,创建一个 Promise 对象,并在 Promise 构造函数中定义
resolve和reject函数。 - 将
lastRejector设置为options.rejectOnCancel为 true 时的reject函数,否则为resolve函数。 - 如果
maxDuration存在且maxTimer为假值(即没有定时器在等待),则创建一个定时器maxTimer,在达到最大等待时间后执行回调函数,并清除之前的定时器。 - 创建一个定时器
timer,在达到防抖间隔后执行回调函数,并在执行时清除maxTimer。 - 返回 Promise 对象。
debounceFilter 函数用于创建一个防抖过滤器,该过滤器根据指定的时间间隔和最大等待时间来延迟执行回调函数,并返回一个 Promise 对象。在延迟期间,如果有新的调用发生,会取消之前的延迟操作,并重新计时。