188 lines
4.9 KiB
TypeScript
188 lines
4.9 KiB
TypeScript
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<void>;
|
|
|
|
/**
|
|
* 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<T extends Component>(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);
|
|
}
|
|
}
|