下面是全局加载遮罩工具,功能:提供show和showWithDelay/hide方法用于显示/延时显示/隐藏遮罩,它还提供loading属性返回是否正在loading。通常用于耗时较长的操作,比如远端api调用。
如何用它,下面是个例子,这个是全局的postAction:
import loadingMask from './loadingMask';
...
// 设置延迟显示加载遮罩(1秒后显示)
loadingMask.showWithDelay('请求处理中,请稍候...', 1000);
return axios({
url: url,
method: 'post',
data: parameter,
headers: { ...signHeader, ...config.headers },
...config
}).then(res => {
// 请求完成后隐藏加载遮罩
loadingMask.hide();
return handleResponse(res);
}).catch(err => {
// 请求出错后隐藏加载遮罩
loadingMask.hide();
return handleError(err);
});
如果想实时获得它的loading属性呢?这时候要订阅它的状态变化:
const [loading, setLoading] = useState(loadingMask.loading);
// 订阅 loadingMask 的 loading 状态变化
useEffect(() => {
// 订阅 loading 状态变化
const unsubscribe = loadingMask.subscribeToLoading(setLoading);
// 组件卸载时取消订阅
return unsubscribe;
}, []);
...
<Button
block
type='submit'
color='primary'
loading={loading}
>
删除选中记录
</Button>
这时候loadingMask的loading状态变化会立即返回到setLoading,也就会引导起button的重新渲染。
组件代码如下:
import React from 'react';
import { createRoot } from 'react-dom/client';
import { Mask, SpinLoading } from 'antd-mobile';
import styled from 'styled-components';
const LoadingContainer = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #ffffff;
`;
const LoadingText = styled.div`
margin-top: 12px;
font-size: 14px;
`;
/**
* 全局加载遮罩工具
* 用于在长时间请求时显示加载遮罩
*/
class LoadingMask {
constructor() {
this.container = null;
this.root = null;
this.visible = false;
this.timeoutId = null;
this.loadingText = '正在加载,请稍候...';
this._loading = false; // 添加内部 loading 状态
this._listeners = []; // 添加监听器数组
this.init();
}
/**
* 初始化加载遮罩容器
*/
init() {
// 创建容器元素
this.container = document.createElement('div');
this.container.id = 'global-loading-mask-container';
document.body.appendChild(this.container);
// 创建React 18的root
this.root = createRoot(this.container);
// 初始渲染
this.render();
}
/**
* 渲染加载遮罩
*/
render() {
if (!this.root) {
this.init();
return;
}
this.root.render(
<Mask opacity={0.7} visible={this.visible}>
<LoadingContainer>
<SpinLoading color='white' style={{ '--size': '48px' }} />
<LoadingText>{this.loadingText}</LoadingText>
</LoadingContainer>
</Mask>
);
}
/**
* 显示加载遮罩
* @param {string} text - 加载提示文本
*/
show(text) {
this.loadingText = text || '正在加载,请稍候...';
this.visible = true;
this._setLoading(true); // 使用新方法设置 loading 状态
this.render();
}
/**
* 隐藏加载遮罩
*/
hide() {
this.visible = false;
this._setLoading(false); // 使用新方法设置 loading 状态
this.render();
// 清除定时器
if (this.timeoutId) {
clearTimeout(this.timeoutId);
this.timeoutId = null;
}
}
/**
* 设置延迟显示加载遮罩
* @param {string} text - 加载提示文本
* @param {number} delay - 延迟时间(毫秒)
*/
showWithDelay(text, delay = 1000) {
// 清除之前的定时器
if (this.timeoutId) {
clearTimeout(this.timeoutId);
}
// 立即设置 loading 状态为 true
this.loadingText = text || '正在加载,请稍候...';
this._setLoading(true); // 使用新方法设置 loading 状态
// 设置新的定时器,只延迟显示遮罩
this.timeoutId = setTimeout(() => {
this.visible = true;
this.render();
}, delay);
}
// 添加设置 loading 状态的方法,并通知监听器
_setLoading(value) {
if (this._loading !== value) {
this._loading = value;
// 通知所有监听器
this._listeners.forEach(listener => listener(value));
}
};
// 添加订阅方法
subscribeToLoading(callback) {
this._listeners.push(callback);
// 立即通知当前状态
callback(this._loading);
// 返回取消订阅的函数
return () => {
this._listeners = this._listeners.filter(cb => cb !== callback);
};
};
}
// 创建单例实例
const loadingMask = new LoadingMask();
// 添加 loading 属性的 getter
Object.defineProperty(loadingMask, 'loading', {
get: function() {
return this._loading;
}
});
export default loadingMask;