news 2026/6/9 20:00:58

在Vue3中如何防止用户重复提交?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
在Vue3中如何防止用户重复提交?

用户重复提交是一个常见问题。用户点击按钮后没有立即看到反馈,会再次点击。这导致重复请求,增加服务器压力,可能产生重复数据。

为什么需要防止重复提交

防止重复提交有多个好处。

  1. 提升用户体验。用户知道操作已经生效,不会困惑。
  2. 减轻服务器负担。减少不必要请求,节省资源。
  3. 避免数据错误。重复提交可能产生重复订单或重复记录。

常见重复提交场景

重复提交发生在这些情况。

  • 用户快速点击提交按钮

  • 页面响应慢,用户以为没点中

  • 网络延迟,请求未立即发送

  • 表单提交后跳转延迟

解决方案

在Vue3中可以用多种方式防止重复提交。下面介绍几种实用方法。

按钮禁用方案

最简单的方法是点击后禁用按钮

<template> <button @click="handleSubmit" :disabled="isSubmitting"> {{ isSubmitting ? '提交中...' : '提交' }} </button> </template> <script setup> import { ref } from 'vue' const isSubmitting = ref(false) const handleSubmit = async () => { if (isSubmitting.value) return isSubmitting.value = true try { await submitForm() } finally { isSubmitting.value = false } } </script>

这种方法简单有效。用户看到按钮状态变化,知道操作已触发

请求锁方案

多个组件可能触发相同请求。这时需要全局请求锁。

// utils/submitLock.js const pendingRequests = new Set() export const addRequest = (requestId:any) => { if (pendingRequests.has(requestId)) { return false } pendingRequests.add(requestId) return true } export const removeRequest = (requestId:any) => { pendingRequests.delete(requestId) } export const checkRequest = (requestId:any) => { return pendingRequests.has(requestId) }

在组件中使用:

