位置: 文档库 > JavaScript > 用Axios Element实现全局的请求loading的方法

用Axios Element实现全局的请求loading的方法

刘青云 上传于 2022-07-26 09:34

《用Axios Element实现全局的请求loading的方法》

前端开发中,用户交互体验是衡量项目质量的重要指标之一。当应用发起网络请求时,若没有明确的加载反馈,用户可能会因界面卡顿或无响应而感到困惑,甚至误操作。因此,实现全局的请求loading效果是提升用户体验的关键环节。本文将详细介绍如何结合Axios(一个基于Promise的HTTP客户端)和Element UI(一套基于Vue.js的桌面端组件库)实现全局的请求loading功能,覆盖从基础配置到高级优化的完整流程。

一、技术选型与核心原理

Axios的核心优势在于其基于Promise的API设计,支持拦截器机制,可在请求发送前或响应返回后统一处理逻辑。Element UI的Loading组件则提供了灵活的加载动画,支持全屏、局部或自定义区域的覆盖层。两者的结合可通过Axios的拦截器动态控制Loading的显示与隐藏,实现无感知的全局加载效果。

核心原理分为三步:

  1. 请求拦截:在发送请求前触发Loading显示。
  2. 响应拦截:在请求完成后隐藏Loading。
  3. 错误处理:确保异常情况下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、排除特定请求)及实际应用场景,通过代码示例和原理分析帮助开发者提升用户交互体验。