解决了 "在每个页面 / 按钮上手动绑定 loading" 的问题,大幅减少了重复代码
核心代码如下:
ini
import axios from 'axios';
import { Loading } from 'element-ui';
// 定义不同API类型的超时时间(单位:毫秒)
const TIMEOUT_CONFIG = {
default: 3000, // 默认超时时间
fast: 1000, // 快速API,简单查询等
normal: 5000, // 普通API,大多数业务接口
slow: 10000, // 慢速API,文件上传、大数据量处理
critical: 15000 // 关键API,支付、重要业务处理
}
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: TIMEOUT_CONFIG.default
});
/**
* loading 计数
* loadingCount //请求次数,为0时,结束loading
**/
let loadingCount = 0
let isLoading = false
let loadingInstance = null
const noLoadingApi = ['a','b','c'] // 禁止触发全局loading的路由
const addLoading = (url) => {
const result = noLoadingApi.includes(url)
if(result){
return;
}
loadingCount++
if (!isLoading){
loadingInstance = Loading.service({
lock: true,
background: 'rgba(0, 0, 0, 0.9)'
})
isLoading = true
}
}
const closeLoading = (url) => {
const result = url && noLoadingApi.includes(url)
if(result){
return;
}
loadingCount--
if (loadingCount <= 0) {
loadingInstance && loadingInstance.close()
isLoading = false
}
}
service.interceptors.request.use(
config => {
// 定义关键API路径数组
const CRITICAL_API_PATHS = ['a','b','c'];
// 检查是否是关键API
if (CRITICAL_API_PATHS.some(path => config.url.includes(path))) {
config.timeout = TIMEOUT_CONFIG.critical
}
addLoading(config.url)
//....根据需求自定义封装请求头
return config;
},
error => {
return Promise.reject(error);
}
);
service.interceptors.response.use(
response => {
closeLoading(response.config.url)
//...根据需求自定义封装响应头
},
error => {
closeLoading()
return Promise.reject(error);
}
);
export default service;
1. 全局统一管理 loading,无需页面 / 按钮单独处理
代码通过 axios 的请求 / 响应拦截器,对所有经过 service 实例的请求进行统一拦截:
- 请求发起时 :自动调用
addLoading显示全局 loading(除非接口在noLoadingApi白名单中); - 请求完成时 (成功 / 失败):自动调用
closeLoading关闭全局 loading(当所有并发请求都完成时)。
这种方式下,无论哪个页面、哪个按钮触发的请求,只要使用了这个 service 实例,都不需要在页面中手动写 loading.show() 或 loading.hide(),完全由拦截器自动处理。
2. 避免了 "重复编写 loading 控制逻辑" 的冗余
如果没有这段代码,通常的做法是:
- 在每个按钮点击事件中,先手动显示 loading;
- 在请求的
then/catch中手动隐藏 loading; - 还要处理多个请求并发时,loading 被提前关闭的问题(比如两个请求同时发起,第一个完成就关 loading,导致第二个请求无 loading)。
而这段代码通过 loadingCount 计数和拦截器统一控制,一次性解决了 "显示 / 隐藏时机""并发请求 loading 管理" 等问题,所有页面 / 按钮都能复用这套逻辑,无需重复编写。
3. 特殊场景通过配置排除,灵活性兼顾
代码中通过 noLoadingApi 数组定义了 "不需要 loading 的接口",对于这些特殊接口,无需在页面中单独处理,只需在全局配置中维护这个数组即可,进一步减少了页面级的重复配置。
总结
这段代码通过 "拦截器 + 全局配置" 的方式,实现了 loading 的 "一次编写,全项目复用",彻底避免了在每个页面、每个按钮中重复编写 loading 控制逻辑的工作,显著减少了冗余代码,同时还解决了并发请求下的 loading 显示问题,是一种高效的全局状态管理方案。