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

方案一

封装为 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>
相关推荐
全栈小51 分钟前
【前端】win11操作系统安装完最新版本的NodeJs运行npm install报错,提示在此系统上禁止运行脚本
前端·npm·node.js
晚霞的不甘5 分钟前
Flutter for OpenHarmony3D DNA 螺旋可视化:用 Canvas 构建沉浸式分子模型
前端·数据库·经验分享·flutter·3d·前端框架
摘星编程1 小时前
React Native + OpenHarmony:Stepper步进器组件
javascript·react native·react.js
●VON1 小时前
React Native for OpenHarmony:简易计算器应用的开发与跨平台适配实践
javascript·react native·react.js
摘星编程8 小时前
OpenHarmony + RN:Placeholder文本占位
javascript·react native·react.js
a1117769 小时前
医院挂号预约系统(开源 Fastapi+vue2)
前端·vue.js·python·html5·fastapi
0思必得09 小时前
[Web自动化] Selenium处理iframe和frame
前端·爬虫·python·selenium·自动化·web自动化
行走的陀螺仪11 小时前
uni-app + Vue3编辑页/新增页面给列表页传参
前端·vue.js·uni-app
摘星编程11 小时前
React Native + OpenHarmony:Spinner旋转加载器
javascript·react native·react.js
We་ct12 小时前
LeetCode 205. 同构字符串:解题思路+代码优化全解析
前端·算法·leetcode·typescript