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

方案一

封装为 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>
相关推荐
菜市口的跳脚长颌2 小时前
Web3 基础
前端
王蛋1113 小时前
前端工作问题或知识记录
前端·npm·node.js
可子是我的小猫3 小时前
【JS】模块(二)
javascript
云枫晖3 小时前
JS核心知识-执行上下文
前端·javascript
麦当_3 小时前
TanStack Router File-Based Router Mask 完全指南
前端·javascript·设计模式
普通码农3 小时前
解决 Element Plus 分页组件英文显示问题
前端
珍珠奶茶爱好者3 小时前
vue二次封装ant-design-vue的table,识别columns中的自定义插槽
前端·javascript·vue.js
target酱3 小时前
Docker部署全流程
前端·docker
hj5914_前端新手3 小时前
React 基础 - 状态管理
前端·react.js