首页
/ React Ant Design Pro消息通知系统:从基础应用到深度定制

React Ant Design Pro消息通知系统:从基础应用到深度定制

2026-05-04 11:15:05作者:范靓好Udolf

在企业级前端框架中,消息通知系统是提升用户体验的关键组件。React Ant Design Pro作为主流的企业级中后台解决方案,提供了完善的消息通知机制,包括轻量级的全局提示(Toast) 和持久化的通知提醒(Notification)。本文将系统解析这两种组件的技术实现与应用场景,帮助开发者构建高效、友好的用户交互体验。

概念解析:认识Ant Design Pro的消息通知体系

Ant Design Pro的消息通知系统基于Ant Design组件库构建,主要包含两类核心组件:Toast(全局提示)Notification(通知提醒)。这两种组件针对不同的使用场景设计,共同构成了完整的用户反馈机制。

核心组件定义

  • 全局提示(Toast):由message组件实现,用于操作结果的即时反馈,通常自动消失,不打断用户当前操作
  • 通知提醒(Notification):由notification组件实现,用于系统级通知,支持手动关闭和点击交互,通常出现在页面角落

企业级应用消息通知设计原则:根据Ant Design Pro设计规范,消息通知应遵循"适时、适度、精准"的原则,既确保用户获取关键信息,又避免过度打扰。

组件功能对比

特性 全局提示(Toast) 通知提醒(Notification)
用途 操作结果反馈 系统重要通知
显示位置 页面顶部居中 右上角/右下角
自动关闭 默认3秒 可配置,默认4.5秒
交互能力 支持点击、关闭
内容复杂度 简单文本 支持标题、描述、图标
典型场景 表单提交成功提示 新消息通知、系统公告

技术实现:从零构建消息通知系统

3分钟上手全局提示

Ant Design Pro的message组件提供了简洁的API,支持多种提示类型和自定义配置。以下是基础使用示例:

// src/components/OperationButton.tsx
import { message } from 'antd';

// 成功提示
const handleSaveSuccess = () => {
  message.success('数据保存成功', 2); // 2秒后自动关闭
};

// 错误提示
const handleDeleteError = () => {
  message.error('删除失败,请重试', 3);
};

// 加载中提示
const handleDataLoading = () => {
  const hide = message.loading('数据加载中...', 0); // 0表示不自动关闭
  // 异步操作完成后手动关闭
  setTimeout(hide, 2000);
};

💡 实战技巧:可以通过message.config()全局配置消息提示的默认行为,如调整显示时长、顶部偏移量等:

// src/app.tsx
import { message } from 'antd';

message.config({
  top: 100, // 距离顶部距离
  duration: 2, // 默认显示时长(秒)
  maxCount: 3, // 最多同时显示条数
});

通知中心深度定制指南

Ant Design Pro的通知中心通常由notification组件构建,支持更复杂的交互和自定义。以下是一个完整的通知中心实现:

// src/components/NotificationCenter.tsx
import { useEffect, useState } from 'react';
import { BellOutlined, CheckCircleOutlined, ClockCircleOutlined } from '@ant-design/icons';
import { Badge, Dropdown, Menu, notification } from 'antd';
import type { MenuProps } from 'antd/es/menu';
import { useNotification } from '@/hooks/useNotification';

