详解angular中的makeDecorator
首先说下作用:这个函数用来创建Decorator,如
Injectable
export const Injectable: InjectableDecorator = makeDecorator('Injectable', undefined, undefined, undefined,(type: Type<any>, meta: Injectable) => R3_COMPILE_INJECTABLE(type, meta)
);
复制代码 Directive
export const Directive: DirectiveDecorator = makeDecorator('Directive', (dir: Directive = {}) => dir, undefined, undefined,(type: Type<any>, meta: Directive
) => R3_COMPILE_DIRECTIVE(type, meta));
复制代码 Component
export const Component: ComponentDecorator = makeDecorator('Component', (c: Component = {}) => ({changeDetection:ChangeDetectionStrategy.Default, ...c}),Directive, undefined, (type: Type<any>, meta: Component) => R3_COMPILE_COMPONENT(type, meta)
);
复制代码 Pipe
export const Pipe: PipeDecorator = makeDecorator('Pipe', (p: Pipe) => ({pure: true, ...p}), undefined, undefined,(type: Type<any>, meta: Pipe) => R3_COMPILE_PIPE(type, meta)
);
复制代码 NgModule
export const NgModule: NgModuleDecorator = makeDecorator('NgModule', (ngModule: NgModule) => ngModule, undefined, undefined,(type: Type<any>, meta: NgModule) => R3_COMPILE_NGMODULE(type, meta)
);
复制代码 参数说明
- 第一个参数: name, 装饰器的名字
- 第二个参数: props, 补充函数,可用于默认值设置
- 第三个参数:parentClass,父级对象
- 第四个参数:回调,参数是装饰器宿主对象
- 第五个参数:回调,参数是装饰器宿主对象和装饰器参数
执行结果
- 将装饰器处理的结果保存在宿主对象的__annotations__属相上,以供compiler编译器识别!
export const ANNOTATIONS = '__annotations__';
export function makeDecorator(name: string,props?: (...args: any[]) => any,parentClass?: any,additionalProcessing?: (type: Type) => void,typeFn?: (type: Type, ...args: any[]) => void
): {new(...args: any[]): any;(...args: any[]): any;(...args: any[]): (cls: any) => any;} {const metaCtor = makeMetadataCtor(props);function DecoratorFactory(...args: any[]): (cls: Type) => any {if (this instanceof DecoratorFactory) {metaCtor.call(this, ...args);return this;}const annotationInstance = new (DecoratorFactory as any)(...args);return function TypeDecorator(cls: Type) {// 触发typeFn回调if (typeFn) typeFn(cls, ...args);const annotations = cls.hasOwnProperty(ANNOTATIONS) ?(cls as any)[ANNOTATIONS] :Object.defineProperty(cls, ANNOTATIONS, { value: [] })[ANNOTATIONS];annotations.push(annotationInstance);// 触发additionalProcessing回调if (additionalProcessing) additionalProcessing(cls);return cls;};}if (parentClass) {DecoratorFactory.prototype = Object.create(parentClass.prototype);}DecoratorFactory.prototype.ngMetadataName = name;(DecoratorFactory as any).annotationCls = DecoratorFactory;return DecoratorFactory as any;
}function makeMetadataCtor(props?: (...args: any[]) => any): any {// 返回一个函数return function ctor(...args: any[]) {if (props) {const values = props(...args);for (const propName in values) {this[propName] = values[propName];}}};
}
复制代码 不过遗憾的是,angular并不支持自定义装饰器。
const testDecorator = makeDecorator('testDecorator');
@testDecorator()
export class TestDecorator { }
复制代码 运行ng build通过ng serve通过,运行ng build --prod时报错
ERROR in main.ts(7,23): Error during template compile of 'TestDecorator'Function calls are not supported in decorators but 'ɵmakeDecorator' was called.
复制代码 报错位置
- @angular/compiler-static_reflector.ts>formatMetadataError
- @angular/compiler-static_reflector.ts>expandedMessage
case FUNCTION_CALL_NOT_SUPPORTED:if (context && context.name) {return `Function calls are not supported in decorators but '${context.name}' was called`;}return 'Function calls are not supported in decorators';
复制代码 触发错误位置
- @angular/compiler-static_reflector.ts> simplify
因为conversionMap中没有注册
case 'call':// Determine if the function is a built-in conversionstaticSymbol = simplifyInContext(context, expression['expression'], depth + 1, /* references */ 0);if (staticSymbol instanceof StaticSymbol) {if (staticSymbol === self.injectionToken || staticSymbol === self.opaqueToken) {return context;}const argExpressions: any[] = expression['arguments'] || [];// 因为conversionMap中没有注册let converter = self.conversionMap.get(staticSymbol);if (converter) {const args = argExpressions.map(arg => simplifyNested(context, arg)).map(arg => shouldIgnore(arg) ? undefined : arg);return converter(context, args);} else {// Determine if the function is one we can simplify.const targetFunction = resolveReferenceValue(staticSymbol);return simplifyCall(staticSymbol,targetFunction,argExpressions,expression['expression']);}}return IGNORE;
复制代码 那看一下那里面都有什么吧!
private initializeConversionMap(): void {this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Injectable'), createInjectable);this.injectionToken = this.findDeclaration(ANGULAR_CORE, 'InjectionToken');this.opaqueToken = this.findDeclaration(ANGULAR_CORE, 'OpaqueToken');this.ROUTES = this.tryFindDeclaration(ANGULAR_ROUTER, 'ROUTES');this.ANALYZE_FOR_ENTRY_COMPONENTS =this.findDeclaration(ANGULAR_CORE, 'ANALYZE_FOR_ENTRY_COMPONENTS');this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Host'), createHost);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Self'), createSelf);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'SkipSelf'), createSkipSelf);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Inject'), createInject);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Optional'), createOptional);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Attribute'), createAttribute);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ContentChild'), createContentChild);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ContentChildren'), createContentChildren);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ViewChild'), createViewChild);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'ViewChildren'), createViewChildren);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Input'), createInput);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Output'), createOutput);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Pipe'), createPipe);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'HostBinding'), createHostBinding);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'HostListener'), createHostListener);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Directive'), createDirective);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Component'), createComponent);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'NgModule'), createNgModule);// Note: Some metadata classes can be used directly with Provider.deps.this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Host'), createHost);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Self'), createSelf);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'SkipSelf'), createSkipSelf);this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Optional'), createOptional);}
复制代码 果不其然仅支持自家的装饰器
Injectable,InjectionToken,OpaqueToken,ROUTES,ANALYZE_FOR_ENTRY_COMPONENTS,Host,Self,SkipSelf,Inject,Optional,Attribute,ContentChild,ContentChildren,ViewChild,ViewChildren,Input,Output,Pipe,HostBinding,HostListener,Directive,Component,NgModule,Host,Self,SkipSelf,Optional
```ts
function makeMetadataFactory(name: string, props?: (...args: any[]) => T): MetadataFactory {const factory: any = (...args: any[]) => {const values = props ? props(...args) : {};return {ngMetadataName: name,...values,};};factory.isTypeOf = (obj: any) => obj && obj.ngMetadataName === name;factory.ngMetadataName = name;return factory;
}
复制代码 创建处理器
const handlerTestDecorator = makeMetadataFactory('testDecorator',()=>{//由于我们知识测试没啥实际功能return {};
});
复制代码 如果能注册到map里面我们就能通过编译,最后一步了,卧槽掉井里了,在compiler-cli里调用的。到此结束了!
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
