@ccgf/red-dot
v0.1.5
Published
红点树:条件树求值 + 脏传播 + 帧末批量重算。零资源、零工程脚本 —— 装上即用,删掉即消失。
Maintainers
Readme
@ccgf/red-dot
红点树 —— id 就是路径的一套红点系统。
npm i @ccgf/red-dot装完之后,在希望红点生效的入口 import 一次(它自带模块,负责把"已读"接进存档):
import '@ccgf/red-dot';默认样式预制体
resources/reddot/default.prefab由编辑器扩展在安装本模块时自动生成 ✓ (预制体只能放在工程里,所以它不随包发布 ✓)。
只有两件事要做
// ① 业务:这一格有新东西了
Reddot.trigger('bag.tabs.0.item.1001');
// ② UI:挂到哪个节点上 / 玩家看过了
import { Reddot, EReddotAlign } from '@ccgf/red-dot';
Reddot.bind('bag.tabs.0.item.1001', itemNode, EReddotAlign.RIGHT_TOP);
Reddot.markRead('bag.tabs.0.item.1001');规则(全部由内核保证)
- id 就是路径:
trigger/bind用哪个路径,整条链自动长出来 —— 不需要提前 define; - 叶子 = 没有子节点的节点,传进来的路径最后一段默认是叶子; 叶子一旦长了子节点就不再是叶子(它原来的状态作废);
- 触发只在最底层叶子上生效:
trigger(path)只有一个参数,意思就是"有新东西了"; - 向上传递:父节点
on= 任一子亮,count= 底下亮着几个叶子 —— 所以上层一行都不用写(底部 Tab、主界面入口都是自动汇总出来的); - UI 与状态无关:界面没打开时业务照样建树;界面创建/销毁都不影响红点状态;
- 一个 id 对应一个 UI;每次
bind都instantiate一份样式;owner销毁时自动退绑; - 已读由红点自己记(
ReddotModule+@Persistent)—— 业务模块不用维护任何"读没读"。
接口
| 接口 | 说明 |
| --- | --- |
| Reddot.trigger(path) | 触发(有新东西了);路径不存在会自动建;幂等 |
| Reddot.markRead(path) | 玩家看过了:灭 + 记已读(跟着存档走) |
| Reddot.markReadTree(prefix) | 一条链下的叶子全标已读(顶层"全部已读") |
| Reddot.clear(path) | 熄灭但不记已读(数据还在、只是不再提示) |
| Reddot.remove(path) | 数据没了:摘掉(空祖先一并上收) |
| Reddot.get(path) / find(path) / listNodes() | 读状态 / 取节点 / 列全部(调试、体检用) |
| Reddot.addStyle(name, path) | 注册样式(路径相对 resources,不带扩展名) |
| Reddot.bind(path, owner, align?, offset?, style?) | 挂红点;九宫格对齐 + 偏移 |
| Reddot.unbind(path) | 解绑(一般不用手调:owner 销毁会自动退) |
文件
| 文件 | 说明 |
| --- | --- |
| ReddotCore.ts | 纯逻辑(不 import cc,可在 Node 里单测) |
| Reddot.ts | 表现层:addStyle / bind / 九宫格对齐 / owner 销毁自动退绑 |
| ReddotModule.ts | 模块 + Model:@Persistent readPaths,已读持久化 |
两个坑(都实测踩过)
- 工作区里别按包名引框架/公共模块 —— 会加载第二份实例:
A Class already exists with the same __cid__或红点报"没有这个节点(已有的:空)" ✓ (开发工作区里一律用相对路径,构建期会自动改写成包名 ✓) - 不要把工程建在框架仓库内部 —— 仓库根有一个
@ccgf/framework的链接, 工程在里面会同时解析到两份框架 ✓
