前景提要:
ts 简易封装 axios,统一 API
实现在 config 中配置开关拦截器
loading 分为全屏 loading 和局部 loading。
axios 中设置 loading 只能设置全屏 loading,因为局部 loading 需要当前局部的 dom,在 axios 中显然拿不到发起请求的元素 dom。
封装 loading 拦截器
- 请求拦截器开启 loading
- 响应拦截器关闭 loading
- 注意:无论请求成功或失败都应关闭 loading,因此在响应拦截器两个回调中都要关闭 loading。
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 开关
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 拦截器
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;
```