axios 实现请求 loading 效果

前景提要:
ts 简易封装 axios,统一 API
实现在 config 中配置开关拦截器

loading 分为全屏 loading 和局部 loading。

axios 中设置 loading 只能设置全屏 loading,因为局部 loading 需要当前局部的 dom,在 axios 中显然拿不到发起请求的元素 dom。

封装 loading 拦截器

  1. 请求拦截器开启 loading
  2. 响应拦截器关闭 loading
    • 注意:无论请求成功或失败都应关闭 loading,因此在响应拦截器两个回调中都要关闭 loading。
typescript 复制代码
import { AxiosError, AxiosResponse } from "axios";
import { ElLoading } from "element-plus";
import { MyInternalAxiosRequestConfig } from "./request";

/**
 * el-loading 有两种方式调用:指令和服务。
 * 指令可以绑定到元素上,局部loading
 * 此处以服务方式调用loading,并且根据请求配置 showLoading 来决定请求是否开启loading
 * 此loading在全局拦截器生效,服务方式默认就是全屏
 */

/* 全局请求 loading(服务方式调用) */
let loadingInstance: ReturnType<typeof ElLoading.service>;

const startElementLoading = () => {
    loadingInstance = ElLoading.service({
        fullscreen: true,
        lock: true,
        text: "Loading",
        background: "rgba(0, 0, 0, 0.7)"
        // spinner:	自定义加载图标类名
        // customClass:	Loading 的自定义类名
    });
};

const endElementLoading = (loadingInstance: ReturnType<typeof ElLoading.service>) => loadingInstance.close();

/**
 * 开启loading
 * @param {import("..").AxiosRequestConfig} config
 * @returns
 */
export function showLoading(config: MyInternalAxiosRequestConfig) {
    if (config.showLoading === false) return config;
    startElementLoading();
    return config;
}

/**
 * 请求成功关闭 loading
 * @param {import("axios").AxiosResponse} res
 * @returns
 */
export function closeLoadingOnFulfilled(res: AxiosResponse) {
    if (loadingInstance) endElementLoading(loadingInstance);
    return res;
}

/**
 * 请求失败关闭 loading
 * @param {import("axios").AxiosError} err
 * @returns
 */
export function closeLoadingOnRejected(err: AxiosError) {
    if (loadingInstance) endElementLoading(loadingInstance);
    throw err;
}

在 config 中配置 loading 开关

typescript 复制代码
const DEFAULT_EXTRA_FEATURE_CONFIG = { showLoading: true, showMessage: true, retry: true };

/** 扩展 axios 的请求配置类型 */
export interface MyAxiosRequestConfig<TReqBodyData = any> extends AxiosRequestConfig<TReqBodyData> {
    showLoading?: boolean;
    showMessage?: boolean;
    retry?: boolean;
}

/** 给拦截器使用 */
export interface MyInternalAxiosRequestConfig extends InternalAxiosRequestConfig {
    showLoading?: boolean;
    showMessage?: boolean;
    retry?: boolean;
}

axios 实例化后注册 loading 拦截器

typescript 复制代码
import HttpRequest from "./http/request";
import { compareUrl, filterFulfilledUrlOnFulfilled, filterFulfilledUrlOnRejected } from "./http/debounceReq";
import { closeLoadingOnFulfilled, closeLoadingOnRejected, showLoading } from "./http/loading";
import { responseMessageOnFulfilled } from "./http/message";
import { getTokenResponseInterceptor, setAccessTokenRequestInterceptor } from "./http/token";
import { retryRequest } from "./http/retryRequest";

const httpRequest = new HttpRequest({
    baseURL: import.meta.env.VITE_APP_API_BASE_URL,
    timeout: import.meta.env.VITE_APP_API_TIMEOUT
});

// loading
httpRequest.getInstance().interceptors.request.use(showLoading);
httpRequest.getInstance().interceptors.response.use(closeLoadingOnFulfilled, closeLoadingOnRejected);

export default httpRequest;
```
相关推荐
Dream-Y.ocean1 小时前
鸿蒙PC平台宅匠 3D 室内设计适配实战:基于 Electron 壳方案的 Three.js 双渲染引擎与参数化户型编辑器开发
javascript·3d·harmonyos
Csvn2 小时前
性能监控
前端
Highcharts.js2 小时前
Highcharts Gantt使用符号的自定义数据标签开发甘特图示例
javascript·甘特图·highcharts·图表开发·实战代码·响应式图表
Csvn3 小时前
构建工具
前端
FRing033 小时前
vue2干货总结3(computed计算属性、watch监听器)
开发语言·前端·vue.js·vue2
kyriewen5 小时前
Skills 榜前 10 我全装了:只有 3 个能直接用
前端·javascript·程序员
IT_陈寒6 小时前
当Java的hashCode遇上Lombok,我的缓存被全清了
前端·人工智能·后端
工控丫丫6 小时前
帆软看板中经常使用的公式函数及经常搭的组合
前端·javascript·数据库
jerrywus7 小时前
我用 GPT-6.1-sol 做了台会讲解的 3D 售货机:60 罐饮料,一口没喝上
前端·agent·claude
孟陬8 小时前
Foobar 技术周刊#159:当看不懂代码时,如何高效排障调试。脏页陷阱:一条只读查询,写入数 TB 数据。推测解码:大模型加速利器
前端·人工智能·后端