Ant Design Pro如何全局更换页面的Loading样式?

本文介绍了在Ant Design Pro v5.0框架中如何全局替换默认的Spin加载动画。通过在src/components创建PageLoading组件,包含index.tsx和index.less文件,然后在app.tsx入口文件中设置全局默认的Spin元素为PageLoading,实现了定制化的页面加载效果。

前言:最新的项目用的是Ant Design Pro v5.0的框架,每个页面的Loading默认用的是Spin组件,以前的项目也是默认用的Spin项目,在这个项目中看到后就有点审美疲劳了~~~,所以就想替换掉默认的加载动画,在网上也找了好多方法,有的是语言不对应,有的是版本不对应,有的虽然可以实现,但是要在每个请求时去做处理,就会比较麻烦,经过认真查阅官网API,在Spin组件的最后一句话中发现了实现的最优方案 ):

官网地址

话不多数,直接上实现过程:

1、在项目的src/components文件下创建一个PageLoading的组件,PageLoading下分2个文件:index.tsx和index.less,一个用来写页面组成元素另一个来写页面样式

index.tsx文件代码如下:

import React from 'react';
import style from './index.less';

const PageLoading: React.FC = () => {

    return (
        <div className={style.page_loading_container}>
            {/* <加载动画 */}
            <div className={style.spinner_box}>
                <div className={style.configure_border_1}>
                    <div className={style.configure_core}></div>
                </div>
                <div className={style.configure_border_2}>
                    <div className={style.configure_core}></div>
                </div>
            </div>
        </div>
    );
};

export default PageLoading;

index.less文件代码如下:

/* 页面刷新 Loading 总容器 */
.page_loading_container {
    display        : flex;
    flex-direction : column;
    align-items    : center;
    justify-content: center;
    height         : 100%;
    min-height     : 420px;
}

.configure_border_1 {
    width          : 50px;
    height         : 50px;
    padding        : 3px;
    position       : absolute;
    display        : flex;
    justify-content: center;
    align-items    : center;
    background     : #ffab91;
    animation      : configure-clockwise 3s ease-in-out 0s infinite alternate;
}

.configure_border_2 {
    width          : 50px;
    height         : 50px;
    padding        : 3px;
    left           : -50px;
    display        : flex;
    justify-content: center;
    align-items    : center;
    background     : rgb(63, 249, 220);
    transform      : rotate(45deg);
    animation      : configure-xclockwise 3s ease-in-out 0s infinite alternate;
}

.configure_core {
    width           : 100%;
    height          : 100%;
    background-color: #37474f;
}

/* 动画 */
@keyframes spin {
    from {
        transform: rotate(0);
    }

    to {
        transform: rotate(359deg);
    }
}

@keyframes configure-clockwise {
    0% {
        transform: rotate(0);
    }

    25% {
        transform: rotate(90deg);
    }

    50% {
        transform: rotate(180deg);
    }

    75% {
        transform: rotate(270deg);
    }

    100% {
        transform: rotate(359deg);
    }
}

@keyframes configure-xclockwise {
    0% {
        transform: rotate(45deg);
    }

    25% {
        transform: rotate(-45deg);
    }

    50% {
        transform: rotate(-135deg);
    }

    75% {
        transform: rotate(-215deg);
    }

    100% {
        transform: rotate(-305deg);
    }
}

@keyframes pulse {
    from {
        opacity  : 1;
        transform: scale(1);
    }

    to {
        opacity  : .25;
        transform: scale(.75);
    }
}

2、在项目的总入口文件(app.tsx)引入PageLoading文件并自定义全局默认 Spin 的元素为PageLoading即可

关键代码如下:

import { Spin, } from 'antd';
import PageLoading from '@/components/PageLoading';
//全局配置Loading
Spin.setDefaultIndicator(<PageLoading />);

3、刷新页面即可看到效果,如下图:

完结撒花~~~

