123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- import { Component } from "cc";
- import { Logger } from "./Logger";
- interface AutoBindOptions {
- type?: any; // 组件类型(如 Label)
- tooltip?: string;
- [key: string]: any;
- }
- const AutoBindMap = new WeakMap<any, { [key: string]: AutoBindOptions }>();
- /**
- * 自动绑定与变量同名的子节点。
- * 装饰器不传参数(组件)则绑定节点,传了组件则绑定节点上的组件。
- * 如果传了组件,则传入的组件一定要和变量类型一致,否则绑定会失败。
- * 记得在组件的onLoad函数调用initAutoBindings(this)
- 事例:
- "@autoBind不传" 绑定是节点
- ”@autoBind(Label)“ 绑定的是Label
- “@autoBind({type: Label,tooltip: "文本"})” 绑定的是Label
- */
- export function autoBind(target: any, propertyKey: string): void;
- export function autoBind<T extends Component>(componentType: { new(): T }): (target: any, propertyKey: string) => void;
- export function autoBind<T extends Component>(options: AutoBindOptions): (target: any, propertyKey: string) => void;
- export function autoBind<T extends Component>(
- 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<string, any>();
- 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<string, any>) {
- nameMap.set(node.name, node);
- for (const child of node.children) {
- buildNodeNameMap(child, nameMap);
- }
- }
|