const NotificationCenter = () => {
  const [unreadCount, setUnreadCount] = useState(0);
  const { notifications, fetchNotifications, markAsRead } = useNotification();
  
  // 初始化获取通知
  useEffect(() => {
    fetchNotifications().then(data => {
      setUnreadCount(data.filter(item => !item.read).length);
    });
  }, [fetchNotifications]);
  
  // 处理通知点击
  const handleNotificationClick = (id: string) => {
    markAsRead(id);
    setUnreadCount(prev => Math.max(0, prev - 1));
  };
  
  // 构建通知菜单
  const menuItems: MenuProps['items'] = notifications.map(item => ({
    key: item.id,
    icon: item.read ? <ClockCircleOutlined /> : <CheckCircleOutlined style={{ color: '#1890ff' }} />,
    label: (
      <div style={{ width: 300 }} onClick={() => handleNotificationClick(item.id)}>
        <div style={{ fontWeight: item.read ? 'normal' : 'bold' }}>{item.title}</div>
        <div style={{ fontSize: 12, color: '#666', marginTop: 4 }}>{item.content}</div>
        <div style={{ fontSize: 12, color: '#999', marginTop: 4 }}>{item.time}</div>
      </div>
    ),
  }));
  
  // 手动触发通知
  const showNotification = () => {
    notification.open({
      message: '新任务提醒',
      description: '您有3个待处理任务需要关注',
      icon: <BellOutlined />,
      onClick: () => console.log('通知被点击'),
    });
  };
  
  return (
    <Dropdown 
      overlay={<Menu items={menuItems} />} 
      placement="bottomRight"
    >
      <Badge count={unreadCount} showZero>
        <BellOutlined style={{ fontSize: 20, cursor: 'pointer' }} onClick={showNotification} />
      </Badge>
    </Dropdown>
  );
};

export default NotificationCenter;

自定义Hook封装:useNotification

为了更好地管理通知状态和操作,我们可以封装一个自定义Hook:

// src/hooks/useNotification.ts
import { useState, useCallback } from 'react';
import { notificationAPI } from '@/services/notification';
import { useRequest } from 'ahooks';

export interface NotificationItem {
  id: string;
  title: string;
  content: string;
  time: string;
  read: boolean;
  type: 'info' | 'warning' | 'success' | 'error';
}

export function useNotification() {
  const [notifications, setNotifications] = useState<NotificationItem[]>([]);
  
  // 获取通知列表
  const fetchNotifications = useCallback(async () => {
    try {
      const response = await notificationAPI.getList();
      setNotifications(response.data);
      return response.data;
    } catch (error) {
      console.error('获取通知失败:', error);
      return [];
    }
  }, []);
  
  // 标记通知为已读
  const markAsRead = useCallback(async (id: string) => {
    try {
      await notificationAPI.markRead(id);
      setNotifications(prev => 
        prev.map(item => item.id === id ? { ...item, read: true } : item)
      );
    } catch (error) {
      console.error('标记通知失败:', error);
    }
  }, []);
  
  // 标记全部为已读
  const markAllAsRead = useCallback(async () => {
    try {
      await notificationAPI.markAllRead();
      setNotifications(prev => 
        prev.map(item => ({ ...item, read: true }))
      );
    } catch (error) {
      console.error('标记全部通知失败:', error);
    }
  }, []);
  
  return {
    notifications,
    fetchNotifications,
    markAsRead,
    markAllAsRead
  };
}

WebSocket实时推送实现

在企业级应用中,实时通知推送是提升用户体验的重要功能。以下是基于WebSocket的实时通知实现:

// src/services/websocket.ts
import { notification } from 'antd';
import { useAuthStore } from '@/stores/auth';

let socket: WebSocket | null = null;

export const connectWebSocket = () => {
  const { token } = useAuthStore.getState();
  
  // 关闭已有连接
  if (socket) {
    socket.close();
  }
  
  // 建立新连接
  socket = new WebSocket(`wss://your-api-domain/ws/notifications?token=${token}`);
  
  // 连接成功
  socket.onopen = () => {
    console.log('WebSocket连接已建立');
  };
  
  // 接收消息
  socket.onmessage = (event) => {
    try {
      const message = JSON.parse(event.data);
      handleNotification(message);
    } catch (error) {
      console.error('解析WebSocket消息失败:', error);
    }
  };
  
  // 连接关闭
  socket.onclose = (event) => {
    console.log('WebSocket连接关闭:', event.code, event.reason);
    // 自动重连
    setTimeout(connectWebSocket, 5000);
  };
  
  // 连接错误
  socket.onerror = (error) => {
    console.error('WebSocket错误:', error);
  };
};

// 处理接收到的通知
const handleNotification = (data: any) => {
  // 显示通知
  notification.open({
    message: data.title,
    description: data.content,
    type: data.type || 'info',
    duration: 5,
  });
  
  // 可以在这里更新本地通知列表
  // 例如调用useNotification hook中的fetchNotifications方法
};

