前端规范新增两条:常量化 id(含群组/Spine)+ 显隐走 showXxx/hideXxx

- 强化「常量集中、禁硬编码」(05 §4 / README 红线速查 / 05 §11 审查表):
  明确 UI 代码禁止任何硬编码 id/裸值,覆盖精灵/群组/图层/图片/声音/Spine
  等全部 id 与资源,一律用对应常量;补 Spine→Spine 动作配置映射。
- 新增「显隐走 showXxx/hideXxx 接口」(02 §3 范式第4条 / 05 §9 红线 /
  README 红线速查 / 05 §11 审查表):UI 组件及零件的精灵/群组显隐必须由组件
  暴露的 showXxx/hideXxx 控制,禁止别处直接用其精灵/群组 id 去 show/hide,
  否则绕过组件、状态分散、重连刷新不一致(与 UI 组件专职一脉相承)。
- 显隐条同进 README 红线速查(@import 常驻层);未改任何小节标题,
  链接/锚点审计通过。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-07 12:21:11 +08:00
co-authored by Claude Opus 4.8
parent b59a6f9ca5
commit 46f65de7ed
3 changed files with 10 additions and 6 deletions
@@ -128,6 +128,7 @@ MyView.init = function (config) {
1. **数据集中在 `this.data`**:组件及其下每个「零件 UI」的自有数据全部收拢到 `this.data.*`,**不散落**在实例其他字段或全局;界面能否重建只取决于 `this.data`。 1. **数据集中在 `this.data`**:组件及其下每个「零件 UI」的自有数据全部收拢到 `this.data.*`,**不散落**在实例其他字段或全局;界面能否重建只取决于 `this.data`。
2. **每个 UI 都有 `setXxx` / `refreshXxx` 成对方法**:`setXxx(...)` **只写数据**到 `this.data`、不碰精灵;`refreshXxx()` **只据 `this.data` 画界面**、不改数据。两者职责单一、互不越界。 2. **每个 UI 都有 `setXxx` / `refreshXxx` 成对方法**:`setXxx(...)` **只写数据**到 `this.data`、不碰精灵;`refreshXxx()` **只据 `this.data` 画界面**、不改数据。两者职责单一、互不越界。
3. **组件有一个总 `refresh()`**:顺序调用其下所有零件的 `refreshXxx()`,据 `this.data` 完整重画。**任何时候调 `refresh()` 都能无歧义重建正确界面**(断线重连、切 app 回来、网页刷新都复用它,不另写一套渲染)。 3. **组件有一个总 `refresh()`**:顺序调用其下所有零件的 `refreshXxx()`,据 `this.data` 完整重画。**任何时候调 `refresh()` 都能无歧义重建正确界面**(断线重连、切 app 回来、网页刷新都复用它,不另写一套渲染)。
4. **显隐走 `showXxx` / `hideXxx` 接口**:组件(及每个「零件 UI」)的精灵/群组显隐,由组件自身暴露的 `showXxx()`/`hideXxx()` 语义方法控制;外部**只调这些接口**,**禁止**在别处直接用该组件/零件的精灵 ID、群组 ID 去 `SpriteManager.show/hide`(或 `showGroup/hideGroup`)——那样绕过组件、状态分散,重连/刷新时不一致。
```js ```js
GameView.setScore = function (v) { this.data.score = v; }; // 只写数据 GameView.setScore = function (v) { this.data.score = v; }; // 只写数据
@@ -49,12 +49,13 @@
- **精灵只走 `SpriteManager`**:UI 代码禁止直接调 `GameABCUtils`/引擎原生 API。 - **精灵只走 `SpriteManager`**:UI 代码禁止直接调 `GameABCUtils`/引擎原生 API。
- **ID 守范围**:精灵 1001–3000、群组 ≥201、普通图层 101–200、弹窗图层 301–400(另有 501–600、701+ 备用段);框架保留 1–1000 及 3001+(精灵)等交替段,不可占用;ID 必须与编辑器一致,不编造。 - **ID 守范围**:精灵 1001–3000、群组 ≥201、普通图层 101–200、弹窗图层 301–400(另有 501–600、701+ 备用段);框架保留 1–1000 及 3001+(精灵)等交替段,不可占用;ID 必须与编辑器一致,不编造。
- **检查返回值**:`SpriteManager.*` 返回 `false` 即 ID/范围有误,及时暴露。 - **检查返回值**:`SpriteManager.*` 返回 `false` 即 ID/范围有误,及时暴露。
- **常量集中、禁硬编码**:精灵 ID / 图片资源 ID / 坐标尺寸 / 动画时长帧数 / 音效 ID / 事件名,一律定义在对应常量文件,业务代码只引用: - **常量集中、禁硬编码**:UI 代码**禁止出现任何硬编码的 id 或裸值**——精灵 ID / 群组 ID / 图层 ID / 图片资源 ID / 声音 ID / Spine 资源 / 坐标尺寸 / 动画时长帧数 / 事件名,一律定义在对应常量文件,业务代码**只引用常量**:
- 精灵结构 → 精灵结构常量(主界面/弹窗分文件) - 精灵结构(含群组 / 图层 ID)→ 精灵结构常量(主界面/弹窗分文件)
- 图片资源 → 图片资源常量 - 图片资源 → 图片资源常量
- 布局坐标 → 布局常量 - 布局坐标 → 布局常量
- 动画参数 → 动画配置 - 动画参数 → 动画配置
- 音效 ID → 音效资源常量 - 音效 / 语音 ID → 音效资源常量
- Spine 资源 → Spine 动作配置
- 事件名 → `EventBus.Events`(专属在子游戏事件常量文件) - 事件名 → `EventBus.Events`(专属在子游戏事件常量文件)
- 整合入口 → 精灵常量整合入口(**最后加载**) - 整合入口 → 精灵常量整合入口(**最后加载**)
@@ -100,6 +101,7 @@
- 一个职能只在一个模块实现,其他模块**调用而非重造**:渲染找 `SpriteManager`、动画找 `AnimationManager`(及游戏动画封装)、音频找游戏音频管理、Spine 找 `SpineMgr`(及 Spine 回调分发)、发包找语义化发包封装、收包分发找收包分发器。 - 一个职能只在一个模块实现,其他模块**调用而非重造**:渲染找 `SpriteManager`、动画找 `AnimationManager`(及游戏动画封装)、音频找游戏音频管理、Spine 找 `SpineMgr`(及 Spine 回调分发)、发包找语义化发包封装、收包分发找收包分发器。
- **UI 组件专职自己的界面**:每个界面的数据与渲染**只由其对应 UI 组件实现**,组件对外提供 `setXxx`/`refreshXxx` 与语义化公开方法。别的模块(controllers/managers/其他组件)要改动或刷新某界面,一律**调用该组件的公开接口**,**禁止**在别处重复实现重叠或类似的界面数据/渲染逻辑(否则同一界面出现多份状态源,重连/刷新时必然不一致)。 - **UI 组件专职自己的界面**:每个界面的数据与渲染**只由其对应 UI 组件实现**,组件对外提供 `setXxx`/`refreshXxx` 与语义化公开方法。别的模块(controllers/managers/其他组件)要改动或刷新某界面,一律**调用该组件的公开接口**,**禁止**在别处重复实现重叠或类似的界面数据/渲染逻辑(否则同一界面出现多份状态源,重连/刷新时必然不一致)。
- **显隐走 `showXxx`/`hideXxx` 接口**:UI 组件及其「零件 UI」的精灵/群组显隐,必须由组件自身暴露的 `showXxx()`/`hideXxx()` 语义接口控制;**禁止**在别处直接用该组件/零件的精灵 ID、群组 ID 去 `SpriteManager.show/hide`(或 `showGroup/hideGroup`)控制其显隐——绕过组件即状态分散,重连/刷新时必然不一致。
- 写代码前先问“这段属于谁的职责”,属于别人就调用它,不在本模块复制一份近似实现。 - 写代码前先问“这段属于谁的职责”,属于别人就调用它,不在本模块复制一份近似实现。
--- ---
@@ -120,14 +122,14 @@
| 语言 | 严格 ES5;新文件插对加载顺序 | | 语言 | 严格 ES5;新文件插对加载顺序 |
| 框架中立 | 框架无玩法逻辑/专属常量;专属内容归子游戏 | | 框架中立 | 框架无玩法逻辑/专属常量;专属内容归子游戏 |
| 渲染 | 只走 `SpriteManager`;ID 守范围、不编造;查返回值 | | 渲染 | 只走 `SpriteManager`;ID 守范围、不编造;查返回值 |
| 常量 | 精灵/资源/坐标/动画/音效/事件全集中,禁硬编码裸值 | | 常量 | 精灵/群组/图层/图片/声音/Spine/坐标/动画/事件全进常量;UI 代码禁硬编码 id 与裸值 |
| 组件 | 继承 `BaseComponent`;事件 `addEventListener`;`destroy` 清动态精灵/定时器 | | 组件 | 继承 `BaseComponent`;事件 `addEventListener`;`destroy` 清动态精灵/定时器 |
| 数据 | 服务端权威(核心运算/裁定在服务端);组件自有数据集中 `this.data`;每个 UI/零件有 set/refresh 对、组件有总 `refresh` | | 数据 | 服务端权威(核心运算/裁定在服务端);组件自有数据集中 `this.data`;每个 UI/零件有 set/refresh 对、组件有总 `refresh` |
| 节奏 | 先写数据后表现;动画回调只刷界面、**不写核心数据**;重画可随时据数据还原界面 | | 节奏 | 先写数据后表现;动画回调只刷界面、**不写核心数据**;重画可随时据数据还原界面 |
| 成败 | 只认 `data.success`,禁 `status` 兜底 | | 成败 | 只认 `data.success`,禁 `status` 兜底 |
| 收发包 | 发走语义化发包封装、收走收包分发器;业务不进 `Game_Modify` | | 收发包 | 发走语义化发包封装、收走收包分发器;业务不进 `Game_Modify` |
| 职责 | 一职能一模块,调用不重造 | | 职责 | 一职能一模块,调用不重造 |
| UI 职责 | 每个界面的数据与渲染只在其 UI 组件实现;别处调组件接口,不重叠/重造 | | UI 职责 | 每个界面的数据/渲染/显隐只在其 UI 组件实现;别处调组件接口(含 `showXxx`/`hideXxx`),不重叠重造、不直接用其精灵/群组 id 控显隐 |
| 重连 | 断线重连 + 硬刷新都要处理;本质=恢复数据→各组件 set-refresh;复用同一重画路径 | | 重连 | 断线重连 + 硬刷新都要处理;本质=恢复数据→各组件 set-refresh;复用同一重画路径 |
--- ---
+2 -1
View File
@@ -60,11 +60,12 @@ BaseComponent / UIManager(ui,组件化与场景) ← gameabc-framework(
- **严格 ES5**:用 `var`/`function`/`Object.create`,禁 `let`/`const`/箭头/模板串/`class`。 - **严格 ES5**:用 `var`/`function`/`Object.create`,禁 `let`/`const`/箭头/模板串/`class`。
- **框架游戏中立**:`gameabc-framework/` 内**不得**出现任何具体玩法逻辑或专属常量;玩法专属的事件/资源/配置一律定义在子游戏侧(如玩法事件在子游戏的事件常量文件里追加到 `EventBus.Events`)。 - **框架游戏中立**:`gameabc-framework/` 内**不得**出现任何具体玩法逻辑或专属常量;玩法专属的事件/资源/配置一律定义在子游戏侧(如玩法事件在子游戏的事件常量文件里追加到 `EventBus.Events`)。
- **精灵只走 SpriteManager**:UI 代码**禁止**直接调 `GameABCUtils` 或引擎原生 API;ID 必须落在规定范围(精灵 1001–3000、群组 ≥201、图层 101–200/弹窗 301–400,另有 501–600、701+ 备用段,框架保留 1–1000 及 3001+ 等交替段)。 - **精灵只走 SpriteManager**:UI 代码**禁止**直接调 `GameABCUtils` 或引擎原生 API;ID 必须落在规定范围(精灵 1001–3000、群组 ≥201、图层 101–200/弹窗 301–400,另有 501–600、701+ 备用段,框架保留 1–1000 及 3001+ 等交替段)。
- **常量集中、禁硬编码**:精灵 ID/图片资源 ID/坐标尺寸/动画时长/音效 ID 一律定义在对应常量文件,业务代码引用,**不内联裸值**。 - **常量集中、禁硬编码**:UI 代码**禁止任何硬编码 id / 裸值**——精灵 ID / 群组 ID / 图层 ID / 图片资源 ID / 声音 ID / Spine 资源 / 坐标尺寸 / 动画时长 / 事件名 一律定义在对应常量文件、只引用常量。
- **服务端权威、前端只展示**:核心运算与胜负裁定以服务端为准、数据以服务端为权威;前端只做界面展示与玩家交互,本地数据仅为渲染副本,不做权威计算。 - **服务端权威、前端只展示**:核心运算与胜负裁定以服务端为准、数据以服务端为权威;前端只做界面展示与玩家交互,本地数据仅为渲染副本,不做权威计算。
- **组件走 BaseComponent**:UI 组件继承 `BaseComponent`,事件用 `this.addEventListener` 注册(`destroy()` 自动清理,防泄漏);动态精灵/定时器在 `onDestroy` 清理。 - **组件走 BaseComponent**:UI 组件继承 `BaseComponent`,事件用 `this.addEventListener` 注册(`destroy()` 自动清理,防泄漏);动态精灵/定时器在 `onDestroy` 清理。
- **组件数据自持 + set-refresh**:组件自有数据集中 `this.data`;每个 UI/零件有 `setXxx`(只写数据)/`refreshXxx`(只据数据画)对,组件有总 `refresh()` 可据数据重建界面。 - **组件数据自持 + set-refresh**:组件自有数据集中 `this.data`;每个 UI/零件有 `setXxx`(只写数据)/`refreshXxx`(只据数据画)对,组件有总 `refresh()` 可据数据重建界面。
- **UI 组件专职自己的界面**:每个界面的数据与渲染只由其对应 UI 组件实现;别的模块要改/刷该界面一律**调该组件的公开接口**(`setXxx`/`refreshXxx`/语义方法),**禁止**在别处重复实现重叠或类似的界面数据/渲染逻辑。 - **UI 组件专职自己的界面**:每个界面的数据与渲染只由其对应 UI 组件实现;别的模块要改/刷该界面一律**调该组件的公开接口**(`setXxx`/`refreshXxx`/语义方法),**禁止**在别处重复实现重叠或类似的界面数据/渲染逻辑。
- **显隐走 `showXxx`/`hideXxx`**:UI 组件/零件的精灵、群组显隐必须由组件暴露的 `showXxx`/`hideXxx` 接口控制;**禁止**别处直接用其精灵 ID/群组 ID 去 `SpriteManager.show/hide` 控显隐。
- **数据优先、表现延后**:收到推送先 `setXxx` 写数据、再播动画;动画的开始/结束/出错回调里**只刷界面、不写核心数据**。即使动画缺失/卡住/出错,数据、逻辑、界面仍正确、互不影响。 - **数据优先、表现延后**:收到推送先 `setXxx` 写数据、再播动画;动画的开始/结束/出错回调里**只刷界面、不写核心数据**。即使动画缺失/卡住/出错,数据、逻辑、界面仍正确、互不影响。
- **重连即重画(断线重连 + 硬刷新都要处理)**:重连/页面重载的本质是**恢复数据 → 调各 UI 组件 set-refresh 恢复数据与界面状态**,复用同一条重画路径,不为重连单写一套渲染(详见 04 §3.3、05 §6)。 - **重连即重画(断线重连 + 硬刷新都要处理)**:重连/页面重载的本质是**恢复数据 → 调各 UI 组件 set-refresh 恢复数据与界面状态**,复用同一条重画路径,不为重连单写一套渲染(详见 04 §3.3、05 §6)。
- **成败只认 `data.success`**:前端一律 `if (!data.success)` 判成败,**不**用 `status`/`code`,**不**写 `status` 兼容兜底。 - **成败只认 `data.success`**:前端一律 `if (!data.success)` 判成败,**不**用 `status`/`code`,**不**写 `status` 兼容兜底。