在项目开发中,点击按钮提交表单是比较常见的需求,在某些情况下,用户可能会快速连续触发同一个事件,这可能导致不必要的重复操作或性能问题。为了解决这个问题,我们可以使用防抖技术(确保函数在一段时间内只执行一次)。像后台管理系统有多个页面用到,因此我们可以封装为指令。
技术栈:Vue(3.5.12)、TypeScript(5.1.6)、Element Plus(2.8.8)、UnoCSS(0.55.2)
-
指令TypeScript脚本
- 指令名称:我们定义了一个名为
debounce
的自定义指令。 - 延迟时间:可以通过指令的参数来指定防抖动的延迟时间,默认是 300 毫秒。
- 创建防抖动函数:使用
lodash-es
提供的debounce
函数来创建防抖动函数。 - 事件绑定:在元素上绑定防抖动函数,并在元素卸载时移除绑定。
import type { DirectiveBinding } from 'vue'
import { debounce } from 'lodash-es'
interface ElType extends HTMLElement {
__debouncedFn__?: () => void
}
export default {
name: 'debounce',
option: {
mounted: (el: ElType, binding: DirectiveBinding) => {
if (typeof binding.value !== 'function') {
console.warn('v-debounce: provided expression must be a function')
return
}
// 如果传递了参数就用参数,否则默认300毫秒
const delay = binding.arg ? parseInt(binding.arg, 10) : 300
// 创建 debounced 函数
const debouncedFn = debounce(binding?.value, delay)
// 在元素上存储 debounced 函数,以便在卸载时可以访问它
el.__debouncedFn__ = debouncedFn
// 添加事件监听
el.addEventListener('click', debouncedFn)
},
beforeUnmount(el: ElType) {
// 移除事件监听
if (el.__debouncedFn__) {
el.removeEventListener('click', el.__debouncedFn__)
delete el.__debouncedFn__
}
}
}
}
-
引入并注册指令
在main.ts中添加指令相关的代码:
import vDebounce from './directives/clickDebounce' // 假设指令文件位于 src/directives/clickDebounce.ts
const app = createApp(App);
// 注册全局指令
app.directive(vDebounce.name, vDebounce.option)
app.mount('#app');
-
模板中使用
默认防抖动的延迟时间是300毫秒,如需修改请改成:v-debounce:1000(你期望的时间)
<template>
<el-button v-debounce="handleClick" type="primary">确认</el-button>
</template>
<script setup>
function handleClick() {
console.log('Button clicked!')
}
</script>
实现效果
编辑
需求拓展
想到有时输入框或者其他业务也有做防抖的需求,或许可以拓展一下指令,兼容其他的事件,一劳永逸。还没想好怎么实现,先立个flag。
编辑
以上就是自定义防抖指令的实现啦^-^