// 应用初始化时连接WebSocket
export const initWebSocket = () => {
  if (useAuthStore.getState().isLogin) {
    connectWebSocket();
  }
};

场景应用:企业级业务解决方案

表单提交反馈最佳实践

在表单操作中,合理使用消息通知可以显著提升用户体验:

// src/views/user/EditUserForm.tsx
import { useCallback } from 'react';
import { Form, Button, message } from 'antd';
import { userAPI } from '@/services/user';

const EditUserForm = ({ userId, onSuccess }) => {
  const [form] = Form.useForm();
  const [loading, setLoading] = useState(false);
  
  const handleSubmit = useCallback(async () => {
    try {
      setLoading(true);
      const values = await form.validateFields();
      await userAPI.update(userId, values);
      message.success('用户信息更新成功');
      onSuccess();
    } catch (error) {
      // 表单验证失败不显示错误消息
      if (!(error instanceof Error) || error.name !== 'ValidateError') {
        message.error('更新失败,请稍后重试');
      }
    } finally {
      setLoading(false);
    }
  }, [form, userId, onSuccess]);
  
  return (
    <Form form={form} layout="vertical">
      {/* 表单字段 */}
      <Form.Item>
        <Button type="primary" loading={loading} onClick={handleSubmit}>
          保存
        </Button>
      </Form.Item>
    </Form>
  );
};

批量操作通知策略

处理批量操作时,需要考虑操作结果的复杂性和用户等待体验:

// src/views/product/BatchOperations.tsx
import { useState } from 'react';
import { Button, message, Modal } from 'antd';
import { productAPI } from '@/services/product';

const BatchOperations = ({ selectedRowKeys }) => {
  const [processing, setProcessing] = useState(false);
  
  const handleBatchDelete = async () => {
    if (selectedRowKeys.length === 0) {
      message.warning('请先选择需要删除的产品');
      return;
    }
    
    Modal.confirm({
      title: '确认删除',
      content: `您确定要删除选中的${selectedRowKeys.length}个产品吗?此操作不可撤销。`,
      okText: '确认',
      cancelText: '取消',
      onOk: async () => {
        try {
          setProcessing(true);
          const result = await productAPI.batchDelete(selectedRowKeys);
          
          if (result.successCount > 0 && result.failureCount === 0) {
            message.success(`成功删除${result.successCount}个产品`);
          } else if (result.successCount > 0 && result.failureCount > 0) {
            message.warning(
              `部分删除成功,成功${result.successCount}个,失败${result.failureCount}个`
            );
          } else {
            message.error('删除失败,请稍后重试');
          }
        } catch (error) {
          message.error('操作失败:' + (error as Error).message);
        } finally {
          setProcessing(false);
        }
      }
    });
  };
  
  return (
    <Button 
      danger 
      icon={<DeleteOutlined />} 
      onClick={handleBatchDelete}
      loading={processing}
      disabled={selectedRowKeys.length === 0}
    >
      批量删除
    </Button>
  );
};

实时协作通知系统

在多人协作场景中,实时通知可以提高团队协作效率:

// src/views/document/CollaborationNotice.tsx
import { useEffect } from 'react';
import { Tag, Tooltip } from 'antd';
import { UserOutlined } from '@ant-design/icons';
import { useWebSocket } from '@/hooks/useWebSocket';

const CollaborationNotice = ({ documentId }) => {
  const [activeUsers, setActiveUsers] = useState([]);
  
  const { onMessage } = useWebSocket();
  
  useEffect(() => {
    // 订阅文档协作事件
    const unsubscribe = onMessage('document协作', (data) => {
      if (data.documentId === documentId) {
        if (data.type === 'userJoined') {
          setActiveUsers(prev => {
            if (!prev.some(u => u.id === data.user.id)) {
              return [...prev, data.user];
            }
            return prev;
          });
          message.info(`${data.user.name}正在查看此文档`);
        } else if (data.type === 'userLeft') {
          setActiveUsers(prev => prev.filter(u => u.id !== data.userId));
        }
      }
    });
    
    return () => unsubscribe();
  }, [documentId, onMessage]);
  
  return (
    <div style={{ marginBottom: 16 }}>
      <Tooltip title="当前在线用户">
        <Tag icon={<UserOutlined />} color="blue">
          协作中 {activeUsers.length}人
        </Tag>
      </Tooltip>
      
      {activeUsers.map(user => (
        <Tag key={user.id} color="green" style={{ marginLeft: 8 }}>
          {user.name}
        </Tag>
      ))}
    </div>
  );
};

