Vue3 + TypeSrcipt 防抖、防止重复点击实例

需要实现防抖应用场景:

点击【查询】按钮,发送网络请求,等待并接收响应数据

原来点击【查询】的代码:

TypeScript 复制代码
<script setup lang="ts" name="ReagentTransactionsDrawer">
......
// 查询,没有防抖,可以重复点击
const onQueryClick = async () => {
  // 检查
  if (
    queryObj.value.transactionTime.length === 0 &&
    !queryObj.value.transactionType &&
    !queryObj.value.materialName
  ) {
    ElMessage.warning("请输入查询条件!");
    return;
  }
  transactionsList.value = [];
  let result = await branchWarehouseTransactionsQueryForReagentService(queryObj.value);
  transactionsList.value = result.data;
};
......
</script>

<template>
......
              <el-button class="btn-same-width" type="primary" plain @click="onQueryClick">查询</el-button>
......
</template>

一、使用自定义的防止重复点击组合式函数 hook

1、编写防止重复点击组合式函数 hook,usePreventReClick.ts

2、导入防止重复点击组合式函数 hook

3、使用 preventReClick 防止重复点击

TypeScript 复制代码
<script setup lang="ts" name="ReagentTransactionsDrawer">
......
import { usePreventReClick } from "@/hooks/usePreventReClick";
const { preventReClick } = usePreventReClick();

// 查询,加装 preventReClick 防抖器,防止重复点击
const onQueryClick = async () => {
  preventReClick(async () => { // 改动1:增加防抖代码
    // 检查
    if (
      queryObj.value.transactionTime.length === 0 &&
      !queryObj.value.transactionType &&
      !queryObj.value.materialName
    ) {
      ElMessage.warning("请输入查询条件!");
      return;
    }
    transactionsList.value = [];
    let result = await branchWarehouseTransactionsQueryForReagentService(queryObj.value);
    transactionsList.value = result.data;
  }); // 改动2:增加防抖代码
};
......
</script>

<template>
......
              <el-button class="btn-same-width" type="primary" plain @click="onQueryClick">查询</el-button>
......
</template>

防止重复点击组合式函数 hook,usePreventReClick.ts

TypeScript 复制代码
import { ref } from "vue";

type AsyncFunction = () => Promise<any>;

/**
 * 防止重复点击 hook
 * @returns
 */
export function usePreventReClick() {
  const isClicking = ref(false);
  const preventReClick = async (fn: AsyncFunction) => {
    if (isClicking.value) {
      return;
    }
    isClicking.value = true;
    try {
      await fn();
    } finally {
      isClicking.value = false;
    }
  };

  return {
    isClicking,
    preventReClick
  };
}

二、使用lodash-es的debounce

1、安装 lodash-es 工具库

2、按需使用导入debounce

3、使用 debounce 防止重复点击

TypeScript 复制代码
<script setup lang="ts" name="ReagentTransactionsDrawer">
......
import { debounce } from "lodash-es";

// 查询,加装 debounce 防抖器,防抖处理(leading: true,立即执行、maxWait: 1000,1秒内至少执行一次)
const onQueryClick = debounce( // 改动1:const onQueryClick = async () => { 改为 const onQueryClick = debounce(
  async () => {
    // 检查
    if (
      queryObj.value.transactionTime.length === 0 &&
      !queryObj.value.transactionType &&
      !queryObj.value.materialName
    ) {
      ElMessage.warning("请输入查询条件!");
      return;
    }
    transactionsList.value = [];
    let result = await branchWarehouseTransactionsQueryForReagentService(queryObj.value);
    transactionsList.value = result.data;
  }, // 改动2:} 改为 },
  1000, // 改动3:增加防抖代码
  { leading: true, trailing: true, maxWait: 1000 } // 改动4:增加防抖代码
); // 改动5:增加防抖代码
......
</script>

<template>
......
              <el-button class="btn-same-width" type="primary" plain @click="onQueryClick">查询</el-button>
