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

方案一

封装为 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>
相关推荐
β添砖java28 分钟前
CSS网格布局
前端·css·html
木易 士心2 小时前
Ref 和 Reactive 响应式原理剖析与代码实现
前端·javascript·vue.js
程序员博博2 小时前
概率与决策 - 模拟程序让你在选择中取胜
前端
被巨款砸中2 小时前
一篇文章讲清Prompt、Agent、MCP、Function Calling
前端·vue.js·人工智能·web
sophie旭2 小时前
一道面试题,开始性能优化之旅(1)-- beforeFetch
前端·性能优化
Cache技术分享3 小时前
204. Java 异常 - Error 类:表示 Java 虚拟机中的严重错误
前端·后端
uhakadotcom3 小时前
execjs有哪些常用的api,如何逆向分析网站的加签机制
前端·javascript·面试
ObjectX前端实验室3 小时前
【图形编辑器架构】:无限画布标尺与网格系统实现解析
前端·canvas·图形学
你的电影很有趣3 小时前
lesson71:Node.js与npm基础全攻略:2025年最新特性与实战指南
前端·npm·node.js
闲蛋小超人笑嘻嘻3 小时前
find数组方法详解||Vue3 + uni-app + Wot Design(wd-picker)使用自定义插槽内容写一个下拉选择器
前端·javascript·uni-app