防抖节流封装模式
VueUse 风格的防抖与节流函数封装
#tech / dev / frontend
#type / concept
#status / evergreen
防抖节流封装模式
前端性能优化:防抖(debounce)与节流(throttle)的 Vue 3 封装
VueUse 风格的防抖封装
// composables/useDebounce.ts
import { ref, watch, unref, type Ref } from 'vue'
export const useDebounceFn = <T extends (...args: any[]) => any>(
fn: T,
delay = 300
) => {
let timer: ReturnType<typeof setTimeout> | null = null
const debouncedFn = (...args: Parameters<T>) => {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn(...args)
}, delay)
}
const cancel = () => {
if (timer) {
clearTimeout(timer)
timer = null
}
}
return { debouncedFn, cancel }
}
export const useDebounce = <T>(value: Ref<T>, delay = 300) => {
const debounced = ref(unref(value)) as Ref<T>
let timer: ReturnType<typeof setTimeout> | null = null
watch(value, (newValue) => {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
debounced.value = newValue
}, delay)
})
return debounced
}
// 使用示例
const searchText = ref('')
const debouncedSearch = useDebounce(searchText, 500)
watch(debouncedSearch, (value) => {
// 只有在用户停止输入 500ms 后才触发搜索
performSearch(value)
})
// 防抖函数
const { debouncedFn } = useDebounceFn(handleSearch, 500)
节流封装
// composables/useThrottle.ts
export const useThrottleFn = <T extends (...args: any[]) => any>(
fn: T,
delay = 300
) => {
let lastTime = 0
const throttledFn = (...args: Parameters<T>) => {
const now = Date.now()
if (now - lastTime >= delay) {
lastTime = now
fn(...args)
}
}
return { throttledFn }
}
// 使用示例 - 滚动加载
const { throttledFn: handleScroll } = useThrottleFn(() => {
const scrollTop = document.documentElement.scrollTop
const clientHeight = document.documentElement.clientHeight
const scrollHeight = document.documentElement.scrollHeight
if (scrollTop + clientHeight >= scrollHeight - 100) {
loadMore()
}
}, 200)
onMounted(() => {
window.addEventListener('scroll', handleScroll)
})
onUnmounted(() => {
window.removeEventListener('scroll', handleScroll)
})
优雅之处:
- 提升性能,避免频繁触发
- 改善用户体验(搜索、滚动)
- 可取消的防抖