Vue 3 中可通过自定义 useDebouncedRef 封装防抖逻辑,接收初始值和延迟毫秒数,返回含 .value、.set()、.cancel()、.flush() 的响应式对象,内部用 setTimeout/clearTimeout 控制更新,并在组件卸载时自动清理定时器。

Vue 3 中可以通过自定义 ref 封装防抖逻辑,让响应式数据在变化时自动延迟更新,避免高频触发(如搜索输入、窗口缩放、表单校验等)带来的性能问题。核心思路是:用 ref 包裹原始值,内部维护一个定时器,在新值到来时清除旧定时器、重设延迟赋值。
封装可复用的防抖 ref 工厂函数
不依赖第三方库,纯 Composition API 实现:
- 接收初始值和防抖毫秒数(默认 300ms),返回一个带
.value的响应式引用 - 内部使用
setTimeout+clearTimeout控制更新时机 - 支持手动触发立即提交(
.flush())和取消待定更新(.cancel())
示例代码:
import { ref, onBeforeUnmount } from 'vue'
export function useDebouncedRef(value, delay = 300) {
const debouncedValue = ref(value)
let timer = null
const cancel = () => {
if (timer) {
clearTimeout(timer)
timer = null
}
}
const flush = () => {
if (timer) {
clearTimeout(timer)
timer = null
// 立即同步当前 pending 值(若需)
// 此处可扩展为传入 pending 值或保留上一次 set 的值
}
}
const setValue = (newValue) => {
cancel()
timer = setTimeout(() => {
debouncedValue.value = newValue
}, delay)
}
// 组件卸载前清理定时器,防止内存泄漏
onBeforeUnmount(cancel)
return {
value: debouncedValue,
set: setValue,
cancel,
flush
}
}
在组件中使用防抖 ref 处理搜索输入
替代 v-model 直连,把用户输入“缓冲”后再触发请求:
立即学习“前端免费学习笔记(深入)”;
审查 Vue 管理后台的变更请求(Vue 2 + Element UI,Vue 3 + Element Plus)。重点关注最小化变更实现、上线风险检查以及回归检查清单生成。
- 绑定
<input @input="debouncedSearch.set($event.target.value)"> - 监听
debouncedSearch.value的变化(配合watch),只在防抖结束后发起 API 请求 - 可添加 loading 状态,避免重复点击或连续输入造成多请求
注意:不要直接对 debouncedSearch.value 赋值,否则绕过防抖逻辑;必须通过 .set() 方法更新。
进阶:支持 deep 防抖与异步 resolve 场景
当需要防抖对象属性变更或等待异步操作完成再更新时,可增强工厂函数:
- 增加
transform参数,在设值前对新值做预处理(如 trim、转小写) - 支持 Promise 返回:在
setValue中 await 异步逻辑,再更新value - 结合
computed暴露“是否处于防抖中”的状态(isPending),用于 UI 反馈(如禁用按钮、显示加载点)
例如搜索框加个“正在搜索…”提示,就靠这个状态驱动。
避坑指南:生命周期与响应式边界
实际开发中容易忽略的关键细节:
-
onBeforeUnmount清理定时器是必须的,否则组件销毁后仍可能触发.value更新,导致警告或异常 - 防抖 ref 不应被解构使用(如
const { value } = useDebouncedRef(...)),会丢失响应性;应始终通过原对象访问.value - 如果多个地方调用
.set(),确保它们共享同一个实例;不要在循环或条件中反复创建新 ref - SSR 场景下
setTimeout不可用,需判断环境或改用nextTick模拟(精度略低但安全)

