import { addRequest, removeRequest } from '@/utils/submitLock' const handleSubmit = async () => { const requestId = 'formSubmit'; // 建议使用业务标识+时间戳生成唯一ID if (!addRequest(requestId)) { alert('请求已提交,请勿重复操作') return } try { await submitData() } finally { removeRequest(requestId) } }

防抖函数方案

防抖函数确保在一定时间内只执行一次。

// utils/debounce.js export const debounce = (func, wait) => { let timeout return function executedFunction(...args) { const later = () => { clearTimeout(timeout) func(...args) } clearTimeout(timeout) timeout = setTimeout(later, wait) } }

在Vue3中使用:

<script setup> import { debounce } from '@/utils/debounce' const handleSubmit = debounce(async () => { await submitForm() }, 1000) </script>

进阶防护方案

基础方案能解决大部分问题。复杂场景需要更高级方案。

请求拦截器方案

axios拦截器可以统一处理重复请求。

// utils/request.js import axios from 'axios' const pendingMap = new Map() const generateReqKey = (config) => { const { method, url, params, data } = config return [method, url, JSON.stringify(params), JSON.stringify(data)].join('&') } const addPending = (config) => { const key = generateReqKey(config) config.cancelToken = config.cancelToken || new axios.CancelToken(cancel => { if (!pendingMap.has(key)) { pendingMap.set(key, cancel) } }) } const removePending = (config) => { const key = generateReqKey(config) if (pendingMap.has(key)) { const cancel = pendingMap.get(key) cancel(key) pendingMap.delete(key) } } const instance = axios.create() //请求拦截器流程 instance.interceptors.request.use(config => { removePending(config) // 先取消已存在的相同请求 addPending(config) // 再添加新请求到pendingMap return config }) //响应拦截器清理 instance.interceptors.response.use(response => { removePending(response.config) // 成功时清理 return response }, error => { removePending(error.config) // 失败时清理 return Promise.reject(error) }) export default instance

路由守卫方案

页面跳转时,可能还有未完成的请求。路由守卫可以处理这种情况。

// router/guards.js import { getCurrentInstance } from 'vue' const pendingRequests = [] export const addPendingRequest = (request) => { pendingRequests.push(request) } export const removePendingRequest = (request) => { const index = pendingRequests.indexOf(request) if (index > -1) { pendingRequests.splice(index, 1) } } export const clearPendingRequests = () => { pendingRequests.forEach(request => { request.cancel && request.cancel() }) pendingRequests.length = 0 }

在路由配置中使用:

// router/index.js import { createRouter, createWebHistory } from 'vue-router' import { clearPendingRequests } from './guards' const router = createRouter({ history: createWebHistory(), routes: [...] }) router.beforeEach((to, from, next) => { clearPendingRequests() next() })

请记得防护措施不应该影响用户体验。

  • 禁用时间不宜过长

  • 提示信息要清晰

  • 错误处理要完善

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/8 15:26:08

2026年度热门盘点原创音乐人首选的5款AI编曲软件

在当今音乐创作的浪潮中&#xff0c;AI编曲软件正逐渐成为原创音乐人的得力助手。它们凭借强大的技术能力&#xff0c;不仅能大幅提升创作效率&#xff0c;还能为音乐带来更多新颖的元素和风格。这些软件打破了传统创作的时间和空间限制&#xff0c;让音乐人可以更自由地发挥创…

作者头像 李华
网站建设 2026/6/8 18:39:47

怎么快速完成编曲?盘点原创音乐人常用的5款AI编曲软件

在音乐创作的领域里&#xff0c;时间和效率往往是原创音乐人面临的一大挑战。传统的编曲过程&#xff0c;从灵感捕捉到旋律构建&#xff0c;再到和声编排和节奏设计&#xff0c;每一个环节都需要耗费大量的时间和精力。而如今&#xff0c;AI编曲软件的出现为音乐人带来了新的曙…

作者头像 李华
网站建设 2026/6/7 19:34:07

人群仿真软件:Vadere_(15).社区与支持资源

社区与支持资源 在进行人群仿真软件的二次开发过程中&#xff0c;社区和支持资源是不可或缺的一部分。这些资源提供了丰富的文档、教程、示例代码和用户反馈&#xff0c;帮助开发者更好地理解和使用软件。本节将详细介绍如何利用这些资源&#xff0c;包括官方文档、用户论坛、…

作者头像 李华
网站建设 2026/6/8 19:23:12

【ShardingJDBC 】【实战】----- SpringBoot3 整合 ShardingJDBC 做分库分表

文章目录 Spring Boot 3 整合 Sharding-JDBC 分库分表实现Nacos配置中心配置Sharding-JDBC 配置类SysMessage 实体类mapper类服务接口类服务接口实现说明 基于spring boot3 lombok 1.18.30 mybatis plus 3.5.5 nacos Spring Boot 3 整合 Sharding-JDBC 分库分表实现 根据需求…

作者头像 李华
网站建设 2026/6/8 19:30:04

【MyCat】第4章 ----垂直拆分——分库

文章目录 4.1 如何划分表4.2 实现分库1、 修改 schema 配置文件2、 新增两个空白库3、 启动 Mycat4、 访问 Mycat 进行分库 一个数据库由很多表的构成&#xff0c;每个表对应着不同的业务&#xff0c;垂直切分是指按照业务将表进行分类&#xff0c;分布到不同 的数据库上面&…

作者头像 李华
网站建设 2026/6/8 19:38:08

专科生必看!10个高效降aigc工具推荐,避坑指南来啦

专科生必看&#xff01;10个高效降aigc工具推荐&#xff0c;避坑指南来啦 AI降重工具&#xff0c;让论文更“自然” 随着人工智能技术的不断发展&#xff0c;越来越多的专科生在撰写论文时开始依赖AI辅助工具。然而&#xff0c;AI生成的内容往往带有明显的痕迹&#xff0c;导致…

作者头像 李华