主题定制与无障碍访问

通知组件主题定制

Ant Design Pro支持通过主题配置自定义通知组件的样式:

// src/config/theme.ts
import type { ThemeConfig } from 'antd';

export const theme: ThemeConfig = {
  token: {
    // 全局提示主题
    colorInfo: '#1677ff',
    colorSuccess: '#52c41a',
    colorWarning: '#faad14',
    colorError: '#ff4d4f',
    
    // 通知组件
    notificationBg: '#fff',
    notificationPadding: 16,
    notificationShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
  },
  components: {
    Message: {
      borderRadius: 4,
      contentFontSize: 14,
    },
    Notification: {
      borderRadius: 8,
      titleFontSize: 16,
      descriptionFontSize: 14,
    },
  },
};

无障碍访问支持

为确保所有用户都能有效使用通知功能,需要添加无障碍支持:

// src/components/AccessibleNotification.tsx
import { useEffect } from 'react';
import { notification } from 'antd';

export const accessibleNotification = {
  // 成功通知
  success: (message: string, description?: string) => {
    const key = `success_${Date.now()}`;
    
    // 显示通知
    notification.success({
      message,
      description,
      key,
      // 添加ARIA标签
      ariaLabel: `成功通知: ${message}`,
    });
    
    // 为屏幕阅读器添加通知
    useEffect(() => {
      const announcement = document.createElement('div');
      announcement.setAttribute('role', 'status');
      announcement.setAttribute('aria-live', 'polite');
      announcement.style.position = 'absolute';
      announcement.style.width = '1px';
      announcement.style.height = '1px';
      announcement.style.overflow = 'hidden';
      document.body.appendChild(announcement);
      
      announcement.textContent = `成功: ${message}`;
      
      return () => {
        document.body.removeChild(announcement);
      };
    }, [message]);
    
    return key;
  },
  
  // 其他类型通知...
};

性能优化:提升通知系统效率

通知渲染优化

对于大量通知的场景,可以通过虚拟滚动提升性能:

// src/components/VirtualizedNotificationList.tsx
import { useState } from 'react';
import { List, Spin } from 'antd';
import { VirtualList } from 'rc-virtual-list';
import { useNotification } from '@/hooks/useNotification';

const VirtualizedNotificationList = () => {
  const { notifications, fetchNotifications } = useNotification();
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    fetchNotifications().finally(() => setLoading(false));
  }, [fetchNotifications]);
  
  if (loading) return <Spin size="large" />;
  
  return (
    <div style={{ height: 400, width: 350, border: '1px solid #e8e8e8' }}>
      <VirtualList
        data={notifications}
        height={400}
        itemHeight={80}
        itemKey="id"
      >
        {item => (
          <List.Item
            key={item.id}
            actions={[<a onClick={() => markAsRead(item.id)}>标为已读</a>]}
          >
            <List.Item.Meta
              title={item.title}
              description={
                <div>
                  <p>{item.content}</p>
                  <p style={{ fontSize: 12, color: '#999' }}>{item.time}</p>
                </div>
              }
            />
          </List.Item>
        )}
      </VirtualList>
    </div>
  );
};

通知频率控制

为避免频繁通知对用户造成干扰,可以实现通知合并机制:

// src/utils/notificationThrottle.ts
import { message } from 'antd';

// 通知缓存,用于合并相似通知
const notificationCache = new Map<string, { timer: NodeJS.Timeout; count: number }>();

/**
 * 合并相似通知
 * @param key 通知唯一标识
 * @param messageContent 通知内容
 * @param delay 合并延迟时间(ms)
 */
export const mergeNotification = (
  key: string,
  messageContent: string,
  delay = 3000
) => {
  const existing = notificationCache.get(key);
  
  if (existing) {
    // 已存在相同通知,更新计数并重置计时器
    clearTimeout(existing.timer);
    notificationCache.set(key, {
      ...existing,
      count: existing.count + 1,
      timer: setTimeout(() => {
        message.info(`${messageContent} (${existing.count + 1}条)`);
        notificationCache.delete(key);
      }, delay)
    });
  } else {
    // 新通知,设置计时器
    const timer = setTimeout(() => {
      message.info(messageContent);
      notificationCache.delete(key);
    }, delay);
    
    notificationCache.set(key, { timer, count: 1 });
  }
};

常见问题排查

通知不显示问题排查

当通知组件不显示时,可以按照以下步骤排查:

  1. 检查容器样式:确保通知容器没有被其他元素遮挡或设置了overflow: hidden
/* 错误示例:可能导致通知被隐藏 */
.ant-layout-content {
  overflow: hidden; /* 移除或改为overflow: visible */
}
  1. 检查Z-index设置:确保通知组件的z-index高于其他元素
/* 全局样式中设置 */
.ant-notification, .ant-message {
  z-index: 1010 !important; /* 确保高于其他UI元素 */
}
  1. 检查API调用:确认通知API调用正确
// 错误示例
notification({
  message: '通知标题', // 缺少type或使用了错误的API
});

// 正确示例
notification.open({
  message: '通知标题',
  description: '通知内容'
});

WebSocket连接问题解决

WebSocket连接失败是实时通知常见问题,解决方案包括:

  1. 跨域问题处理:确保服务端正确配置CORS
// src/services/websocket.ts - 处理跨域
const connectWebSocket = () => {
  // 使用withCredentials确保cookie传递
  socket = new WebSocket(`wss://your-api-domain/ws/notifications`, {
    withCredentials: true
  });
};
  1. 认证失效处理:实现token过期自动重连
// src/services/websocket.ts - 处理token过期
socket.onmessage = (event) => {
  const message = JSON.parse(event.data);
  if (message.type === 'tokenExpired') {
    // 重新获取token
    authAPI.refreshToken().then(newToken => {
      // 使用新token重新连接
      connectWebSocket();
    });
  }
};
  1. 网络异常恢复:实现断线自动重连机制
// src/services/websocket.ts - 指数退避重连
let reconnectAttempts = 0;

const connectWebSocket = () => {
  // 清除之前的重连计时器
  if (reconnectTimer) clearTimeout(reconnectTimer);
  
  socket = new WebSocket(`wss://your-api-domain/ws/notifications`);
  
  socket.onclose = (event) => {
    // 计算重连延迟(指数退避)
    const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), 30000);
    reconnectAttempts++;
    
    reconnectTimer = setTimeout(() => {
      connectWebSocket();
    }, delay);
  };
};

总结与最佳实践

Ant Design Pro的消息通知系统是提升用户体验的关键组件,通过合理使用messagenotification组件,可以为用户提供及时、清晰的反馈。以下是企业级应用的最佳实践总结:

  1. 选择合适的通知类型

    • 操作结果反馈使用message
    • 重要系统通知使用notification
    • 复杂交互确认使用Modal.confirm
  2. 通知设计原则

    • 保持简洁:通知内容控制在2-3行内
    • 提供操作:重要通知应包含直接操作按钮
    • 尊重用户:提供关闭和静音选项
  3. 性能与体验平衡

    • 合并相似通知,避免消息轰炸
    • 使用虚拟滚动处理大量历史通知
    • 实现WebSocket自动重连机制
  4. 无障碍支持

    • 为通知添加ARIA标签
    • 支持键盘操作关闭通知
    • 为屏幕阅读器提供通知朗读

通过本文介绍的技术实现和最佳实践,开发者可以构建出既美观又实用的消息通知系统,为企业级应用提供专业、流畅的用户体验。

登录后查看全文
热门项目推荐
相关项目推荐