防抖节流封装模式

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)
})

优雅之处

  • 提升性能,避免频繁触发
  • 改善用户体验(搜索、滚动)
  • 可取消的防抖

创建于 2026/5/27 更新于 2026/5/27