Vue.js中axios后端调用期间如何冻结UI以防止重复请求
Vue.js避免重复请求的可行实现方案
1. 全局请求遮罩方案
通过axios拦截器统一控制全局loading遮罩,请求未完成时完全阻止用户操作,实现成本最低
- 实现逻辑:统计请求计数,有未完成请求时显示遮罩,所有请求结束后自动关闭
- 代码示例:
import axios from 'axios' import { ElLoading } from 'element-plus' // 可替换为项目内的loading组件 let requestCount = 0 let loadingInstance = null // 请求拦截器 axios.interceptors.request.use(config => { requestCount++ loadingInstance = ElLoading.service({ lock: true, text: '处理中', background: 'rgba(0,0,0,0.6)' }) return config }, err => { requestCount = 0 loadingInstance?.close() return Promise.reject(err) }) // 响应拦截器 axios.interceptors.response.use(res => { requestCount-- if (requestCount === 0) loadingInstance?.close() return res }, err => { requestCount = 0 loadingInstance?.close() return Promise.reject(err) })
- 适用场景:对操作连贯性要求不高,需要严格避免任何重复提交的场景,比如表单提交、支付类请求。
2. 单操作点锁定方案
只对触发请求的按钮/组件做状态锁定,不会全局阻断用户操作,体验更灵活
- 实现逻辑:给每个触发请求的操作绑定loading状态,请求过程中禁用组件,请求结束后恢复
- 代码示例:
<template> <!-- 按钮自带loading状态,请求过程中自动禁用 --> <el-button :loading="submitLoading" @click="handleSubmit">提交表单</el-button> </template> <script setup> import { ref } from 'vue' import axios from 'axios' const submitLoading = ref(false) const handleSubmit = async () => { if (submitLoading.value) return // 额外加一层判断避免异常触发 submitLoading.value = true try { await axios.post('/api/form/submit', {}) // 业务成功逻辑 } catch (err) { // 错误处理逻辑 } finally { submitLoading.value = false } } </script>
- 拓展方案:可以封装成自定义hooks批量复用逻辑:
// hooks/useRequestLock.js import { ref } from 'vue' export const useRequestLock = () => { const loading = ref(false) const runRequest = async (requestFn) => { if (loading.value) return loading.value = true try { return await requestFn() } finally { loading.value = false } } return { loading, runRequest } }
3. 请求层自动去重方案
不需要修改业务组件,直接在axios拦截层过滤重复请求
- 实现逻辑:根据请求方法、路径、参数生成唯一标识,相同标识的未完成请求直接拦截取消
- 代码示例:
import axios from 'axios' const pendingRequests = new Map() // 生成请求唯一标识 const getRequestKey = (config) => { const { method, url, params, data } = config return [method, url, JSON.stringify(params), JSON.stringify(data)].join('|') } // 请求拦截 axios.interceptors.request.use(config => { const requestKey = getRequestKey(config) if (pendingRequests.has(requestKey)) { // 重复请求直接取消 config.cancelToken = new axios.CancelToken(cancel => cancel(`重复请求已拦截:${requestKey}`)) } else { config.cancelToken = new axios.CancelToken(cancel => { pendingRequests.set(requestKey, cancel) }) } return config }) // 响应拦截 axios.interceptors.response.use(res => { const requestKey = getRequestKey(res.config) pendingRequests.delete(requestKey) return res }, err => { if (!axios.isCancel(err)) { const requestKey = getRequestKey(err.config) pendingRequests.delete(requestKey) } return Promise.reject(err) })
- 适用场景:列表查询类重复请求多,不想修改业务代码的场景。
内容的提问来源于stack exchange,提问作者Viet Ma
相关产品推荐
相关产品推荐

