refactor(ui): 重构英雄信息面板组件,提取通用逻辑

- 将 HInfoComp 重构为独立组件,封装标签查找与数据绑定逻辑
- 在 MissionCardComp 中使用 HInfoComp 替代直接操作 Label 组件
- 移除冗余的 findNodeByPath 和 resolvePanelLabel 方法
- 通过 isModelAlive 方法统一检查模型有效性
This commit is contained in:
panw
2026-03-25 17:26:51 +08:00
parent de90dadaed
commit 80bf8efc30
3 changed files with 66 additions and 36 deletions

View File

@@ -8,6 +8,7 @@ import { smc } from "../common/SingletonModuleComp";
import { CardComp } from "./CardComp";
import { oops } from "db://oops-framework/core/Oops";
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
import { HInfoComp } from "./HInfoComp";
const { ccclass, property } = _decorator;
@@ -54,8 +55,7 @@ export class MissionCardComp extends CCComp {
private heroInfoItems: Map<number, {
node: Node,
model: HeroAttrsComp,
apLabel: Label | null,
hpLabel: Label | null
comp: HInfoComp
}> = new Map();
onLoad() {
/** 绑定事件 -> 缓存子控制器 -> 初始化UI状态 */
@@ -372,18 +372,24 @@ export class MissionCardComp extends CCComp {
const current = this.heroInfoItems.get(eid);
if (current) {
current.model = model;
current.comp.bindData(eid, model);
this.updateHeroInfoPanel(current);
return;
}
const node = instantiate(this.hero_info_prefab);
node.parent = this.hero_info_node;
node.active = true;
const comp = node.getComponent(HInfoComp);
if (!comp) {
node.destroy();
return;
}
const item = {
node,
model,
apLabel: this.resolvePanelLabel(node, [["ap", "val"]]),
hpLabel: this.resolvePanelLabel(node, [["hp", "val"]])
comp
};
comp.bindData(eid, model);
this.heroInfoItems.set(eid, item);
this.relayoutHeroInfoPanels();
this.updateHeroInfoPanel(item);
@@ -396,8 +402,7 @@ export class MissionCardComp extends CCComp {
removeKeys.push(eid);
return;
}
const ent = (item.model as any)?.ent;
if (!ent) {
if (!item.comp.isModelAlive()) {
if (item.node.isValid) item.node.destroy();
removeKeys.push(eid);
return;
@@ -415,11 +420,9 @@ export class MissionCardComp extends CCComp {
private updateHeroInfoPanel(item: {
node: Node,
model: HeroAttrsComp,
apLabel: Label | null,
hpLabel: Label | null
comp: HInfoComp
}) {
if (item.apLabel) item.apLabel.string = `${Math.max(0, Math.floor(item.model.ap ?? 0))}`;
if (item.hpLabel) item.hpLabel.string = `${Math.max(0, Math.floor(item.model.hp_max ?? 0))}`;
item.comp.refresh();
}
private relayoutHeroInfoPanels() {
@@ -448,25 +451,6 @@ export class MissionCardComp extends CCComp {
this.heroInfoSyncTimer = 0;
}
private resolvePanelLabel(root: Node, paths: string[][]): Label | null {
for (let i = 0; i < paths.length; i++) {
const node = this.findNodeByPath(root, paths[i]);
if (!node) continue;
const label = node.getComponent(Label) || node.getComponentInChildren(Label);
if (label) return label;
}
return null;
}
private findNodeByPath(root: Node, path: string[]): Node | null {
let current: Node | null = root;
for (let i = 0; i < path.length; i++) {
current = current?.getChildByName(path[i]) ?? null;
if (!current) return null;
}
return current;
}
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
reset() {
this.clearHeroInfoPanels();