Pinia 通过 state 集中管理跨组件未读消息数,用对象键值对区分标签页,actions 统一更新,getters 派生总和,插件持久化防刷新丢失。

标签页未读消息数量这类状态,本质是跨组件、需实时同步的共享数据——比如聊天列表页、通知中心、顶部导航栏都可能显示同一个数字。直接在组件内用 ref 或 data 管理会导致更新不同步、逻辑分散、难以追踪来源。Pinia 的 state 正是为此设计的集中存储点。
用 State 定义未读数基础结构
在 store 中声明一个响应式对象,明确记录各标签页的未读量。不推荐只存一个总和,因为不同标签页(如“系统通知”“私信”“群聊”)需要独立计数:
- 定义
unreadCounts为对象,键为标签页唯一标识(如'notification'、'chat'),值为数字 - 初始化时设默认值,避免访问
undefined导致计算错误 - 使用
ref包裹整个对象,确保响应式更新能被 Vue 自动追踪
通过 Actions 统一更新逻辑
所有修改都必须走 actions,禁止组件直接赋值。这样能保证行为可追溯、可加日志、可做防抖或合并:
-
increment(tabKey: string):安全地 +1,自动处理键不存在的情况 -
setCount(tabKey: string, count: number):支持重置或精确设值(如拉取后覆盖) -
clearAll()或clearTab(tabKey: string):用于已读操作后清零
用 Getters 派生聚合状态
导航栏常需显示“总未读数”,但不应在每个组件里重复累加。用 getters 声明一个计算属性:
-
totalUnread返回Object.values(unreadCounts).reduce((a, b) => a + b, 0) - 它会自动响应
unreadCounts的任何变更,无需手动刷新 - 如果某类标签页需隐藏(如“已关闭群聊”),可在 getter 内加过滤条件
结合持久化避免刷新丢失
用户刷新页面后未读数归零,体验极差。启用 pinia-plugin-persistedstate 插件,配置只持久化 unreadCounts 字段:
- 插件自动将 state 存入
localStorage,页面加载时恢复 - 注意排除临时字段(如 loading 状态),避免污染持久层
- 若需服务端对齐,可在
onMounted时调用 action 触发一次同步请求


















