分享一个非常实用的防止重复提交操作

方案一

封装为 Hooks 函数

> 在一个项目中,肯定不止一处需要给按钮做防止重复点击按钮的操作,这里封装一个等接口加载完之后,才能进行 下一次点击的hooks函数避免造成代码冗余

ts 复制代码
//useLoading.ts

 import { ref, type Ref } from "vue";
/**
 * 封装一个带有 loading 状态的 Hook,防止重复点击
 * @returns { isLoading: Ref<boolean>, withLoading: (fn: () => Promise<any>) => Promise<void> }
 */
export function useLoading() {
  const isLoading: Ref<boolean> = ref(false);

  /**
   * 包装异步函数,自动管理 loading 状态
   * @param fn 需要执行的异步函数
   */
  const withLoading = async (fn: () => Promise<any>): Promise<void> => {
    isLoading.value = true;
    try {
      await fn();
    } finally {
      isLoading.value = false;
    }
  };

  return {
    isLoading,
    withLoading,
  };
}

//xxx.vue
<script setup lang="ts">
import axios from "axios";

import { useLoading } from "@/hooks/useLoading";

const { isLoading, withLoading } = useLoading();

const handleTestLoading = async () => {
  await withLoading(async () => {
    // 模拟请求数据
    try {
      const res = await axios.get(
        "http://xx.xx.xx.xx:8080/api"
      );
      console.log(res.data);
    } catch (err) {
      console.error("请求失败", err);
    }
  });
};
</script>

<template>
   <button @click="handleTestLoading" :disabled="isLoading">
      {{ isLoading ? "加载中..." : "点击获取数据" }}
    </button>
  </div>
</template>

方案二

封装一个带防抖的自定义指令

js 复制代码
// prevent-repeate-clicks.js

export default {
  mounted(el, binding) {
    const { value = 3000, arg = "disable" } = binding;
    let timer = null;

    const handleClick = () => {
      if (arg === "disable") {
        if (el.disabled) return;
        el.disabled = true;
        timer = setTimeout(() => {
          el.disabled = false;
        }, value);
      } else if (arg === "debounce") {
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => {
          binding.value?.();
        }, value);
      }
    };

    el._clickHandler = handleClick;
    el.addEventListener("click", handleClick);
  },
  unmounted(el) {
    if (el._clickHandler) {
      el.removeEventListener("click", el._clickHandler);
    }
  },
};

//main.ts  全局使用
import preventRepeatedClick from "@/directive/prevent-repeate-clicks";
app.directive("prevent-repeated-click", preventRepeatedClick);

//xxx.vue
<template>
    <button v-prevent-repeated-click="2000">2秒内禁用</button>
</template>
相关推荐
xiaobaoyu11 分钟前
vue2+element开发中问题和解决方式
前端
KaMeidebaby12 分钟前
卡梅德生物技术快报 | 核酸适配体文库测序:核酸适配体文库测序的技术原理、实验流程与数据解析
前端·网络·数据库·人工智能·算法
Hilaku1 小时前
为什么在 2026 年,MPA(多页面应用)正在悄悄复辟?
前端·javascript·程序员
幸福小宝1 小时前
eslint和prettier
前端
anyup1 小时前
终于在今天入选了 Gitee GVP,这真值得庆祝~
前端·uni-app·开源
幸福小宝1 小时前
husky和lint-staged
前端
悟空瞎说1 小时前
iOS 高效绘图
javascript
Slice_cy1 小时前
Mint 自研框架设计与实现:从重复开发走向配置驱动(五)
前端·后端·架构
寒水馨1 小时前
Windows下载、安装 Tailwind CSS-v4.3.3(附安装包tailwindcss-windows-x64.exe)
前端·css·前端开发·tailwind css·utility-first·css 框架·独立 cli
西楼_1 小时前
一文读懂React19究竟更新了什么
前端