<think>我们需要实现全局防抖,避免在短时间内触发多个Message提示,导致界面被多个提示框占据,影响用户体验。 思路: 1. 我们可以封装一个高阶函数,该函数内部使用防抖策略,控制Message调用的频率。 2. 防抖函数可以设定一个等待时间(例如1秒),在这个时间内,如果多次调用,只执行最后一次。 3. 但是注意:Message组件有多个类型(success, error, warning等),我们需要对每种类型都进行防抖处理,并且同一种类型的提示防抖在一起,不同类型的提示互不影响。 然而,Ant Design的Message组件本身不提供防抖功能,因此我们需要自己实现。 具体方案: 我们可以创建一个messageUtil.js工具模块,在该模块中,我们为每种消息类型创建一个防抖函数。同时,我们还需要考虑同一个类型中不同内容的消息是否需要分开防抖?这里有两种选择: a) 只根据消息类型防抖:即同一种类型的消息,无论内容是否相同,都视为同一类,防抖时间内只显示最后一次。 b) 根据消息类型和内容生成唯一键:这样不同内容的消息不会互相覆盖。 但是,通常我们可能希望即使是相同类型,不同内容的消息也应该独立展示。然而,如果同时触发大量不同内容的消息,也会造成界面混乱。因此,我们需要权衡。 这里我们采用折中方案:为每个消息类型和消息内容生成一个唯一键(将消息内容作为键的一部分),然后针对每个键进行防抖。但是,如果消息内容很长,或者有动态内容,可能会导致键过多,因此我们可以考虑使用消息内容的摘要(如hash)或者限制键的数量(例如使用LRU缓存)。 不过,为了简化,我们可以只对相同内容的消息进行防抖。但实际场景中,消息内容可能每次都不同(比如错误信息包含时间戳或随机数),这样防抖就会失效。 因此,另一种更常见的做法是:对同一种消息类型,不管内容是什么,在防抖时间内只显示一次,且显示最后一次调用的内容。这样可以避免界面被同类型的消息刷屏。 下面我们按照第二种做法:对同一种消息类型进行防抖,不区分内容。这样实现简单,且能有效防止同类型消息的频繁弹出。 步骤: 1. 创建一个对象,用于存储每种消息类型对应的防抖函数。 2. 在防抖函数中,我们使用setTimeout来延迟执行真正的Message显示。 3. 每次调用防抖函数时,会取消前一个等待中的执行,并重新设置新的执行。 但是,注意:我们可能同时需要显示多个不同类型的消息,比如一个成功消息和一个错误消息,它们应该互不影响。 我们将为每种类型(如'success', 'error'等)分别设置防抖函数。 代码实现: 在工具模块中: ```javascript import { message } from 'antd'; // 存储每种消息类型的定时器 const messageDebounceTimers = {}; // 防抖时间(毫秒) const DEBOUNCE_DURATION = 1000; // 防抖的Message函数 const debouncedMessage = (type, content, duration, onClose) => { // 清除该类型之前的定时器 if (messageDebounceTimers[type]) { clearTimeout(messageDebounceTimers[type]); } // 设置新的定时器 messageDebounceTimers[type] = setTimeout(() => { // 调用原始的message方法 message[type](content, duration, onClose); // 执行完后,可以清除定时器引用,但不清除也可以,因为下次会覆盖 }, DEBOUNCE_DURATION); }; // 为每个消息类型创建防抖函数 export const messageUtil = { success: (content, duration, onClose) => debouncedMessage('success', content, duration, onClose), error: (content, duration, onClose) => debouncedMessage('error', content, duration, onClose), warning: (content, duration, onClose) => debouncedMessage('warning', content, duration, onClose), info: (content, duration, onClose) => debouncedMessage('info', content, duration, onClose), loading: (content, duration, onClose) => debouncedMessage('loading', content, duration, onClose), }; ``` 使用方式: 在组件中,我们不再直接使用`message.success`,而是使用我们封装的`messageUtil.success`。 但是,这样封装后,我们无法直接使用message的其他功能(如全局配置等)。如果需要,可以进一步封装。 另外,注意:我们这里只对消息的显示做了防抖,但是每个消息类型在防抖时间内只保留最后一次调用。这样,在防抖时间(1秒)内,如果多次调用同一个类型的消息,最终只会显示最后一次的内容。 然而,上述实现有一个问题:如果我们在短时间内连续调用多次,每次的内容不同,那么最终显示的是最后一次调用的内容,但之前的内容都被丢弃了。这符合防抖的预期。 但是,如果我们希望显示所有内容,只是控制频率,那么防抖就不合适了,可能需要节流(throttle)。不过,节流会按照固定频率显示消息,可能还是会造成消息堆积。因此,我们这里采用防抖,因为通常我们只关心最后一次消息。 另一种思路:使用队列,然后以固定时间间隔显示消息。但这样实现比较复杂,且可能会延迟重要消息的显示。因此,防抖在大多数场景下是合适的。 改进:我们可能希望在某些情况下立即显示消息(比如第一次),然后防抖后续的消息。这可以通过设置`leading`和`trailing`来实现(即lodash的debounce中的选项)。但这里我们只实现简单的trailing防抖。 如果需要更复杂的控制,可以使用lodash的debounce函数,但为了减少依赖,我们自行实现。 另外,注意清理定时器,避免内存泄漏。由于我们只存储了定时器的ID,并且每次都会清除之前的定时器,所以不会造成内存泄漏。 但是,如果组件卸载时,定时器还未执行,可能会尝试更新已卸载组件的状态。然而,Ant Design的Message组件是全局的,不会因为组件卸载而消失,所以没有问题。 但是,我们最好在应用卸载时清除所有定时器,但这种情况很少发生,因为整个应用卸载时,定时器也会被自动清除。 使用示例: ```jsx import { messageUtil } from './messageUtil'; // 在组件中使用 function showSuccess() { messageUtil.success('操作成功!'); } ``` 注意:这个工具模块导出的对象,我们覆盖了常见的消息类型,但如果你需要其他类型,可以自行扩展。 另外,如果我们需要显示多个相同类型的消息(即使内容相同)且不进行防抖,那么这种封装就不适用了。因此,我们需要根据实际场景选择。 如果项目中有不同的防抖需求,我们可以提供两种方式:防抖的消息和非防抖的消息(直接使用antd的message)。 总结:通过为每种消息类型设置防抖函数,我们可以有效避免同类型消息的频繁弹出,提升用户体验。 但是,请注意,防抖的时间需要根据实际需求调整,1秒可能不是最佳时间,可以根据项目调整。 下面我们给出完整的代码,并添加注释。</think>## Ant Design Message 组件全局防抖实现方案 在 Ant Design 中实现全局防抖可以防止用户频繁操作导致消息提示堆积,造成视觉干扰。以下是完整解决方案: ### 核心思路 1. **创建防抖包装器**:封装 Message 组件,添加防抖逻辑 2. **基于消息内容防抖**:相同内容的消息在指定时间内只显示一次 3. **支持自定义防抖策略**:允许不同消息类型使用不同的防抖时间 4. **全局注册**:替换原生 Message 组件 ### 完整实现代码 ```javascript // messageDebounce.js import { message } from 'antd'; // 存储消息内容的最近触发时间 const messageTimestamps = new Map(); // 存储消息内容的定时器 const messageTimers = new Map(); /** * 带防抖的 Message 包装器 * @param {Function} method - 原始消息方法 (success, error, warning等) * @param {string} content - 消息内容 * @param {number} duration - 显示时长(ms) * @param {number} debounceTime - 防抖时间(ms),默认1000 * @param {string} key - 自定义消息键名(可选) */ const debouncedMessage = (method, content, duration = 3, debounceTime = 1000, key) => { // 使用自定义键或内容作为标识 const messageKey = key || content; // 清除现有定时器 if (messageTimers.has(messageKey)) { clearTimeout(messageTimers.get(messageKey)); messageTimers.delete(messageKey); } const now = Date.now(); const lastTimestamp = messageTimestamps.get(messageKey) || 0; // 如果在防抖时间窗口内 if (now - lastTimestamp < debounceTime) { // 设置新的定时器,延迟显示消息 const timer = setTimeout(() => { method({ content, duration, key: messageKey }); messageTimestamps.set(messageKey, Date.now()); }, debounceTime - (now - lastTimestamp)); messageTimers.set(messageKey, timer); return; } // 直接显示消息 method({ content, duration, key: messageKey }); messageTimestamps.set(messageKey, now); }; // 创建防抖消息对象 const debouncedMessageAPI = { success: (content, duration, debounceTime, key) => debouncedMessage(message.success, content, duration, debounceTime, key), error: (content, duration, debounceTime, key) => debouncedMessage(message.error, content, duration, debounceTime, key), warning: (content, duration, debounceTime, key) => debouncedMessage(message.warning, content, duration, debounceTime, key), info: (content, duration, debounceTime, key) => debouncedMessage(message.info, content, duration, debounceTime, key), loading: (content, duration, debounceTime, key) => debouncedMessage(message.loading, content, duration, debounceTime, key), destroy: message.destroy, config: message.config, }; export default debouncedMessageAPI; ``` ### 全局注册使用 ```javascript // src/setupMessage.js import debouncedMessage from './utils/messageDebounce'; // 替换全局 message 对象 if (!window.antdMessageOriginal) { window.antdMessageOriginal = message; // 备份原始对象 message = debouncedMessage; // 替换为防抖版本 } // 在应用入口文件 (src/index.js) 导入 import './setupMessage'; ``` ### 使用示例 ```jsx import { message } from 'antd'; // 基本使用(默认1000ms防抖) const handleClick = () => { message.success('操作成功!'); }; // 自定义防抖时间 const handleCriticalAction = () => { message.error('危险操作!', 3, 3000); // 3秒防抖 }; // 带键名的消息(相同键名共享防抖) const handleUpdate = (id) => { message.info(`更新了项目 ${id}`, 2, 1000, `update-${id}`); }; ``` ### 实现原理详解 1. **消息标识管理** - 使用 `Map` 存储消息键和最近显示时间戳 - 消息键可以是内容本身或自定义键(如 `update-123`) 2. **防抖逻辑** ```javascript if (now - lastTimestamp < debounceTime) { // 设置延迟显示定时器 const timer = setTimeout(() => { // 显示消息并更新时间戳 }, debounceTime - (now - lastTimestamp)); } ``` 3. **定时器管理** - 每个消息键关联一个定时器 - 新消息会清除旧定时器,确保只显示最后一次消息 4. **API 兼容性** - 保持与原生 Message 相同的 API 签名 - 额外支持 `debounceTime` 和 `key` 参数 ### 高级配置选项 在 `messageDebounce.js` 中添加全局配置: ```javascript // 全局防抖配置 const debounceConfig = { defaultDebounceTime: 1000, // 默认防抖时间 typeSpecific: { success: 800, error: 1500, // 错误消息更长防抖时间 loading: 0, // loading 消息不防抖 }, }; // 在 debouncedMessage 函数中: const resolvedDebounceTime = debounceTime || (debounceConfig.typeSpecific[methodName] ?? debounceConfig.defaultDebounceTime); ``` ### 性能优化建议 1. **LRU 缓存策略** ```javascript // 限制最大存储条目 const MAX_ENTRIES = 100; const messageTimestamps = new Map(); const setWithLimit = (map, key, value) => { if (map.size >= MAX_ENTRIES) { // 删除最旧的条目 const oldestKey = map.keys().next().value; map.delete(oldestKey); } map.set(key, value); }; ``` 2. **批量消息处理** ```javascript // 添加批量消息处理方法 const batchMessages = (messages) => { const now = Date.now(); messages.forEach(msg => { if (now - (messageTimestamps.get(msg.key) || 0) > msg.debounceTime) { // 立即显示符合条件的消息 } }); }; ``` 3. **防抖时间动态调整** ```javascript // 根据消息长度动态调整防抖时间 const dynamicDebounceTime = Math.min( 3000, Math.max(500, content.length * 50) ); ``` ### 使用场景建议 | 场景 | 推荐防抖时间 | 键名策略 | |------|-------------|----------| | 表单提交 | 1000ms | 使用操作类型键 `submit-form` | | 实时数据更新 | 300ms | 使用数据ID键 `update-item-${id}` | | 错误通知 | 1500ms | 使用错误类型键 `error-${code}` | | 加载提示 | 0ms (不防抖) | 不需要键名 | | 批量操作 | 2000ms | 使用操作批次键 `batch-${timestamp}` |
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值