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

方案一

封装为 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>
相关推荐
程序员黑豆3 小时前
Java包装类:基本类型与对象的桥梁
java·前端·ai编程
bugcome_com6 小时前
JWT 知识小课堂:从入门到精通,一文吃透 JSON Web Token
前端·json
To_OC6 小时前
写了三天 Next.js,我的 React 世界观被拆了又装回去
前端·全栈·next.js
独泪了无痕7 小时前
viewer.js 安装与配置指南:实现图片预览功能
前端·vue.js
起床学FPGA8 小时前
AI回答问题之后,会自动跳到最下面的问题
开发语言·javascript·ecmascript
Fluxart.ai9 小时前
电商商品图审核怎么自动化?规则引擎、人工复核与发布门禁
java·前端·自动化
why技术9 小时前
AI 写的文章,可能都带着手敲一遍都去不掉的“隐形水印”。
前端·人工智能·后端
愚公搬代码9 小时前
【愚公系列】《Android应用案例开发大全》016-LBS类应用掌上杭州(辅助工具类的开发)
android·前端
CodeSheep9 小时前
又一个华为天才少年,离职了!
前端·后端·程序员
kyriewen10 小时前
面试官说"打开你的AI工具"——我才发现,他考的根本不是写代码
前端·人工智能·面试