方法一:利用定时器设置时间,下方代码设置时间为1秒
但是有个缺点:请求如果很慢,1秒钟还没有好,那么该方法就没用了
// 利用定时器:1秒之后才能再次点击
app.directive('preventReClick', {
mounted: (el, binding) => {
el.addEventListener('click', () => {
if (!el.disabled) {
el.disabled = true
setTimeout(() => {
el.disabled = false
}, binding.value || 1000)
}
})
}
})
方法二:传入请求的函数作为参数,根据请求的finally来判断是否可以点击了,更推荐!!!
但是传入的参数必须是一个promise函数!!
//自定义指令版本2:根据请求结果防止按钮重复提交请求
//使用方式如下:
//1、请求函数不需要传参,直接传函数名或者包含函数名的对象,比如v-prevent-dup-click="submit"或者{fn:submit}
//2、请求函数需要传参,传递一个对象,包含函数名和参数,比如{fn:submit,params:[1,2,3]}
import type { App, Directive, DirectiveBinding } from 'vue'
interface ReturnPromiseFn {
(...args: any[]): Promise<any>
}
interface objectType {
fn: ReturnPromiseFn
params?: any[]
}
app.directive('preventDupClick', directiveBindingDirective)
const directiveBindingDirective: Directive = {
mounted(el, binding: DirectiveBinding<ReturnPromiseFn & objectType>) {
if (!binding.value) {
throw new Error('v-prevent-dup-click must pass a parameter')
}
if (typeof binding.value !== 'function' && typeof binding.value !== 'object') {
throw new Error('v-prevent-dup-click requires a function or an object with a function `fn`')
}
// 一开始是未点击状态
el.isClicked = false
const handerClick = function (event) {
// 如果已经点击过,则阻止事件
if (el.isClicked === 'true') {
event.preventDefault()
event.stopPropagation()
return
}
// 标记为已点击
el.isClicked = 'true'
// 调用传入的函数
let fn: ReturnPromiseFn
let params: any[] = []
//如果只传函数名
if (typeof binding.value == 'function') {
fn = binding.value
} else {
//如果传对象{fn:submit,params:[1,2,3]}或者{fn:submit}
fn = (binding.value as objectType).fn
params = (binding.value as objectType)?.params ?? []
}
console.log(params, 'params')
try {
fn(...params).finally(() => {
el.isClicked = false
})
} catch (error) {
throw new Error('binding.value或 binding.value.fn必须是返回Promise类型的函数')
}
}
el.hander = handerClick
el.addEventListener('click', handerClick)
},
//销毁事件
beforeUnmount(el) {
if (el.hander) {
el.removeEventListener('click', el.hander)
}
}
}