usedebouncedref 是最贴合 vue 3 响应式特性的防抖方案,通过 customref 拦截 set 实现延迟赋值,配合 track/trigger 保证响应式更新,闭包维护状态,支持 v-model 双向绑定且业务层无感。

直接用 customRef 封装防抖逻辑,是最贴合 Vue 3 响应式特性的做法——它不破坏 v-model 的双向绑定体验,又能把输入延迟更新这件事“藏”在响应式数据内部,业务层完全无感。
用 customRef 写一个防抖 ref
核心是拦截 set 操作:每次用户输入,先清掉旧定时器,再设新定时器;等延迟结束才真正赋值并触发视图更新。
- 必须调用
track()(在get中)让 Vue 知道谁依赖这个值 - 必须调用
trigger()(在set的定时器回调里)通知 Vue 值已变 - 闭包保存原始值和定时器,避免污染全局或组件状态
代码示例(可直接复用)
新建 useDebouncedRef.ts:
使用 `@ainative/vue-sdk` 为 Vue 3 应用添加 AI 聊天功能。适用于以下场景:(1) 安装 `@ainative/vue-sdk`,(2) 在 Vue 组件中使用 `useChat` 组合式函数,(3) 提供……
import { customRef } from 'vue'
<p>export function useDebouncedRef<t>(value: T, delay = 300) {
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)
}
}))
}</t></p>
在组件中使用
和普通 ref 一样用,v-model 依然生效:
<script setup lang="ts">
import { useDebouncedRef } from './useDebouncedRef'
<p>const searchKeyword = useDebouncedRef('', 500)
</script><p><template><input v-model="searchKeyword" placeholder="输入关键词..."><p>当前值:{{ searchKeyword }}</p>
</template></p>
注意:搜索逻辑应监听 searchKeyword 的变化(比如用 watch),而不是原生 input 事件——这样自然就只在防抖后触发一次。
进阶要点
- 如果需要手动触发立即提交(比如点击搜索按钮),可在 customRef 返回对象里加
flush()方法 - 如需取消待定更新(比如组件卸载前清理),加
cancel()并在onBeforeUnmount中调用 - 不建议在
watch里对普通 ref 手动加 debounce 函数——那样只是延迟了副作用,响应式数据本身仍是实时更新的,没解决根本问题
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










