废话不多说直接上代码
/**
* 创建一个防抖函数。
*
* @param {Function} fn - 需要防抖的函数。
* @param {number} delay - 防抖延迟时间,单位毫秒。
* @return {Object} 包含防抖函数和取消函数的对象。
*/
export function debounce<T extends (...args: any[]) => any>(fn: T, delay: number = 500) {
let timeout: ReturnType<typeof setTimeout> | null = null;
const debouncedFn = (...args: Parameters<T>) => {
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(() => fn(...args), delay);
};
return { debouncedFn };
}
vue3中有所不同 直接看代码
import { Directive, DirectiveBinding, watchEffect } from "vue";
import { debounce } from "@/utils/debounce";
/**
* Vue 自定义指令,提供防抖功能。
*
* 使用方法:
* 在元素上应用 v-debounce 指令,并传入一个对象,该对象包含:
* - fn: 需要防抖的函数。
* - event: 触发防抖的事件类型,可以是一个字符串或字符串数组。
* - delay (可选): 防抖延迟时间,单位毫秒,默认为 500 毫秒。
*
* 示例:
* <button v-debounce="{ fn: handleClick, event: ['click', 'mouseover'], delay: 300 }">Click me</button>
*/
const vDebounce: Directive = {
mounted(el: HTMLElement, binding: DirectiveBinding) {
// 提取防抖设置
const stopWatch = watchEffect(() => {
const { fn, event, delay = 500 } = binding.value;
// 校验 fn 和 event 属性
if (typeof fn !== "function" || !event) {
console.warn(
'vDebounce expects an object with "fn" and "event" properties'
);
return;
}
// 移除已存在的防抖事件监听器
removeDebounceListeners(el);
// 支持单个事件或多个事件的数组
const events = Array.isArray(event) ? event : [event];
// 为每个事件添加防抖监听器
el.__debouncedEvents__ = events.map((eventType) => {
const debounceFn = debounce(fn, delay).debouncedFn;
el.addEventListener(eventType, debounceFn);
return { eventType, handler: debounceFn };
});
});
// 在元素上存储停止函数,以便在 beforeUnmount 时调用
el.__stopDebounceWatch__ = stopWatch;
},
beforeUnmount(el: HTMLElement) {
removeDebounceListeners(el);
if (el.__stopDebounceWatch__) {
el.__stopDebounceWatch__(); // 停止 watchEffect
}
},
};
/**
* 移除元素上所有防抖事件监听器。
*
*
* @param {HTMLElement} el - 绑定指令的 DOM 元素。
*/
function removeDebounceListeners(el: HTMLElement) {
if (el.__debouncedEvents__) {
el.__debouncedEvents__.forEach(({ eventType, handler }) => {
el.removeEventListener(eventType, handler);
});
// 清除存储的事件监听器信息
delete el.__debouncedEvents__;
}
}
export default vDebounce;
<template>
<h1>{{ msg }}</h1>
<input v-debounce="{ fn: handleInput, event: 'input', delay: 3000 }" />
<div class="card">
<button type="button" v-debounce="debounce">count is {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
</p>
</div>
<p>
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank">create-vue</a>, the official Vue + Vite
starter
</p>
<p>
Install
<a href="https://github.com/vuejs/language-tools" target="_blank">Volar</a>
in your IDE for a better DX
</p>
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import vDebounce from '@/directives/debounceDirectve'; //导入自定义指令函数
const handleInput = (event: { target: { value: any; }; }) => {
console.log(event.target.value); // 或者您希望执行的其他操作
};
const count = ref(0)
const click = () => {
console.log('click')
debounce.value.delay=debounce.value.delay+1000
count.value++;
}
const debounce = ref(
{ fn: click,
event: 'click',
delay: 2000
}
)
</script>
<style scoped>
.read-the-docs {
color: #888;
}
</style>