import { Button, Canvas, Component, EventHandler, EventTouch, Node, SpriteFrame, _decorator, warn } from "cc"; // import GlobalDC from "../common/data.global.center"; const { ccclass, property } = _decorator; @ccclass export class UI extends Component { /** 获取节点深度 */ public static getDepth(node: Node) { let d: number; if (node.getComponent(Canvas)) d = 0; else d = this.getDepth(node.parent) + 1; return d; } /** 节点层级深度 */ protected get depth() { return UI.getDepth(this.node); } /** 组件名称 */ get comp_name() { let reg = new RegExp('(?<=<)(?[\\w, \\W]+)(?=>)', 'g'); return reg.exec(this.name).groups.comp_name; } /** 给按钮绑定点击事件 */ private __ButtonBindCall() { this.__handle = mtec.cc.creatEventHandle({ target: this.node, component: this.comp_name, handler: '__ClickButton', }); this.node.getComponentsInChildren(Button) .filter(btn => { let pass = false; // 如果btn的事件列表是空的,则直接无脑把自己的中继事件放进去 if (btn.clickEvents.length === 0) pass = true; else { // 分别收集手动绑定事件和自动绑定事件 let [hand_event, auto_event] = [[], []] as EventHandler[][]; btn.clickEvents.forEach(hdl => { if (hdl.handler === '__ClickButton') auto_event.push(hdl); else hand_event.push(hdl); }); // 如果脚本中初始化了按钮事件,并且按钮事件列表中没有其它初始化事件,则直接添加 if (auto_event.length === 0 && this._click_event_[btn.node.name]) pass = true; // 如果存在其它初始化事件,则以组件的深度优先(即距离按钮最近的组件为准)覆盖,相同深度则以当前为准覆盖 else if (auto_event.length > 0) { let power = this.depth; if (this._click_event_[btn.node.name]) power += 10000; let el = auto_event.map(h => { let comp = h.target.getComponent(UI); let p = comp.depth; if (comp._click_event_[btn.node.name]) p += 10000; return { h, p }; }).sort((a, b) => a.p - b.p).pop(); if (el.p <= power) pass = true; else auto_event.splice(auto_event.indexOf(el.h), 1); auto_event.forEach(h => btn.clickEvents.splice(btn.clickEvents.indexOf(h), 1)); } } return pass; }).forEach(btn => { btn.clickEvents.push(this.__handle); this.__btn_map__.set(btn.node.name, btn); }); } /** 按钮点击事件中继 */ protected __ClickButton(event: EventTouch) { let node = event.currentTarget as Node; let btn = node.getComponent(Button); let call = Reflect.get(this._click_event_, node.name); if (node.name in this._click_event_) { Reflect.apply(call, this, [btn]); // 发送点击事件,只对初始化的按钮发送事件 // GlobalDC.Trigger.CLICK = { // component: this.comp_name, // button: node.name // }; } else this.ClickBtn(btn); } /** 没有被初始化的按钮 */ protected ClickBtn(btn: Button) { btn.interactable warn(`<${this.comp_name}> 按钮[${btn.node.name}]未被初始化`); } /** ui交互控制 */ protected interactable(able: boolean) { this.__btn_map__.forEach(btn => btn.interactable = able); } /** 初始化组件基本逻辑 */ private __init() { if (!this._click_event_.__common) this._click_event_.__common = (() => { }).bind(this); this.__ButtonBindCall(); if (this.sframe.length > 0) { this.sframe.forEach(frame => this.smap.set(frame.name, frame)); this.sframe = undefined; } if (this.initAfterOnLoad) this.initAfterOnLoad(); } /** 组件事件对象 */ protected _click_event_: { [name: string]: (this: UI, button: Button) => void } = {}; /** 组件上的按钮通用回调 */ protected __handle: EventHandler = null; protected __btn_map__: Map = new Map(); /** ui常用贴图映射 */ protected smap: Map = new Map(); /** 在加载后的一些自定义初始化 */ protected initAfterOnLoad(): void { }; @property([SpriteFrame]) /** ui常用贴图 */ private sframe: SpriteFrame[] = []; protected onLoad() { this.__init(); } }