import { Node, Component, Button } from 'cc'; /** * UI基类 * 职责: * - 定义UI的基础接口和生命周期 * - 管理UI根节点 * - 提供显示/隐藏控制 * * 所有UI必须继承此类并实现onGetUrl方法 */ export abstract class UIBase { /** UI根节点 */ protected _node: Node | null = null; /** UI是否已加载 */ protected _isLoaded: boolean = false; /** UI是否显示中 */ protected _isShowing: boolean = false; /** * 获取UI资源路径 (必须重载) * @returns UI预制体路径 * @example * onGetUrl(): string { * return 'UI/Login/UILogin'; * } */ abstract onGetUrl(): string; /** * UI开始时调用 (可选重载) * 在UI预制体加载完成后调用 * 可以在此方法中初始化UI数据、绑定事件等 * @param params 传入的参数 * @example * onStart(params?: any): void { * console.log('UI初始化', params); * // 绑定按钮事件 * this.bindEvents(); * } */ onStart?(params?: any): void | Promise; /** * UI结束时调用 (可选重载) * 在UI被卸载前调用 * 可以在此方法中清理资源、解绑事件等 * @example * onEnd(): void { * console.log('UI清理'); * // 解绑按钮事件 * this.unbindEvents(); * } */ onEnd?(): void; /** * UI更新 (可选重载) * 在每帧调用(仅当UI显示时) * @param dt 距离上一帧的时间(秒) * @example * onUpdate(dt: number): void { * // 更新倒计时 * this.updateTimer(dt); * } */ onUpdate?(dt: number): void; /** * 设置UI根节点 * 由UIMgr在加载完成后调用 * @param node UI根节点 */ setNode(node: Node): void { this._node = node; this._isLoaded = true; } /** * 获取UI根节点 * @returns UI根节点,如果未加载则返回null */ getNode(): Node | null { return this._node; } /** * 显示UI */ show(): void { if (this._node) { this._node.active = true; this._isShowing = true; } } /** * 隐藏UI */ hide(): void { if (this._node) { this._node.active = false; this._isShowing = false; } } /** * 检查UI是否显示中 * @returns true表示正在显示,false表示已隐藏 */ isShowing(): boolean { return this._isShowing; } /** * 检查UI是否已加载 * @returns true表示已加载,false表示未加载 */ isLoaded(): boolean { return this._isLoaded; } /** * 查找子节点并获取组件 * @param path 节点路径,支持多层级查找(如: 'mid/input_account') * @param componentType 组件类型 * @returns 组件实例,未找到则返回null * @example * const editBox = this.GetChild('mid/input_account', EditBox); * const button = this.GetChild('btn_login', Button); */ protected GetChild(path: string, componentType: { new(): T }): T | null { if (!this._node) { console.error('[UIBase] GetChild失败: UI根节点不存在'); return null; } const childNode = this._node.getChildByPath(path); if (!childNode) { console.error(`[UIBase] GetChild失败: 未找到节点 ${path}`); return null; } const component = childNode.getComponent(componentType); if (!component) { console.error(`[UIBase] GetChild失败: 节点 ${path} 未挂载 ${componentType.name} 组件`); return null; } return component; } /** * 设置按钮点击事件 * @param button Button组件或包含Button组件的Node * @param callback 点击回调函数 * @param target 回调函数的this指向 * @example * const btn = this.GetChild('btn_login', Button); * this.SetClick(btn, this.onLoginClick, this); */ protected SetClick(button: Button | Node | null, callback: () => void, target?: any): void { if (!button) { console.error('[UIBase] SetClick失败: button为null'); return; } let targetNode: Node | null = null; // 判断是Button组件还是Node if (button instanceof Button) { targetNode = button.node; } else if (button instanceof Node) { targetNode = button; } if (!targetNode) { console.error('[UIBase] SetClick失败: 无法获取目标节点'); return; } // 绑定点击事件 targetNode.on(Node.EventType.TOUCH_END, callback, target); } }