You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.08 20:48:01