Uniapp和 Vue3项目中防止按钮重复点击的3种方案

AI 概述
文章围绕 uniapp 移动端项目开发中按钮或 view 组件重复点击问题,给出三种解决方案。方案一是状态锁,通过设置变量控制组件状态,在点击方法中加锁解锁,防止重复操作;方案二是全局自定义防重复点击指令,在根创建指令文件,定义相关逻辑,在 main.js 全局注册后组件中使用;方案三是封装防重复点击 Hook,在 hooks 创建文件定义逻辑,在组件中引入使用,通过执行受保护操作函数控制重复点击,提升应用性能与用户体验。
目录
文章目录隐藏
  1. 方案一:状态锁
  2. 方案二:全局自定义防重复点击指令
  3. 方案三:封装一个防重复点击的 Hook

在完成基于 uniapp 框架的移动端项目开发后,为确保应用流畅运行并提升用户体验,性能优化是不可或缺的关键环节。其中,防止按钮或 view 组件的重复点击问题尤为常见,这类问题不仅可能导致数据重复提交、界面状态错乱,还可能引发不必要的资源消耗。针对此,我总结了以下三种实用且高效的解决方案:

Uniapp 和 Vue3 项目中防止按钮重复点击的 3 种方案

方案一:状态锁

核心:通过设置变量 true/false 来控制按钮或者 view 的状态。

这种方式应该最常见。

<template>
  <view>
  <!-- 作者:知否技术 -->
<!--1. 视图 -->
<view :class="{ 'disabled': isLoading }" @click="handleSubmit">
   提交
</view>
<!--2. 按钮 disabled -->
<uv-button :disabled="isLoading" @click="handleSubmit"> 提交 </uv-button>
<!--3. 按钮 loading -->
<uv-button :loading="isLoading" @click="handleSubmit">提交</uv-button>
 </view>
</template>

<script setup>
  import {ref} from 'vue'
  import orderApi from '@/api/order/order.js';
  const isLoading = ref(false)
  // 提交方法
  const handleSubmit = async () => {
      // 防止重复点击
      if (isLoading.value) return
      // 锁住
      isLoading.value = true
      try {
          const res = await orderApi.handleSubmit(order);
          if (res.code === 200) {
              getReturnFundList();
              uni.showToast({ title: '提交成功' });
          } else {
              uni.showToast({ title: '提交失败' });
          }
      } catch (error) {
          console.error("提交失败:", error);
      } finally {
          // 解锁
          isLoading.value = false;
      }
  }
</script>

方案二:全局自定义防重复点击指令

在项目根目录中新建 /directives/preventClick.js :

1. preventClick.js

// 防止重复点击指令
exportconst preventClick = {
// 指令绑定到元素时执行
  mounted(el, binding) {
    // 1. 设置防抖间隔时间,默认 1000 毫秒
    const delay = binding.value || 1000;
    
    // 2. 创建一个标记,记录当前是否可点击
    el.isDisabledClick = false;
    
    // 3. 保存原始的点击事件处理函数
    const originalClickHandler = el.__originalClickHandler;
    
    // 4. 创建新的点击事件处理函数
    el.__preventClickHandler = (event) => {
      // 如果当前不可点击,直接拦截点击事件
      if (el.isDisabledClick) {
        event.preventDefault(); // 阻止默认行为
        event.stopPropagation(); // 阻止事件冒泡
        return;
      }
      
      // 设置为不可点击状态
      el.isDisabledClick = true;
      
      // 5. 执行原始的点击事件处理函数
      if (originalClickHandler) {
        originalClickHandler(event);
      }
      
      // 6. 设置定时器,在指定时间后恢复点击
      el.preventClickTimer = setTimeout(() => {
        // 恢复点击状态
        el.isDisabledClick = false;
        // 清除定时器引用
        el.preventClickTimer = null;
      }, delay);
    };
    
    // 7. 移除原始的点击事件,添加新的点击事件
    el.removeEventListener('click', originalClickHandler);
    el.addEventListener('click', el.__preventClickHandler);
  },

// 指令从元素解绑时执行
  unmounted(el) {
    // 8. 清除定时器
    if (el.preventClickTimer) {
      clearTimeout(el.preventClickTimer);
      el.preventClickTimer = null;
    }
    
    // 9. 移除事件监听器
    if (el.__preventClickHandler) {
      el.removeEventListener('click', el.__preventClickHandler);
      el.__preventClickHandler = null;
    }
    
    // 10. 清除自定义属性
    el.isDisabledClick = null;
    el.__originalClickHandler = null;
  }
};

2. 在 main.js 中全局注册指令

import { createSSRApp } from'vue';
import App from'./App.vue';
// 导入指令
import { preventClick } from'@/directives/preventClick';

exportfunction createApp() {
const app = createSSRApp(App);
// 全局注册指令,指令名为 prevent-click
  app.directive('prevent-click', preventClick);
return { app };
}

3.在组件中使用指令

<template>
  <view>
    <!-- 方式 1:使用默认 1000ms 防抖 -->
    <button v-prevent-click @click="handleClick">点击</button>
    <!-- 方式 2:自定义防抖时间 -->
    <button v-prevent-click="2000" @click="handleClick">点击</button>
  </view>
</template>

方案三:封装一个防重复点击的 Hook

在项目目录 hooks 新建文件: usePreventReclick.js

import { ref } from'vue'
exportfunction usePreventReclick(delay = 1000) {
const isDisabled = ref(false)
// 执行受保护的操作 fn - 要执行的函数(建议返回 Promise)
// 返回 fn 的结果或 undefined(如果被阻止)
const execute = async (fn) => {
    if (isDisabled.value) {
      console.info('操作被阻止')
      returnundefined
    }
// 设置为 true
    isDisabled.value = true
    try {
      const result = await fn()
      return result
    } catch (error) {
      // 抛出异常
      throw error
    } finally {
      // 延迟后自动重置状态
      setTimeout(() => {
        isDisabled.value = false
      }, delay)
    }
  }
// 解除禁用
const reset = () => {
    isDisabled.value = false
  }
return {
    isDisabled,
    execute,
    reset
  }
}

在项目中使用:

<template>
  <view class="container">
    <button 
      :disabled="isLoading" 
      :loading="isLoading"
      @click="handleSubmit"
    >
      {{ isLoading ? '正在提交中...' : '提交订单' }}
    </button>
  </view>
</template>

<script setup>
import { ref } from 'vue'
import { usePreventReclick } from '@/hooks/usePreventReclick'
const isLoading = ref(false)
// 创建防重实例:时间 1500 毫秒
const { isDisabled: isLoading, execute } = usePreventReclick(1500)

const handleSubmit = () => {
  execute(async () => {
    // 模拟后端请求
    await new Promise()
    uni.showToast({ title: '提交成功'})
  }).catch(err => {
    console.error('提交失败:', err)
    uni.showToast({ title: '提交失败'})
  })
}
</script>

以上关于Uniapp和 Vue3项目中防止按钮重复点击的3种方案的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。

「点点赞赏,手留余香」

1

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
重要:如软件存在付费、会员、充值等,均属软件开发者或所属公司行为,与本站无关,网友需自行判断
码云笔记 » Uniapp和 Vue3项目中防止按钮重复点击的3种方案

发表回复