dst*_*str 19 typescript angular
我有几个组件装饰器声明,我在每个组件上重复,例如:
@Component({
moduleId: module.id,
directives: [BootstrapInputDirective]
})
Run Code Online (Sandbox Code Playgroud)
如何将这些声明应用于我的所有组件?我试图用这个装饰器创建一个基类,并用它扩展其他类,但基类装饰似乎不适用于派生类.
Thi*_*ier 23
@Component是装饰师.这意味着它通过添加一些利用reflect-metadata库的元数据来处理它所应用的类.Angular2不会查找父类的元数据.因此,不能在父类上使用装饰器.
关于BootstrapInputDirective指令,您可以将其定义为平台指令.这样,您不需要每次都将它包含directives在组件的属性中.
这是一个示例:
(...)
import {PLATFORM_DIRECTIVES} from 'angular2/core';
bootstrap(AppComponent, [
provide(PLATFORM_DIRECTIVES, {useValue: [BootstrapInputDirective], multi:true})
]);
Run Code Online (Sandbox Code Playgroud)
编辑
是的,您可以创建自己的装饰器来实现这一点.这是一个示例:
export function CustomComponent(annotation: any) {
return function (target: Function) {
var parentTarget = annotation.parent;
delete annotation.parent;
var parentAnnotations = Reflect.getMetadata('annotations', parentTarget);
var parentAnnotation = parentAnnotations[0];
Object.keys(parentAnnotation).forEach(key => {
if (isPresent(parentAnnotation[key])) {
annotation[key] = parentAnnotation[key];
}
});
var metadata = new ComponentMetadata(annotation);
Reflect.defineMetadata('annotations', [ metadata ], target);
}
}
Run Code Online (Sandbox Code Playgroud)
该CustomComponent装饰将采用这种方式:
@Component({
template: `
<div>Test</div>
`
})
export class AbstractComponent {
}
@CustomComponent({
selector: 'sub',
parent: AbstractComponent
})
export class SubComponent extends AbstractComponent {
}
Run Code Online (Sandbox Code Playgroud)
请注意,我们需要提供父类作为装饰器的输入,因为我们可以在装饰器中找到这个父类.只有该类的原型,但元数据应用于类,而不是通过reflect-metadata应用于关联的原型.
EDIT2
感谢Nitzam的回答,这是一个改进:
export function CustomComponent(annotation: any) {
return function (target: Function) {
var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
var parentAnnotations = Reflect.getMetadata('annotations', parentTarget);
var parentAnnotation = parentAnnotations[0];
Object.keys(parentAnnotation).forEach(key => {
if (isPresent(parentAnnotation[key])) {
annotation[key] = parentAnnotation[key];
}
});
var metadata = new ComponentMetadata(annotation);
Reflect.defineMetadata('annotations', [ metadata ], target);
}
}
Run Code Online (Sandbox Code Playgroud)
不需要parent属性来引用自定义装饰器中的父类.
请参阅此plunkr:https://plnkr.co/edit/ks1iK41sIBFlYDb4aTHG ? p = preview .
看到这个问题:
在最新版本的Angular之后,ComponentMetadata类不可用,如此处的几个成员所指出的那样.
这就是我实现CustomComponent以使其工作的方式:
export function CustomComponent(annotation: any) {
return function (target: Function) {
let parentTarget = Object.getPrototypeOf(target.prototype).constructor;
let parentAnnotations = Reflect.getOwnMetadata('annotations', parentTarget);
let parentAnnotation = parentAnnotations[0];
Object.keys(annotation).forEach(key => {
parentAnnotation[key] = annotation[key];
});
};
}
Run Code Online (Sandbox Code Playgroud)
希望能帮助到你!
编辑:前面的代码块,即使它工作,它也会覆盖扩展类的原始元数据.在下面找到它的增强版本,允许您具有多个继承和覆盖而无需修改基类.
export function ExtendComponent(annotation: any) {
return function (target: Function) {
let currentTarget = target.prototype.constructor;
let parentTarget = Object.getPrototypeOf(target.prototype).constructor;
let parentAnnotations = Reflect.getOwnMetadata('annotations', parentTarget);
Reflect.defineMetadata('annotations', [Object.create(parentAnnotations[0])], currentTarget);
let currentAnnotations = Reflect.getOwnMetadata('annotations', currentTarget);
Object.keys(annotation).forEach(key => {
currentAnnotations[0][key] = annotation[key];
});
};
Run Code Online (Sandbox Code Playgroud)
}
如果有人正在寻找更新的解决方案,那么Thierry Templier的答案非常完美.除了ComponentMetadata已被弃用.使用Component相反为我工作.
完整的Custom Decorator CustomDecorator.ts文件如下所示:
import 'zone.js';
import 'reflect-metadata';
import { Component } from '@angular/core';
import { isPresent } from "@angular/platform-browser/src/facade/lang";
export function CustomComponent(annotation: any) {
return function (target: Function) {
var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
var parentAnnotations = Reflect.getMetadata('annotations', parentTarget);
var parentAnnotation = parentAnnotations[0];
Object.keys(parentAnnotation).forEach(key => {
if (isPresent(parentAnnotation[key])) {
// verify is annotation typeof function
if(typeof annotation[key] === 'function'){
annotation[key] = annotation[key].call(this, parentAnnotation[key]);
}else if(
// force override in annotation base
!isPresent(annotation[key])
){
annotation[key] = parentAnnotation[key];
}
}
});
var metadata = new Component(annotation);
Reflect.defineMetadata('annotations', [ metadata ], target);
}
}
Run Code Online (Sandbox Code Playgroud)
然后将其导入到新的组件sub-component.component.ts文件中,@CustomComponent而不是@Component像这样使用:
import { CustomComponent } from './CustomDecorator';
import { AbstractComponent } from 'path/to/file';
...
@CustomComponent({
selector: 'subcomponent'
})
export class SubComponent extends AbstractComponent {
constructor() {
super();
}
// Add new logic here!
}
Run Code Online (Sandbox Code Playgroud)
以防您正在寻找isPresent功能:
function isPresent(obj: any): boolean {
return obj !== undefined && obj !== null;
}
| 归档时间: |
|
| 查看次数: |
16508 次 |
| 最近记录: |