import { Component } from "cc"; import { Logger } from "./Logger"; interface AutoBindOptions { type?: any; // 组件类型(如 Label) tooltip?: string; [key: string]: any; } const AutoBindMap = new WeakMap(); /** * 自动绑定与变量同名的子节点。 * 装饰器不传参数(组件)则绑定节点,传了组件则绑定节点上的组件。 * 如果传了组件,则传入的组件一定要和变量类型一致,否则绑定会失败。 * 记得在组件的onLoad函数调用initAutoBindings(this) 事例: "@autoBind不传" 绑定是节点 ”@autoBind(Label)“ 绑定的是Label “@autoBind({type: Label,tooltip: "文本"})” 绑定的是Label */ export function autoBind(target: any, propertyKey: string): void; export function autoBind(componentType: { new(): T }): (target: any, propertyKey: string) => void; export function autoBind(options: AutoBindOptions): (target: any, propertyKey: string) => void; export function autoBind( componentTypeOrTarget?: { new(): T } | AutoBindOptions | any, propertyKey?: string ) { if (propertyKey !== undefined) { //情况1:@autoBind 不传参 const target = componentTypeOrTarget; if (!AutoBindMap.has(target)) { AutoBindMap.set(target, {}); } AutoBindMap.get(target)![propertyKey] = {}; return; } //情况2:@autoBind(Label) 或 @autoBind({type: Label}) return function (target: any, propertyKey: string) { if (!AutoBindMap.has(target)) { AutoBindMap.set(target, {}); } const options: AutoBindOptions = typeof componentTypeOrTarget === "function" ? { type: componentTypeOrTarget } : componentTypeOrTarget; AutoBindMap.get(target)![propertyKey] = options; }; } /** * 获取变量的类型 */ function getComponentType(instance: any, propertyKey: string, binding: AutoBindOptions): any { //1. 优先用 @autoBind 指定的类型 if(binding.type) { return binding.type; } //2. 尝试从变量默认值推断(如 `= null! as Label`) const defaultValue = instance[propertyKey]; if (defaultValue !== null && defaultValue !== undefined) { return defaultValue.constructor; } //3. 尝试从类型断言推断(如 `= null! as Label`) //注意:这种方式在运行时无法获取类型信息,需要用户确保正确使用 // 这里我们无法直接获取类型断言信息,只能依赖用户正确设置默认值 //4. 如果仍然没有,返回 null(绑定节点而非组件) return null; } /** * 在onLoad中调用这个函数然后才会自动绑定。initAutoBindings(this)。 */ export function initAutoBindings(instance: any) { const bindings = AutoBindMap.get(Object.getPrototypeOf(instance)); if (!bindings) return; const nameMap = new Map(); buildNodeNameMap(instance.node, nameMap); for (const propertyKey in bindings) { const binding = bindings[propertyKey]; const node = nameMap.get(propertyKey); if (!node) { //Logger.warn(`[AutoBind] 节点未找到: ${propertyKey}`); continue; } const componentType = getComponentType(instance, propertyKey, binding); if (componentType && !(node instanceof componentType)) { // 关键修改:排除 Node 类型 instance[propertyKey] = node.getComponent(componentType); //Logger.log(`[AutoBind] 绑定组件 ${propertyKey}:`, componentType.name); } else { instance[propertyKey] = node; // 直接绑定节点 // Logger.log(`[AutoBind] 绑定节点 ${propertyKey}`); } } } function buildNodeNameMap(node: any, nameMap: Map) { nameMap.set(node.name, node); for (const child of node.children) { buildNodeNameMap(child, nameMap); } }