useDebouncedRef 是 Vue 3 中基于 customRef 实现防抖 ref 的最佳实践,它通过延迟 trigger() 实现响应式更新,支持 v-model 直接绑定,内部自动管理定时器与依赖追踪。

在 Vue 3 中,用 customRef 实现防抖 ref 是最干净、最响应式友好的方式——它让防抖逻辑完全内聚在 ref 本身,模板中仍可直接用 v-model,无需改写事件监听或手动拆解绑定。
核心原理:延迟触发响应式更新
防抖 ref 的关键不是“延迟赋值”,而是“延迟通知 Vue 值已变”。每次输入都清除旧定时器,只让最后一次输入的定时器执行 trigger(),从而确保视图只在用户停顿后更新一次。
-
get 里必须调用
track():否则模板无法建立依赖,值变了也不刷新 -
set 里必须调用
trigger():否则依赖收不到更新信号,界面卡住 - 内部值(
value)可随时被读取,但只有定时器完成时才真正变更并触发响应
封装一个可复用的 useDebouncedRef
下面是一个 TypeScript 友好、生产可用的实现:
<script setup></script>
import { customRef } from 'vue'
function useDebouncedRef
let timeout: NodeJS.Timeout | null = null
return customRef((track, trigger) => ({
get() {
track()
return initialValue
},
set(newValue) {
if (timeout) clearTimeout(timeout)
timeout = setTimeout(() => {
initialValue = newValue
trigger()
}, delay)
}
}))
}
const search = useDebouncedRef('', 500)
从零开始编排 SpringBoot+Vue 全栈项目工作流,适用于新建全栈项目或完整脚手架请求,触发后依次调用 product‑spec‑builder(需求调研)等模块。
模板中直接使用 v-model
因为它是标准 ref,所以绑定方式和普通 ref 完全一致:
当前值:{{ search }}
用户连续输入时,search 的值不会实时变化;只有停顿 500ms 后,它才更新并触发后续逻辑(比如 watch 请求接口)。
注意事项:避开常见陷阱
- 不要在
set中直接赋值却不调trigger()——那样值变了但视图不动 - 避免多个
customRef共享同一个timeout或initialValue变量——会导致相互覆盖 - 延迟时间按场景调整:搜索建议常用 300–500ms,表单自动保存可设为 800–1200ms
- 如需手动触发立即更新(比如点击搜索按钮),可在函数中调用
clearTimeout(timeout)并立刻set
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!