......
</template>

三、使用自定义防抖组件

1、编写防止重复点击按钮组件(防抖按钮组件),BasePreventReClickButton.vue

2、导入防抖组件

3、在模板中使用组件

TypeScript 复制代码
<script setup lang="ts" name="ReagentTransactionsDrawer">
......
import BasePreventReClickButton from "@/components/base/BasePreventReClickButton.vue";

// 查询,使用 BasePreventReClickButton 防抖组件,防止重复点击
const onQueryClick = async () => {
  // 检查
  if (
    queryObj.value.transactionTime.length === 0 &&
    !queryObj.value.transactionType &&
    !queryObj.value.materialName
  ) {
    ElMessage.warning("请输入查询条件!");
    return;
  }
  transactionsList.value = [];
  let result = await branchWarehouseTransactionsQueryForReagentService(queryObj.value);
  transactionsList.value = result.data;
};
......
</script>

<template>
......
              <BasePreventReClickButton class="btn-same-width" type="primary" plain @click="onQueryClick">查询</BasePreventReClickButton> <!-- 改动1:改用防抖组件 BasePreventReClickButton -->
......
</template>

防止重复点击按钮组件(防抖按钮组件),BasePreventReClickButton.vue

TypeScript 复制代码
/** * 防止重复点击按钮组件(防抖按钮组件) */
<script setup lang="ts" name="BasePreventReClickButton">
import { ref } from "vue";

const props = withDefaults(
  defineProps<{
    onClick: () => Promise<void> | void;
    delay?: number;
  }>(),
  {
    delay: 0
  }
);

// 加载标识
const loading = ref(false);

// 点击事件
const handleClick = async (): Promise<void> => {
  if (loading.value) return;
  loading.value = true;
  try {
    await props.onClick();
  } finally {
    let delay = props.delay;
    if (delay < 0) delay = 0;
    setTimeout(() => {
      loading.value = false;
    }, delay);
  }
};
</script>

<template>
  <!-- v-bind="$attrs" 绑定父组件传递的所有属性 -->
  <!-- 设置当前组件的个性属性,可以覆盖父组件属性 :loading="loading" :disabled="loading" @click="handleClick" -->
  <el-button v-bind="$attrs" :loading="loading" :disabled="loading" @click="handleClick">
    <!-- 插槽 -->
    <slot></slot>
  </el-button>
</template>

<style scoped lang="scss"></style>
相关推荐
用户3600555790021 分钟前
Kestrel_VLLM - 26 · 发射空档三步曲:事件计时 → nsys → 判别实验
前端
echome88826 分钟前
JavaScript async/await 错误处理:别让 Promise 静默失败
开发语言·前端·javascript·promise
PedroQue9942 分钟前
v0.2.0 架构升级:class + reactive 重塑状态管理
前端·uni-app
鶴哥只手遮天42 分钟前
Angular 22 源码级深度解析-第 02 章 编译链路总览:从模板字符串到 `ɵɵ` 指令
前端·开源·angular.js
尘世中一位迷途小书童42 分钟前
别再堆万字 Prompt:用 Agent Skills 给团队写一个「前端 Review」Skill
前端·ai编程·cursor
aixingpan44 分钟前
aixingpan.cn API开发文档:api_docs_bichart_common2接口指南
前端·php
super_Omni1 小时前
text/PDF/Word → 解析成纯文本 → 分词 → 词表匹配 → 加权打分 → 低于阈值
前端·chrome
阶进遐1 小时前
浏览器工具自制指南·对话导出(3):消息池设计
前端
SameX1 小时前
HarmonyOS 用 relationalStore 做阅读统计 App —— 5 张表背后的 5 个 schema 决策
前端
LV技术派1 小时前
【成为 AI Native Builder · 02】什么是 AI Native Builder:一个人 + AI,交付完整闭环
前端·程序员·ai编程