一介绍
防抖与节流,应用场景有很多,例如:禁止重复提交数据的场景、搜索框输入搜索条件,待输入停止后再开始搜索。
防抖
点击button按钮,设置定时器,在规定的时间内再次点击会重置定时器重新计时,在规定的时间没有再次点击才执行相关函数。
规定时间内最后一次点击有效。
节流
点击button按钮,执行相关函数。设置定时器,在规定的时间内连续点击均无效,定时器过后,可以再次点击。
规定时间内可点击一次(第一次点击有效)。
案例-防抖
Vue项目中使用自定义指令实现(按钮)防抖功能。
应用场景:搜索框输入搜索条件,待输入停止后再开始搜索。
案例-节流
Vue项目中使用自定义指令实现(按钮)节流功能。
应用场景:click事件,禁止重复提交数据的场景。
二 使用
debounceThrottle.ts
import { App, Directive } from "vue"// 防抖指令
export const debounce: Directive = {mounted(el: HTMLElement, binding) {if (!validateBinding(binding, "debounce")) returnlet timer: number | null = nullconst eventType = binding.arg || "click"const delay = binding.value.time || 300const handler = binding.value.handlerconst args = binding.value.args || [] // 参数数组const listener = () => {if (timer) clearTimeout(timer)timer = window.setTimeout(() => {handler(...args) // 执行方法并传递参数}, delay)}el.addEventListener(eventType, listener);(el as any).__debounce_listener__ = listener // 保存监听器以便卸载时移除},unmounted(el: HTMLElement) {removeListener(el, "__debounce_listener__", "debounce")}
}// 节流指令
export const throttle: Directive = {mounted(el: HTMLElement, binding) {if (!validateBinding(binding, "throttle")) returnlet lastTime = 0const eventType = binding.arg || "click"const delay = binding.value.time || 300const handler = binding.value.handlerconst args = binding.value.args || [] // 参数数组const listener = () => {const now = Date.now()if (now - lastTime >= delay) {handler(...args) // 执行方法并传递参数lastTime = now}}el.addEventListener(eventType, listener);(el as any).__throttle_listener__ = listener // 保存监听器以便卸载时移除},unmounted(el: HTMLElement) {removeListener(el, "__throttle_listener__", "throttle")}
}// 校验绑定值
function validateBinding(binding: any, directiveName: string): boolean {if (!binding.value ||typeof binding.value.handler !== "function" ||(binding.value.args && !Array.isArray(binding.value.args))) {console.warn(`[v-${directiveName}]: Expected an object with a "handler" function, optional "time" (number), and optional "args" (array). Example: { time: 300, handler: () => {...}, args: [arg1, arg2] }`)return false}return true
}// 移除事件监听器
function removeListener(el: HTMLElement, listenerKey: string, directiveName: string) {const eventType = el.getAttribute(`v-${directiveName}-event`) || "click"const listener = (el as any)[listenerKey]if (listener) {el.removeEventListener(eventType, listener)}
}
index.ts
import { debounce, throttle } from "./debounceThrottle"export default {debounce,throttle,
}
main.ts
import { createApp } from "vue"
import App from "./App.vue"
import directives from "@/directives"const app = createApp(App)// 批量注册自定义指令
Object.keys(directives).forEach((directiveName) => {app.directive(directiveName, directives[directiveName])
})
使用
<el-buttontype="primary"v-if="hasAuth"v-throttle:click="{ time: 500, handler: onSaveAndAuth }">保存并验证</el-button>const onSaveAndAuth = () => {contactsFormRef.value?.validate((valid) => {valid && saveContact(1)})
}