From c0078fb410cec0e83695ee97b7edc69a2ec0f45b Mon Sep 17 00:00:00 2001 From: Jakub Freisler Date: Sat, 25 Sep 2021 11:31:55 +0200 Subject: [PATCH] feat(throttleFilter): add leading option (#771) --- packages/shared/useDebounceFn/index.md | 2 +- packages/shared/useThrottle/demo.vue | 4 +++- packages/shared/useThrottle/index.md | 10 ++++++++++ packages/shared/useThrottle/index.ts | 5 +++-- packages/shared/useThrottleFn/index.md | 2 +- packages/shared/useThrottleFn/index.ts | 6 ++++-- packages/shared/utils/filters.ts | 10 ++++++++-- 7 files changed, 30 insertions(+), 9 deletions(-) diff --git a/packages/shared/useDebounceFn/index.md b/packages/shared/useDebounceFn/index.md index f18a5e85e4c7..19357ffad79c 100644 --- a/packages/shared/useDebounceFn/index.md +++ b/packages/shared/useDebounceFn/index.md @@ -17,7 +17,7 @@ const debouncedFn = useDebounceFn(() => { // do something }, 1000) -document.addEventLisenter('resize', debouncedFn) +document.addEventListener('resize', debouncedFn) ``` ## Related Functions diff --git a/packages/shared/useThrottle/demo.vue b/packages/shared/useThrottle/demo.vue index f71f799b1513..58ac7e1af1aa 100644 --- a/packages/shared/useThrottle/demo.vue +++ b/packages/shared/useThrottle/demo.vue @@ -3,8 +3,9 @@ import { ref, watch } from 'vue-demi' import { useThrottle } from '.' const trailing = ref(true) +const leading = ref(false) const input = ref('') -const throttled = useThrottle(input, 1000, trailing.value) +const throttled = useThrottle(input, 1000, trailing.value, leading.value) const updated = ref(0) watch(throttled, () => { @@ -20,5 +21,6 @@ watch(throttled, () => {

Throttled: {{ throttled }}

Times Updated: {{ updated }}

Trailing: {{ trailing }}

+

Leading: {{ leading }}

diff --git a/packages/shared/useThrottle/index.md b/packages/shared/useThrottle/index.md index 3a1738e7cd02..52834ca1a5ef 100644 --- a/packages/shared/useThrottle/index.md +++ b/packages/shared/useThrottle/index.md @@ -26,6 +26,16 @@ const input = ref('') const throttled = useThrottle(input, 1000, false) ``` +### Leading + +Allows the callback to be invoked immediately (on the leading edge of the `ms` timeout). If you don't want this begavior, set 4rd param `false` (it's `true` by default): + +```js +import { useThrottle } from '@vueuse/core' + +const input = ref('') +const throttled = useThrottle(input, 1000, undefined, false) +``` ## Related Functions diff --git a/packages/shared/useThrottle/index.ts b/packages/shared/useThrottle/index.ts index d162374cb134..b76ea18f2a09 100644 --- a/packages/shared/useThrottle/index.ts +++ b/packages/shared/useThrottle/index.ts @@ -8,8 +8,9 @@ import { useThrottleFn } from '../useThrottleFn' * @param value Ref value to be watched with throttle effect * @param delay A zero-or-greater delay in milliseconds. For event callbacks, values around 100 or 250 (or even higher) are most useful. * @param [trailing=true] if true, update the value again after the delay time is up + * @param [leading=true] if true, update the value on the leading edge of the ms timeout */ -export function useThrottle(value: Ref, delay = 200, trailing = true) { +export function useThrottle(value: Ref, delay = 200, trailing = true, leading = true) { if (delay <= 0) return value @@ -17,7 +18,7 @@ export function useThrottle(value: Ref, delay = 200, trailing = true) { const updater = useThrottleFn(() => { throttled.value = value.value - }, delay, trailing) + }, delay, trailing, leading) watch(value, () => updater()) diff --git a/packages/shared/useThrottleFn/index.md b/packages/shared/useThrottleFn/index.md index e00d906cdaf3..80c1c2f0e57f 100644 --- a/packages/shared/useThrottleFn/index.md +++ b/packages/shared/useThrottleFn/index.md @@ -17,7 +17,7 @@ const throttledFn = useThrottleFn(() => { // do something, it will be called at most 1 time per second }, 1000) -document.addEventLisenter('resize', throttledFn) +document.addEventListener('resize', throttledFn) ``` ## Related Functions diff --git a/packages/shared/useThrottleFn/index.ts b/packages/shared/useThrottleFn/index.ts index 877d51a6032b..98189b54db07 100644 --- a/packages/shared/useThrottleFn/index.ts +++ b/packages/shared/useThrottleFn/index.ts @@ -10,11 +10,13 @@ import { createFilterWrapper, FunctionArgs, throttleFilter, MaybeRef } from '../ * * @param [trailing=true] if true, call fn again after the time is up * + * @param [leading=true] if true, call fn on the leading edge of the ms timeout + * * @return A new, throttled, function. */ -export function useThrottleFn(fn: T, ms: MaybeRef = 200, trailing = true): T { +export function useThrottleFn(fn: T, ms: MaybeRef = 200, trailing = true, leading = true): T { return createFilterWrapper( - throttleFilter(ms, trailing), + throttleFilter(ms, trailing, leading), fn, ) } diff --git a/packages/shared/utils/filters.ts b/packages/shared/utils/filters.ts index 79c9f19815f1..6a6e48cb8204 100644 --- a/packages/shared/utils/filters.ts +++ b/packages/shared/utils/filters.ts @@ -66,10 +66,12 @@ export function debounceFilter(ms: MaybeRef) { * * @param ms * @param [trailing=true] + * @param [leading=true] */ -export function throttleFilter(ms: MaybeRef, trailing = true) { +export function throttleFilter(ms: MaybeRef, trailing = true, leading = true) { let lastExec = 0 let timer: ReturnType | undefined + let preventLeading = !leading const clear = () => { if (timer) { @@ -91,15 +93,19 @@ export function throttleFilter(ms: MaybeRef, trailing = true) { if (elapsed > duration) { lastExec = Date.now() - invoke() + if (preventLeading) preventLeading = false + else invoke() } else if (trailing) { timer = setTimeout(() => { lastExec = Date.now() + if (!leading) preventLeading = true clear() invoke() }, duration) } + + if (!leading && !timer) timer = setTimeout(() => preventLeading = true, duration) } return filter