《用Axios Element实现全局的请求loading的方法》
在前端开发中,用户交互体验是衡量项目质量的重要指标之一。当应用发起网络请求时,若没有明确的加载反馈,用户可能会因界面卡顿或无响应而感到困惑,甚至误操作。因此,实现全局的请求loading效果是提升用户体验的关键环节。本文将详细介绍如何结合Axios(一个基于Promise的HTTP客户端)和Element UI(一套基于Vue.js的桌面端组件库)实现全局的请求loading功能,覆盖从基础配置到高级优化的完整流程。
一、技术选型与核心原理
Axios的核心优势在于其基于Promise的API设计,支持拦截器机制,可在请求发送前或响应返回后统一处理逻辑。Element UI的Loading组件则提供了灵活的加载动画,支持全屏、局部或自定义区域的覆盖层。两者的结合可通过Axios的拦截器动态控制Loading的显示与隐藏,实现无感知的全局加载效果。
核心原理分为三步:
- 请求拦截:在发送请求前触发Loading显示。
- 响应拦截:在请求完成后隐藏Loading。
- 错误处理:确保异常情况下Loading也能被正确关闭。
二、基础实现步骤
1. 安装依赖
确保项目中已安装Axios和Element UI:
npm install axios element-ui --save
2. 创建Axios实例
在项目中新建一个http.js
文件,封装Axios实例并配置基础URL和超时时间:
import axios from 'axios';
const service = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000
});
export default service;
3. 引入Element UI的Loading服务
Element UI提供了两种Loading使用方式:指令式和组件式。这里选择指令式(通过this.$loading()
调用),因其更灵活且易于全局控制。
在Vue项目中,需确保已正确引入Element UI:
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
4. 实现请求拦截器
在Axios实例中添加请求拦截器,在发送请求前显示Loading:
let loadingInstance;
service.interceptors.request.use(
config => {
// 显示Loading,设置文本和背景色
loadingInstance = Vue.prototype.$loading({
lock: true,
text: '加载中...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
return config;
},
error => {
// 请求错误时隐藏Loading
if (loadingInstance) loadingInstance.close();
return Promise.reject(error);
}
);
5. 实现响应拦截器
在响应拦截器中隐藏Loading,并处理可能的错误:
service.interceptors.response.use(
response => {
// 请求成功时隐藏Loading
if (loadingInstance) loadingInstance.close();
return response.data;
},
error => {
// 请求失败时隐藏Loading并抛出错误
if (loadingInstance) loadingInstance.close();
return Promise.reject(error);
}
);
三、进阶优化与问题解决
1. 避免重复Loading
默认情况下,每次请求都会触发新的Loading。若需合并多个请求的Loading(例如同时发起3个接口,仅显示一个Loading),可通过计数器实现:
let requestCount = 0;
service.interceptors.request.use(config => {
if (requestCount === 0) {
loadingInstance = Vue.prototype.$loading({ /* 配置 */ });
}
requestCount++;
return config;
});
service.interceptors.response.use(
response => {
requestCount--;
if (requestCount === 0) {
loadingInstance.close();
}
return response.data;
},
error => {
requestCount--;
if (requestCount === 0) {
loadingInstance.close();
}
return Promise.reject(error);
}
);
2. 排除特定请求的Loading
某些场景下(如心跳检测、静态资源加载),可能不需要显示Loading。可通过自定义请求头或参数标记:
// 发送请求时添加标记
service.get('/api/data', { hideLoading: true });
// 修改请求拦截器
service.interceptors.request.use(config => {
if (!config.hideLoading && requestCount === 0) {
loadingInstance = Vue.prototype.$loading(/* 配置 */);
}
requestCount++;
return config;
});
3. 全局错误处理
结合Element UI的Message组件,在响应拦截器中统一处理错误提示:
import { Message } from 'element-ui';
service.interceptors.response.use(
response => {
requestCount--;
if (requestCount === 0) loadingInstance.close();
return response.data;
},
error => {
requestCount--;
if (requestCount === 0) loadingInstance.close();
// 根据错误状态码显示不同提示
if (error.response) {
switch (error.response.status) {
case 404:
Message.error('请求资源不存在');
break;
case 500:
Message.error('服务器内部错误');
break;
default:
Message.error(error.response.data.message || '请求失败');
}
} else {
Message.error('网络连接失败');
}
return Promise.reject(error);
}
);
4. 自定义Loading样式
Element UI的Loading组件支持通过CSS覆盖默认样式。在全局样式文件中添加:
.el-loading-mask {
.el-loading-spinner .path {
stroke: #409EFF; /* 修改加载动画颜色 */
}
.el-loading-text {
color: #409EFF; /* 修改文本颜色 */
font-size: 16px;
}
}
四、完整代码示例
将上述优化整合后的完整http.js
文件:
import axios from 'axios';
import Vue from 'vue';
import { Message } from 'element-ui';
let requestCount = 0;
let loadingInstance;
const service = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000
});
// 请求拦截器
service.interceptors.request.use(
config => {
if (!config.hideLoading && requestCount === 0) {
loadingInstance = Vue.prototype.$loading({
lock: true,
text: '加载中...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
}
requestCount++;
return config;
},
error => {
requestCount--;
if (requestCount === 0 && loadingInstance) {
loadingInstance.close();
}
return Promise.reject(error);
}
);
// 响应拦截器
service.interceptors.response.use(
response => {
requestCount--;
if (requestCount === 0 && loadingInstance) {
loadingInstance.close();
}
return response.data;
},
error => {
requestCount--;
if (requestCount === 0 && loadingInstance) {
loadingInstance.close();
}
if (error.response) {
switch (error.response.status) {
case 404:
Message.error('请求资源不存在');
break;
case 500:
Message.error('服务器内部错误');
break;
default:
Message.error(error.response.data.message || '请求失败');
}
} else {
Message.error('网络连接失败');
}
return Promise.reject(error);
}
);
export default service;
五、实际应用场景
1. 表单提交
在提交表单时,用户点击按钮后立即显示Loading,防止重复提交:
methods: {
async submitForm() {
try {
const res = await this.$http.post('/api/submit', this.formData);
this.$message.success('提交成功');
} catch (e) {
console.error(e);
}
}
}
2. 页面初始化数据加载
在组件的created
钩子中发起请求,Loading会自动显示:
export default {
data() {
return { list: [] };
},
async created() {
try {
this.list = await this.$http.get('/api/list');
} catch (e) {
console.error(e);
}
}
};
3. 文件上传
上传大文件时,Loading可提示用户等待:
async uploadFile(file) {
const formData = new FormData();
formData.append('file', file);
try {
await this.$http.post('/api/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' }
});
this.$message.success('上传成功');
} catch (e) {
this.$message.error('上传失败');
}
}
六、总结与注意事项
通过Axios拦截器和Element UI的Loading组件,可高效实现全局请求loading效果。关键点包括:
- 使用计数器管理多个请求的Loading状态。
- 通过自定义参数排除特定请求的Loading。
- 统一处理错误并显示友好提示。
- 优化样式以匹配项目设计规范。
注意事项:
- 避免在Loading显示期间执行阻塞操作(如同步IO)。
- 测试时需覆盖网络超时、服务器错误等异常场景。
- 移动端需考虑Loading对性能的影响,适当降低动画复杂度。
关键词:Axios、Element UI、全局Loading、请求拦截器、响应拦截器、Vue.js、前端开发、用户体验
简介:本文详细介绍了如何结合Axios和Element UI实现前端项目的全局请求loading功能,涵盖基础配置、进阶优化(如合并多个请求的Loading、排除特定请求)及实际应用场景,通过代码示例和原理分析帮助开发者提升用户交互体验。