customref 更合适,因其将读写逻辑封装于响应式引用内部,天然支持 v-model,精准控制 track/trigger 时机,避免 watch + settimeout 的清理遗漏和重复触发问题。

在 Vue 3 Composition API 中,用 customRef 实现输入框防抖,核心是让响应式值“读取时可追踪、更新时有节制”——用户每打一个字,模板不立刻重渲染;只有停止输入、延迟到期后,才真正更新值并触发视图响应。
为什么 customRef 比 watch + setTimeout 更合适
watch 方式需额外监听 ref 变化、手动控制定时器、再赋新值,容易漏掉清理或重复触发;而 customRef 把读写逻辑收束到一个响应式引用内部,天然支持 v-model,且能精准控制依赖收集(track)和更新通知(trigger)的时机:
- 每次 get 时调用
track(),确保模板能响应当前值 - 每次 set 不立即更新,而是清旧定时器、设新延迟
- 延迟结束才把值写入内部变量,并调用
trigger()通知更新 - 中间所有输入都不触发计算属性重算或模板刷新
封装一个可复用的 useDebouncedRef
下面是一个生产可用的防抖响应式引用 Hook,支持类型推导、默认延迟、自动清理:
import { customRef } from 'vue'
export function useDebouncedRef<t>(value: T, delay = 300) {</t> let timeout: NodeJS.Timeout | null = null return customRef((track, trigger) => ({ get() { track() return value }, set(newValue) { if (timeout) clearTimeout(timeout) timeout = setTimeout(() => { value = newValue trigger() }, delay) } }))}
在组件中直接绑定 v-model
它行为上与普通 ref 几乎一致,但自带防抖逻辑:
<template></template> <input v-model="searchText" placeholder="输入搜索关键词..."> <p>当前值:{{ searchText }}</p>
<script setup></script>import { useDebouncedRef } from './debounceRef'const searchText = useDebouncedRef('', 500)
你甚至可以基于它进一步封装搜索逻辑:当 searchText 真正变化时(即 trigger 后),再调用 API 请求建议列表,避免请求堆积。
注意组件卸载时的定时器清理
上面基础版未显式清理定时器,实际项目中建议增强健壮性:
- 在
onBeforeUnmount中手动clearTimeout(timeout) - 或改用
onScopeDispose(推荐),在作用域销毁时自动清理 - 也可扩展返回对象,暴露
cancel和flush方法供外部控制
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










