customref 实现防抖响应式输入框的核心是手动控制 track() 收集依赖和 trigger() 触发更新,通过 settimeout 延迟 innerref.value 赋值并通知更新,避免 v-model 即时响应。

用 customRef 实现带防抖的响应式输入框,核心在于**手动控制依赖收集与触发更新**,避开 v-model 的即时响应,把赋值和更新时机交给防抖逻辑控制。
理解 customRef 的关键作用
customRef 不像 ref 那样自动追踪,它让你完全掌控:
– 什么时候收集依赖(track())
– 什么时候通知更新(trigger())
– 甚至可以拦截读写行为(比如延迟写入、忽略中间值)
实现防抖 ref 的基本结构
定义一个 useDebouncedRef 工厂函数,接收初始值和延迟时间:
- 内部用
ref存原始值,用于真实数据流 - 用
setTimeout和clearTimeout管理防抖定时器 -
get中调用track(),确保组件能响应变化 -
set中不立即更新ref,而是重置定时器,延迟后才提交
完整可运行代码示例
在 Vue 3 setup 中使用:
import { customRef, ref } from 'vue'
function useDebouncedRef(value, delay = 300) {
const innerRef = ref(value)
let timeout = null
return customRef((track, trigger) => ({
get() {
track() // 告诉 Vue:这里用了这个值,需要响应
return innerRef.value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
innerRef.value = newValue
trigger() // 值真正变了,通知所有依赖更新
}, delay)
}
}))
}
// 组件中
export default {
setup() {
const searchQuery = useDebouncedRef('', 500)
return {
searchQuery
}
}
}
模板中直接绑定:<input v-model="searchQuery"> —— 它会正常读写,但 searchQuery.value 的变化会被防抖延迟。
注意事项与优化点
– 防抖期间若组件卸载,记得清理定时器(可在 onUnmounted 中 clearTimeout)
– 如需立刻获取最新输入(比如按 Enter 立即搜索),可额外暴露一个 flush() 方法强制提交
– 若需兼容首次输入不防抖(如空值转非空时立即触发),可在 set 中加判断逻辑
– 多个防抖 ref 共用一个 timer 变量会导致冲突,每个实例应独占自己的 timeout










