customref 实现输入框防抖响应的核心是手动控制 ref 的 get/set 行为,在 set 时启动防抖逻辑、延迟更新内部值,并在组件卸载前清理定时器;需注意闭包变量管理、定时器清除及初始值响应性。

使用 customRef 实现输入框防抖响应,核心是**手动控制 ref 的 get/set 行为,在 set 时启动防抖逻辑,延迟更新内部值,并在组件卸载前清理定时器**。
理解 customRef 的作用时机
customRef 允许你创建一个响应式引用,并完全自定义它的读取(get)和写入(set)行为。它不直接提供防抖能力,但为你提供了拦截赋值、插入异步逻辑(如 setTimeout)的入口。
关键点:
- 每次用户输入触发
v-model赋值时,都会执行你定义的set函数 - 你在
set中不立即更新内部值,而是用定时器延后更新 - 下一次输入到来时,清除上一个定时器,避免旧任务生效
- 必须在组件卸载时清除残留定时器,防止内存泄漏或状态错乱
封装一个 useDebouncedRef Hook
把防抖逻辑抽成可复用的组合式函数,便于多处使用:
import { customRef, onBeforeUnmount } from 'vue'
export function useDebouncedRef(value, delay = 300) {
let timeout = null
const ref = customRef((track, trigger) => {
return {
get() {
track()
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
}
}
})
// 组件卸载前清理定时器
onBeforeUnmount(() => {
clearTimeout(timeout)
})
return ref
}
在组件中使用
在 <script setup></script> 中引入并使用:
<script setup>
import { useDebouncedRef } from './useDebouncedRef.js'
const searchQuery = useDebouncedRef('', 500)
// 可以监听它做搜索请求等
watch(searchQuery, (newVal) => {
if (newVal) {
console.log('执行搜索:', newVal)
// api.search(newVal)
}
})
</script><template><input v-model="searchQuery" placeholder="输入关键词..."><p>当前值:{{ searchQuery }}</p>
</template>
注意:v-model 会自动调用 searchQuery.value 的 set 方法,所以防抖逻辑自然生效。
注意事项与常见问题
实际使用中需留意以下细节:
-
初始值必须是响应式变量:传给
useDebouncedRef的value是一个普通变量(如字符串),customRef内部靠闭包维护它,不能传入 reactive 对象属性,否则会丢失响应性 -
不要在 setup 中直接修改闭包变量:所有更新应通过 ref 的
set触发,否则不会触发视图更新 - 延迟时间不宜过短:低于 100ms 防抖意义不大;过高则响应迟钝,通常 300–500ms 较平衡
-
需要支持「立即执行首次输入」? 可扩展参数,加入
immediate: true逻辑,首次输入不防抖,后续才启用
不复杂但容易忽略定时器清理和闭包变量管理,按这个模式封装后,就能稳定实现输入即搜、防抖响应的效果。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










