vue3 原生实现防抖
优点:实现简单,适合简单场景
例子:输入姓名、关键词延时搜索,操作更新后的DOM
watch实现
HTML代码:
<template>
<input v-model="name" ref="inputEl" />
<input v-model="searchKeyword" ref="inputEl" />
</template>
TS 代码
<script setup lang="ts">
import { ref, watchEffect, watchPostEffect } from 'vue'
const name = ref('')
const searchKeyword = ref('')
watch(
[name, searchKeyword],
(newValue, oldValue, cleanup) => {
let timer = setTimeout(() => {
console.log("设置定时")
doSearch() // 执行搜索
}, 500)
cleanup(() => {
console.log("清除定时")
clearTimeout(timer)
})
},
{ deep: true }
)
</script>
watchEffect实现
HTML代码:
<template>
<input v-model="name" ref="inputEl" />
<input v-model="searchKeyword" ref="inputEl" />
</template>
TS 代码
<script setup lang="ts">
import { ref, watchEffect, watchPostEffect } from 'vue'
const name = ref('')
const searchKeyword = ref('')
// 防抖搜索,清理定时器
watchEffect((onCleanup) => {
// 访问所有响应式依赖,确保watchEffect能追踪变化
name.value
searchKeyword.value
// 实现防抖
const t = setTimeout(() => {
console.log("设置定时")
doSearch() // 执行搜索
}, 500)
onCleanup(() => {
console.log("清除定时")
clearTimeout(timer) //清除定时
})
})
</script>
第三方库 Lodash 防抖(项目常用)
VUE原生实现,开发很少用,一般直接使用成熟库,如:Lodash
功能强大,稳定,适合有多个输入框等复杂的场景
安装
npm i lodash
使用
import { debounce } from 'lodash';
// 延迟500ms执行
const fn = debounce(function(e) {
console.log(e.target.value);
}, 500);
// 立即执行,leading=true,trailing=false
const btnFn = debounce(submit, 1000, { leading: true, trailing: false });
// 取消防抖(组件销毁时释放定时器,防止内存泄漏)
fn.cancel();
Lodash 参数说明:_.debounce(func, wait, options)
- wait:等待毫秒
- options.leading:true=首次立即执行
- options.trailing:true=延迟后执行最后一次
- options.maxWait:最大等待时间(结合节流特性)
Vue3 + Lodash 实现防抖
<template>
<input @input="handleInput" />
</template>
<script setup>
import { debounce } from './utils';
const query = (e) => {
console.log("搜索", e.target.value);
};
// 生成防抖函数,仅创建一次
const handleInput = debounce(query, 400);
</script>
常见坑与优化
组件销毁未清除定时器 → 内存泄漏
解决:lodash提供.cancel(),手写防抖可增加取消方法:function debounce(fn, delay) { let timer = null; const debounced = function (...args) { if (timer) clearTimeout(timer); timer = setTimeout(() => fn.apply(this, args), delay); }; // 暴露取消方法 debounced.cancel = () => clearTimeout(timer); return debounced; } // 组件卸载时调用 debounced.cancel()每次渲染重复生成防抖函数,防抖失效
Vue/React中必须缓存防抖函数(useCallback、setup顶层定义),不能写在渲染循环内部。delay 设置过小,失去防抖意义
小于100ms基本和不防抖无区别,推荐300ms起步。