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