Vue3 + Element Plus 防止按钮重复点击的解决方案
在 Vue3 和 Element Plus 项目中,防止按钮重复点击是一个常见的需求,特别是在表单提交、支付等场景下。以下是几种实现方式:
1. 使用 Element Plus 的 loading 状态
Element Plus 的按钮组件本身就支持 loading 状态,这是最简单的方式:
vue
复制
下载
<template><el-button type="primary" :loading="loading" @click="handleSubmit">提交</el-button> </template><script setup> import { ref } from 'vue';const loading = ref(false);const handleSubmit = async () => {loading.value = true;try {// 执行异步操作await submitForm();} finally {loading.value = false;} }; </script>
2. 自定义指令实现防重复点击
可以创建一个全局指令来实现防重复点击:
javascript
复制
下载
// directives.js import { Directive } from 'vue';export const preventReClick: Directive = {mounted(el, binding) {el.addEventListener('click', () => {if (!el.disabled) {el.disabled = true;setTimeout(() => {el.disabled = false;}, binding.value || 2000);}});} };// main.js import { preventReClick } from './directives'; app.directive('prevent-reclick', preventReClick);
使用方式:
vue
复制
下载
<el-button v-prevent-reclick="1000" @click="handleClick">提交</el-button>
3. 使用装饰器(适用于组合式 API)
可以创建一个可组合函数来防止重复点击:
javascript
复制
下载
// composables/usePreventReClick.js import { ref } from 'vue';export function usePreventReClick() {const isClicking = ref(false);const preventReClick = async (fn) => {if (isClicking.value) return;isClicking.value = true;try {await fn();} finally {isClicking.value = false;}};return {isClicking,preventReClick}; }
ts,usePreventReClick.ts
import { ref } from "vue";type AsyncFunction = () => Promise<void>;/*** 防止重复点击 hook* @returns*/
export function usePreventReClick() {const isClicking = ref(false);const preventReClick = async (fn: AsyncFunction) => {if (isClicking.value) {return;}isClicking.value = true;try {await fn();} finally {isClicking.value = false;}};return {isClicking,preventReClick};
}
使用方式:
vue
复制
下载
<script setup> import { usePreventReClick } from './composables/usePreventReClick';const { isClicking, preventReClick } = usePreventReClick();const handleSubmit = () => {preventReClick(async () => {// 执行提交逻辑await submitForm();}); }; </script><template><el-button :loading="isClicking" @click="handleSubmit">提交</el-button> </template>
4. 封装高阶组件
如果需要更复杂的控制,可以封装一个高阶组件:
vue
复制
下载
<!-- PreventReClickButton.vue --> <template><el-button v-bind="$attrs" :loading="loading" @click="handleClick"><slot></slot></el-button> </template><script setup> import { ref } from 'vue';const props = defineProps({onClick: {type: Function,required: true},delay: {type: Number,default: 1000} });const loading = ref(false);const handleClick = async () => {if (loading.value) return;loading.value = true;try {await props.onClick();} finally {setTimeout(() => {loading.value = false;}, props.delay);} }; </script>
使用方式:
vue
复制
下载
<PreventReClickButton type="primary" :onClick="submitForm" >提交 </PreventReClickButton>
总结
以上方法各有优缺点,根据项目需求选择:
-
简单场景:直接使用 Element Plus 的 loading 状态
-
全局控制:使用自定义指令
-
组合式 API:使用可组合函数
-
复杂组件:封装高阶组件