1.使用 React.lazy 来懒加载页面(进入对应的路由页面才开始加载)节省资源,让响应速度更快。
2.发送异步请求的时候出现loding图标,请求成功之后隐藏loding图片,给用户更好的体验。
3.由于2个loding都是基于antd的 Spin 组件,会存在冲突,所以做了 z-index 的层级处理。
一:页面路由懒加载loding
1:新建 src/components/SpinLoding文件夹
1.1:新建index.tsx
import styles from "./index.module.scss";
import { Spin } from "antd";
import React from "react";
function SpinLoding() {
return (
<div className={styles.SpinLoding}>
<Spin size='large'/>
</div>
);
}
const MemoSpinLoding = React.memo(SpinLoding);
export default MemoSpinLoding;
1.2:新建index.module.scss
.SpinLoding {
position: relative;
z-index: 9999;
width: 100%;
height: 100%;
background-color: #fff;
display: flex;
justify-content: center;
align-items: center;
}
2:在页面中使用
//导入
import { Router, Route, Switch } from "react-router-dom";
import SpinLoding from "./components/SpinLoding";
//懒加载的页面组件
const Layout = React.lazy(() => import("./pages/Layout"));
const Login = React.lazy(() => import("./pages/Login"));
{/* 关于路由 */}
<Router>
<React.Suspense fallback={<SpinLoding />}>
<Switch>
<Route path="/login" component={Login} />
<Route path="/" component={Layout} />
</Switch>
</React.Suspense>
</Router>
二:异步请求loding
1:新建 src/components/AsyncSpinLoding文件夹
1.1:新建index.tsx
import styles from "./index.module.scss";
import { Spin } from "antd";
import React from "react";
function AsyncSpinLoding() {
return (
<div id="AsyncSpinLoding" className={styles.AsyncSpinLoding}>
<Spin size="large" />
</div>
);
}
const MemoAsyncSpinLoding = React.memo(AsyncSpinLoding);
export default MemoAsyncSpinLoding;
1.2:新建index.module.scss
.AsyncSpinLoding {
opacity: 0;
pointer-events: none;
transition: all .5s;
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100%;
height: 100%;
// background-color: rgba(0, 0, 0, .6);
background-color: transparent;
:global{
.ant-spin-spinning{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
}
}
2.新建src/utils/http.ts来统一处理请求(基于axios)
import axios from "axios";
import { message } from "antd";
// 请求基地址
export const baseURL =
//开发环境 基地址 和 打包环境 基地址。一般打包环境都是为空,各位可以自己设置
process.env.NODE_ENV === "development" ? "后端地址" : "";
// 创建 axios 实例
const http = axios.create({
baseURL: baseURL,
timeout: 5000,
});
//发送请求和所有请求都发送完毕的标识
let axajInd = 0;
//拿到loding加载元素
const lodingDom: any = document.querySelector("#AsyncSpinLoding");
// 请求拦截器
http.interceptors.request.use(
function (config: any) {
// 发请求前打开加载提示
lodingDom.style.opacity = 1;
lodingDom.style.pointerEvents = "auto";
axajInd++;
//这里的代码是获取token和在所有请求头中添加token,先注释
//const { token } = getTokenInfo();
//if (token) config.headers.token = token;
return config;
},
function (err) {
return Promise.reject(err);
}
);
//定义一个定时器,防止发送多个请求,没有token的情况下多次执行返回登录页和 message 消息提示问题
let timeId = -1;
// 响应拦截器
http.interceptors.response.use(
function (response) {
// 请求回来的关闭加载提示
axajInd--;
//所有请求都加载成功之后才隐藏loding
if (axajInd === 0) {
//可以使用延时器,让loding不会一闪而过,本人项目不需要这个效果
// setTimeout(() => {
lodingDom.style.opacity = 0;
lodingDom.style.pointerEvents = "none";
// }, 100);
}
//后端返回5001的时候为token失效,可以根据自己的后端返回值来判断
if (response.data.code === 5001 || response.data.code === 5002) {
//防抖,先清理定时器,防止200毫秒内多次执行
clearTimeout(timeId);
timeId = window.setTimeout(() => {
//清理token信息,先注释,各位根据业务需求自己处理
//removeTokenInfo();
message.warning("登录失效!");
//跳到登录页,这里使用的是自己封装的history,各位可以自己处理调整逻辑,先注释
//history.push("/login");
}, 200);
} else if (response.data.code === 0) {
//请求成功,这里不做处理,在对应的业务模块,针对处理
// message.success(response.data.msg);
} else message.warning(response.data.msg); //请求失败,返回后端的失败信息
return response.data;
},
async function (err) {
//在请求失败的时候,直接把 axajInd 标识归0,防止loding一直存在
axajInd = 0;
// setTimeout(() => {
lodingDom.style.opacity = 0;
lodingDom.style.pointerEvents = "none";
// }, 300);
// 如果因为网络原因,response没有,给提示消息
if (!err.response) {
message.warning("网络繁忙,请稍后重试!");
} else {
message.warning("错误!");
}
return Promise.reject(err);
}
);
// 导出 axios 实例
export default http;
3.在页面中使用,这里我在App根组件中使用,全局都可以拿到这个加载的dom
在src/App.tsx中
//导入
import AsyncSpinLoding from "./components/AsyncSpinLoding";
//使用
{/* 发送请求的加载组件 */}
<AsyncSpinLoding />