装饰器在Angular中是个很常见的概念,@Component
、@Directive
、@Pipe
、@NgModule
、@Injectable
、@Input
、@Inject
等等.本文着重讲解各种装饰器的作用以及在Angular中的实际使用
装饰工厂
装饰器工厂只是一个函数,它返回将由装饰器在运行时调用的表达式function color(value: string) {
// this is the decorator factory, it sets up
// the returned decorator function
return function (target) {
// this is the decorator
// do something with 'target' and 'value'...
};
}
类装饰
类型注释:
type ClassDecorator = <TFunction extends Function> |
@参数:
1.
target
:类的构造函数@Returns
如果类装饰器返回一个值,它将替换类声明。
因此,它适用于扩展具有某些属性或方法的现有类。
function toString() { |
方法装饰
类型注释:type MethodDecorator = <T>(
target: Object,
propertyKey: string | symbol,
descriptor: TypedPropertyDescriptor<T>
) => TypedPropertyDescriptor<T> | void;
@参数:
1.
target
:类的构造函数或实例成员的类的原型2.
propertyKey
:属性名称3.
descriptor
:成员的属性描述符@Returns
如果返回一个值,它将作为成员的描述符
function logger(target: any, propertyKey: string, descriptor: PropertyDescriptor) { |
属性装饰
类型注释:
type PropertyDecorator = |
@参数:
1.
target
:类的构造函数或实例成员的类的原型2.
propertyKey
:属性名称@Returns
如果返回一个值,它将作为属性的描述符
class Greeter { |
访问器装饰
访问器装饰器通常与方法装饰器相同,唯一的区别是描述符中的键:
方法装饰器中的描述符具有键:
- value
- writable
- enumerable
- configurable
访问器装饰器中的描述符具有键:
- get
- set
- enumerable
- configurable
参数装饰
类型注释:
type ParameterDecorator = ( |
@参数:
1.
target
:类的构造函数或实例成员的类的原型2.
propertyKey
:属性名称(方法名,不是参数名)3.
parameterIndex
:函数参数列表中参数的序号索引@Returns
返回值将被忽略。
实例
有如下的button组件,在传入danger输入属性时,根据不同的值,传入不同的值以此来改变按钮样式,
.. |
实际使用时,组件的使用:<button my-button [danger]="true">btn</button>
,danger的入参过于繁琐,通过给danger添加装饰器来达到将不符合的类型值转化为布尔值;已达到<button my-button danger>btn</button>
的效果
定义参数装饰器,引入@angular/cdk
的coerceBooleanProperty
方法将值转换为布尔;function InputBoolean(){
return function ( target: any,propertyKey: string){
const privatePropName = `$$__private__${propName}`;
//创建新的属性并设置属性描述
Object.defineProperty(target, privatePropName, {
configurable: true,
writable: true,
});
/**
* 返回新的属性描述
* 来达到如下效果
* // @Input()
* // get visible() { return this.__visible; }
* // set visible(value) { this.__visible = value; }
* // __visible = false;
*/
return {
get(): string {
this[privatePropName];
},
set(value: T): void {
this[privatePropName] = coerceBooleanProperty(value);
},
};
}
}
之后使用定义好的装饰器,此时使用组件并设置danger参数时,angular会有Type 'string' is not assignable to type 'boolean'
的报错...
export class ButtonComponent {
@Input() @InputBoolean() danger : boolean= false;
}
//danger会提示报错 |
此时通过添加ngAcceptInputType_
前缀来放宽入参的类型
export type BooleanInput = boolean | string | undefined | null;
...
export class ButtonComponent {
static ngAcceptInputType_danger: BooleanInput;
@Input() @InputBoolean() danger : boolean= false;
}
完整代码//button.component.js
...
({
selector: 'button[my-button]',
exportAs: 'myButton',
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
preserveWhitespaces: false,
template: ` <ng-content></ng-content> `,
host: {
class: 'ant-btn',
'[class.ant-btn-dangerous]': `danger`,
},
})
export class ButtonComponent {
static ngAcceptInputType_danger: BooleanInput;
false; () () danger =
constructor() {}
}
//util/convert.ts |
//convert-input.ts |