消息列表须用包裹每条通知,标题用,时间戳用,未读状态用aria-label显式声明,动态时间更新需绑定唯一ID定时器并监听transitionend,未读同步以服务端为准。

消息列表必须用 <article></article> 包裹每条通知
不用 <div> 堆砌,否则屏幕阅读器无法识别独立消息单元,键盘焦点也会错乱。每个 <code><article></article> 代表一条完整、可单独操作的通知。
-
<h3></h3>作为标题容器,不能降级为<div class="title"> —— 否则语义丢失,SEO 和无障碍都受损 <li>时间戳必须用 <code><time datetime="2026-05-10T04:42:00+08:00"></time>,不能只写“刚刚”或“5分钟前”——JS 后续要靠el.dateTime解析,中文文本无法可靠反向转成时间对象 - 未读状态必须显式声明:
aria-label="未读:系统维护将于今晚23:00开始",而不是仅靠class="unread"+ CSS 变色——后者对视障用户完全不可见 - 正确格式示例:
2026-05-10T04:42:00+08:00(中国标准时间)或2026-05-09T20:42:00Z(UTC) - 若后端无法输出带时区,前端需补全:
new Date(`${isoDate}+08:00`),但不如后端直接提供可靠 - 别用
toLocaleString()直接渲染时间戳——它不解决解析问题,反而掩盖了原始时间源缺陷 - 每条消息应有唯一 ID(如
id="msg_abc123"),JS 用该 ID 绑定独立定时器,避免互相干扰 - 添加/移除通知时,必须
clearInterval对应定时器,否则内存泄漏 + 多余计算 - 使用
transitionend事件判断动画结束,再真正从 DOM 移除元素——否则opacity: 0后 JS 还在尝试更新已不可见节点的时间文本 - “X 分钟前”逻辑建议封装为函数:
formatRelativeTime(new Date(el.querySelector('time').dateTime)),复用且可测 - 多标签页场景下,一个标签页标记已读,其他页不会自动响应——必须配合
storage事件监听并触发重载或局部更新 - 用户清空缓存或换设备,
localStorage数据丢失,未读数就永久错位 - 真正可靠的方案:每次打开消息列表,先发请求
GET /api/messages?status=unread,以服务端返回的unread_count和message_ids为准;localStorage仅作临时优化,不参与状态判定
datetime 属性值必须带时区且为 ISO 8601 格式
后端返回的时间字段如果只是 "2026-05-10 04:42:00" 或 "2026-05-10",前端用 new Date() 解析会默认按本地时区处理,跨地区用户看到的“距今 X 小时”可能差 8 小时。
动态更新时间显示(如“2分钟前”)必须监听 transitionend 和手动控制定时器
纯靠 setInterval 每秒刷新所有消息的时间文本,既浪费性能,又在通知关闭动画中导致 DOM 状态错乱。
未读状态同步必须以后端为准,localStorage 只存 ID 列表
前端用 localStorage.setItem('readMsgIds', JSON.stringify(['msg_abc123'])) 缓存已读 ID 是常见做法,但极易出错:
立即学习“前端免费学习笔记(深入)”;
datetime 值没带时区,以及未读状态在多端间不同步时,靠前端缓存硬扛——这两处一旦上线,排查成本远高于初期规范约束。



















