异步同步示例会先展示失败状态,重试后完成。
保存一条提醒,卸载后可恢复;关闭提醒会删除存档。
<div class="icen-toolbar" style="margin-bottom:10px"> <span class="icen-toolbar-label">语义</span> <button class="icen-btn icen-btn-sm" id="notif-async">异步同步与重试</button> <button class="icen-btn icen-btn-sm" id="notif-info">普通通知</button> <button class="icen-btn icen-btn-sm icen-btn-primary" id="notif-success">成功反馈</button> <button class="icen-btn icen-btn-sm" id="notif-warn">配额提醒</button> <button class="icen-btn icen-btn-sm icen-btn-danger" id="notif-error">失败反馈</button></div><div class="icen-toolbar" style="margin-bottom:10px"> <span class="icen-toolbar-label">特性</span> <button class="icen-btn icen-btn-sm" id="notif-progress">进度通知</button> <button class="icen-btn icen-btn-sm" id="notif-group">同组消息</button> <button class="icen-btn icen-btn-sm" id="notif-confirm">Promise 确认</button> <button class="icen-btn icen-btn-sm" id="notif-multi">多按钮</button> <button class="icen-btn icen-btn-sm" id="notif-countdown">倒计时(8s)</button> <button class="icen-btn icen-btn-sm" id="notif-priority">高优先级</button></div><div class="icen-toolbar" style="margin-bottom:10px"> <span class="icen-toolbar-label">丰富</span> <button class="icen-btn icen-btn-sm" id="notif-avatar">带头像</button> <button class="icen-btn icen-btn-sm" id="notif-link">带链接</button> <button class="icen-btn icen-btn-sm" id="notif-unread">未读标记</button> <button class="icen-btn icen-btn-sm" id="notif-actions">actions 回调</button> <button class="icen-btn icen-btn-sm" id="notif-update">动态更新</button></div><div class="icen-toolbar"> <span class="icen-toolbar-spacer"></span> <span class="icen-toolbar-label" id="notif-count" dir="auto">0 条</span> <button class="icen-btn icen-btn-sm" id="notif-read">全部已读</button> <button class="icen-btn icen-btn-sm" id="notif-clear">清空</button></div><p class="demo-label"><bdi>异步同步示例会先展示失败状态,重试后完成。</bdi></p><div class="icen-toolbar" style="margin-top:16px"> <span class="icen-toolbar-label">保留</span> <button class="icen-btn icen-btn-sm" id="notif-save">保存提醒</button> <button class="icen-btn icen-btn-sm" id="notif-unmount">卸载通知区</button> <button class="icen-btn icen-btn-sm" id="notif-restore">恢复通知区</button> <button class="icen-btn icen-btn-sm" id="notif-forget">清除存档</button></div><p class="demo-label" id="notif-archive-status" role="status"><bdi>保存一条提醒,卸载后可恢复;关闭提醒会删除存档。</bdi></p>
特性
- 能力:进度通知、Promise confirm、多按钮、优先级置顶、详情链接
- 交互:hover 暂停 + 倒计时进度条;已读 / 未读状态
- 外观:自定义图标 / 头像;多容器并存
- 持久:localStorage 持久化,刷新不丢
- 配套:行为在
behaviors/notification
与 toast(瞬时)/ alert(内嵌)正交:需要持久与可操作的通知才用它。
接口
- 初始化
initNotification()(kit 一行入口可直接命名导入)- 导出
-
notifycreateNotificationCenter - 类型
dist/behaviors/notification.d.mts(随 npm 包发布,含全部 JSDoc 约束)
安装
bun add @icen.ai/ui pnpm add @icen.ai/ui npm install @icen.ai/ui yarn add @icen.ai/ui 一行引入该组件(CSS 与 behavior 自动带上,无需关心内部 CSS 文件名):
import '@icen.ai/ui/kit/notification';
也可以用脚手架直接打印引入行:
bunx --bun @icen.ai/ui add notification
Astro 项目注意:kit 入口里的 CSS import 在页面 <script> 里会被 Astro 的 client bundle 摇掉——请改在布局 frontmatter 里引 CSS(import '@icen.ai/ui/components/notification.css';),JS 行为仍可走 kit。Vite SPA / webpack 项目无此问题。
用法
import { notify, createNotificationCenter } from '@icen.ai/ui/behaviors/notification';// ── 便捷 API ──notify.success('已发布', { description: '5 分钟后全量生效' });notify.warn('配额将尽', { description: '已用 80%', duration: 8000 }); // 8s 自动关闭notify.error('发布失败', { description: '封面图尺寸不足' });// ── 进度通知(返回 handle,可动态 setProgress)──const h = notify.progress('正在导出', { progressLabel: '准备中…' });let p = 0;const timer = setInterval(() => { p += 0.08; if (p >= 1) { h.setProgress(1, '完成'); clearInterval(timer); setTimeout(() => h.dismiss(), 1500); } else { h.setProgress(p, '导出中 ' + Math.round(p * 100) + '%'); }}, 300);// ── Promise confirm(阻塞式确认)──const ok = await notify.confirm('确认删除该作品?', { description: '此操作不可撤销,相关数据将被清除。', confirmLabel: '删除', cancelLabel: '取消',});if (ok) { /* 执行删除 */ }// ── 多按钮 ──notify.info('评论了你的作品', { description: '「很喜欢这段配乐」—— 沈墨', avatar: 'https://example.com/u.jpg', actions: [ { label: '回复', type: 'primary', onClick: () => openReply() }, { label: '忽略', onClick: () => {} }, ], link: '/works/123', linkLabel: '查看作品',});// ── 同组消息:每个容器按 tag 折叠,保留各条原始操作 ──notify.info('林晚晴补充了批注', { tag: 'review:42', unread: true });notify.info('沈墨回复了批注', { tag: 'review:42', unread: true });// 入口显示同组数量/未读数;展开后分别处理。maxStack 按原始记录数计算。// 隐藏成员暂停计时,焦点或进行中的操作不会被折叠。// ── 高优先级置顶 + 未读 ──notify.error('服务中断', { description: 'gateway-001 不可达,已自动切换备用节点', priority: 'high', unread: true,});// ── Handle 方法 ──h.update({ title: '新标题', description: '更新后' });h.markRead();h.pause(); h.resume();h.dismiss();notify.markRead(); // 全部已读notify.clear(); // 全清notify.get(id); // 读取notify.getAll(); // 全部// ── 多容器(独立位置与配置)──const center = createNotificationCenter(document.body, { position: 'bottom-right', maxStack: 3, persist: 'app:messages',});center.push({ title: '新消息', kind: 'info', options: { description: '…' } });center.markAllRead();center.destroy(); // 卸载并保留常驻提醒存档,重新创建同 key 的中心可恢复。// dismiss()/clear() 删除存档;动作函数不序列化,可 update({ actions }) 重新接入。// 如需永久清空:先 center.clear(),再 center.destroy()。// ── 全局配置 ──notify.config({ position: 'top-right', maxStack: 5, pauseOnHover: true });