通知与消息系统
通知系统是 Web 应用中连接用户与实时信息的重要桥梁。一个成熟的通知系统需要覆盖从服务端推送到前端展示的全链路,同时兼顾用户体验、性能开销和权限管理。本文从前端视角出发,深入探讨 Web 通知系统的核心技术方案。
Web Notification API 使用与权限管理
浏览器通知 API
Web Notification API 允许网页向用户发送系统级桌面通知,即使用户没有停留在当前页面也能收到提醒。其使用流程分为三步:
- 检查权限:通过
Notification.permission获取当前授权状态 - 请求权限:调用
Notification.requestPermission()弹窗询问用户 - 发送通知:创建
new Notification(title, options)实例
async function requestNotificationPermission(): Promise<boolean> {
if (!('Notification' in window)) {
console.warn('浏览器不支持 Notification API');
return false;
}
const permission = await Notification.requestPermission();
return permission === 'granted';
}
function sendDesktopNotification(title: string, options?: NotificationOptions) {
if (Notification.permission === 'granted') {
new Notification(title, {
icon: '/favicon.ico',
body: options?.body || '',
tag: options?.tag || 'default',
...options
});
}
}权限管理策略
实践中需要注意以下权限管理要点:
- 渐进请求:在用户首次触发有意义的交互(如收到消息)时请求权限,而不是页面加载时就弹出
- 权限降级:用户拒绝后不应反复弹窗,应提供 UI 引导让用户手动开启
- 静默模式:支持让用户选择关闭通知而不触发浏览器的权限拒绝状态
SSE 推送原理
SSE(Server-Sent Events)是一种服务端向浏览器推送数据的轻量级技术。与 WebSocket 的双工通信不同,SSE 是单向的——仅服务端可发送数据,浏览器通过 EventSource API 接收。
SSE 与 WebSocket 对比
| 维度 | SSE | WebSocket |
|---|---|---|
| 通信方向 | 服务端 → 客户端(单向) | 双向 |
| 协议 | HTTP | WS/WSS |
| 自动重连 | 原生支持 | 需自行实现 |
| 消息格式 | 文本(默认 UTF-8) | 文本或二进制 |
| 浏览器支持 | 广泛 | 广泛 |
| 适用场景 | 通知推送、数据流更新 | 即时通讯、游戏 |
EventSource 使用
class NotificationSSE {
private eventSource: EventSource | null = null;
connect(url: string) {
this.eventSource = new EventSource(url);
this.eventSource.onopen = () => {
console.log('SSE 连接已建立');
};
this.eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
this.handleNotification(data);
};
this.eventSource.onerror = () => {
// EventSource 自动重连,无需手动处理
console.warn('SSE 连接异常,等待重连...');
};
}
disconnect() {
this.eventSource?.close();
}
}SSE 的核心优势在于其简洁性:基于标准 HTTP 协议,服务端无需引入额外的库,前端通过 EventSource 即可消费。此外,EventSource 内置自动重连机制,当连接断开时会自动尝试重连。
消息中心组件设计
通知列表组件
一个完整的消息中心包含两层 UI:
下拉通知面板:
- 顶部标题栏 + "全部已读"操作
- 最近 N 条通知列表(按时间倒序)
- 未读通知有蓝色圆点标识
- 每条通知可单独标记已读
- 底部"查看全部"入口
消息中心页面:
- 左侧分类导航(全部、系统通知、点赞、评论、关注)
- 右侧通知列表(显示标题、描述、时间)
- 各分类的未读计数
分类管理
通知按业务类型划分为多个类别,便于用户聚焦处理:
- 系统通知:维护公告、版本更新、安全提醒
- 点赞通知:内容被点赞、收藏
- 评论通知:收到评论、回复
- 关注通知:新粉丝、新关注
标记已读
标记已读是通知系统的核心交互。设计时需要考虑:
- 单条标记:每条通知上显示"标为已读"按钮
- 批量标记:支持"全部已读"一键操作
- 自动标记:点击通知进入详情页后自动标记为已读
- 已读状态持久化:记录已读 ID 列表,跨设备同步
未读计数与徽章
未读计数是通知系统的"门面",直接影响用户对系统的感知。
前端实现策略
服务端推送新通知 → 前端接收 → 更新本地未读计数 → 刷新徽章显示 ↓
↙ ↘
桌面端数字徽章 浏览器 Tab 标题徽章组件设计
徽章(Badge)组件需要处理边界情况:
- 计数为 0 时隐藏
- 超过 99 条时显示 "99+"
- 新增通知时带弹跳/缩放动画
- 颜色使用红色以引起注意
多端同步
用户可能同时在浏览器和桌面端登录,未读计数需要在各端保持一致。通常的做法是:
- 服务端维护每个用户的全局未读计数
- 前端在连接 SSE 时获取当前未读总数
- 每次推送新通知时,服务端下发递增后的计数
- 标记已读时前端发送确认请求,服务端重新计算未读数
实时推送体验优化
通知动画
当用户收到新通知时,应提供即时的视觉反馈:
- Toast 提示:右上角滑入式弹窗,显示通知标题和摘要,3-4 秒后自动消失
- 徽章弹跳:通知栏图标上的徽章数字变化时带有弹跳动画
- 列表插入动画:新的通知项以淡入或滑动方式插入列表顶部
性能优化
高频推送场景下需注意性能问题:
- 节流合并:短时间内大量相同类型的通知可以合并为一条(如"3 人赞了你的文章")
- 虚拟滚动:通知列表超过 50 条时启用虚拟滚动
- 懒加载:图片类通知内容延迟加载
- 页面可见性:页面不可见时暂停不必要的动画和轮询
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
// 暂停动画、降低轮询频率
this.throttleInterval = 30000;
} else {
// 恢复频率、拉取离线期间遗漏的通知
this.throttleInterval = 5000;
this.syncMissedNotifications();
}
});声音通知
对于重要通知,可以配合音频提醒。前端通过 AudioContext 或简单的 Audio 元素播放提示音,同时提供设置面板让用户选择是否开启声音。
总结
构建企业级通知系统的前端方案涉及 Web Notification API、SSE 推送、消息中心组件设计、未读计数管理和用户体验优化等多个层面。合理利用浏览器原生 API 和前端工程化手段,可以打造出高实时性、低性能开销的通知体验。
以下是一个消息通知系统的交互 Demo,展示了下拉通知面板、消息中心页面、实时推送动画和分类管理等功能: