我正在尝试创建一个共享Angular组件库,以便在许多不同的Web项目中使用。除了共享组件库之外,我还尝试创建一个包含并显示所有这些组件的Web项目以及如何使用它们的代码示例。
从与类似问题相关的其他查询中可以看出,为了在<pre>
或<code>
标记的网页中显示HTML代码,这些HTML代码段的某些方面需要包含HTML编码字符(即>
必须为>
,<
必须为<
)。需要从源代码手动进行这些更改可能非常繁琐且乏味。
我想找到一种方法能够读取给定组件的HTML模板,进行少量文本替换,然后将该值设置为要在视图中显示的属性。我已经看到了其他类似的SO问题,这些问题的答案不同且不够,例如this。
如果我有foo.component.ts
如下:
import { Component } from '@angular/core';
@Component({
selector: 'foo',
template: `
<div class="foo">
<div class="content">
<ng-content select="[top-content]"></ng-content>
</div>
<div class="extra content">
<ng-content select="[bottom-content]"></ng-content>
</div>
</div>
`
})
export class FooComponent {}
我想创建一个display-foo.component.ts
,其内容如下:
import { Component } from '@angular/core';
import { FooComponent } from './foo.component';
@Component({
selector: 'display-foo',
template: `
<pre class="example-code">
<code>
{{encodedExampleHtml}}
</code>
</pre>
<foo>
<div top-content>TOP</div>
<div bottom-content>BOTTOM</div>
</foo>
`
})
export class DisplayFooComponent {
encodedExampleHtml: string;
constructor() {
this.encodedExampleHtml = new FooComponent().template.replace('<', '<').replace('>', '>');
}
}
本质上,这将把模板放在UI中,供下一个开发人员查看和理解如何利用该类型组件的实际渲染元素,以及显示组件在实际中使用时的外观应用
我无法弄清楚如何工作的DisplayFooComponent
部分是this.encodedExampleHtml = new FooComponent().template.replace('<', '<').replace('>', '>');
将其视为我想要做的伪代码,因为Angular组件对象没有模板属性,据我所知,没有公开该组件模板的属性。
有没有办法利用Angular框架来获取组件的HTML模板?再次,我不希望替换表达式的插值内容,而是实际的原始HTML模板是否由装饰器的template
属性或其templateUrl
属性与元素相关联?
答案 0 :(得分:3)
您可以尝试使用特殊功能来获取注释:
<强> annotation.ts 强>
declare let Reflect: any;
export function getAnnotation(typeOrFunc: Type<any>): any[]|null {
// Prefer the direct API.
if ((<any>typeOrFunc).annotations) {
let annotations = (<any>typeOrFunc).annotations;
if (typeof annotations === 'function' && annotations.annotations) {
annotations = annotations.annotations;
}
return annotations[0];
}
// API of tsickle for lowering decorators to properties on the class.
if ((<any>typeOrFunc).decorators) {
return convertTsickleDecoratorIntoMetadata((<any>typeOrFunc).decorators)[0];
}
// API for metadata created by invoking the decorators.
if (Reflect && Reflect.getOwnMetadata) {
return Reflect.getOwnMetadata('annotations', typeOrFunc)[0];
}
return null;
}
function convertTsickleDecoratorIntoMetadata(decoratorInvocations: any[]): any[] {
if (!decoratorInvocations) {
return [];
}
return decoratorInvocations.map(decoratorInvocation => {
const decoratorType = decoratorInvocation.type;
const annotationCls = decoratorType.annotationCls;
const annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : [];
return new annotationCls(...annotationArgs);
});
}
然后
this.encodedExampleHtml = getAnnotation(FooComponent).template;
<强> Plunker Example 强>
另见
答案 1 :(得分:0)
yurzui's answer适用于Angular 4.4.2但不适用于5.0.2。注释机制已更改:使用属性而不是Reflect.defineMetadata()来存储元数据。由于没有记录,人们只能在代码中找到它:
const /** @type {?} */ TypeDecorator = (function TypeDecorator(cls) {
const /** @type {?} */ annotations = Reflect.getOwnMetadata('annotations', cls) || [];
annotations.push(annotationInstance);
Reflect.defineMetadata('annotations', annotations, cls);
return cls;
});
在Angular 4.4.2(@angular/core/@angular/core.js
,l.356)中
const ANNOTATIONS = '__annotations__';
const /** @type {?} */ TypeDecorator = /** @type {?} */ (function TypeDecorator(cls) {
// Use of Object.defineProperty is important since it creates non-enumerable property which
// prevents the property is copied during subclassing.
const /** @type {?} */ annotations = cls.hasOwnProperty(ANNOTATIONS) ?
(/** @type {?} */ (cls))[ANNOTATIONS] :
Object.defineProperty(cls, ANNOTATIONS, { value: [] })[ANNOTATIONS];
annotations.push(annotationInstance);
return cls;
});
在Angular 5.0.2(@angular/core/esm2015/core.js
,l.96)中。
更新了访问元数据的代码,例如模板:
import 'reflect-metadata';
export function getAnnotation(typeOrFunc: Type<any>): any[]|null {
// Prefer the direct API.
if ((<any>typeOrFunc)['__annotations__']) {
return (<any>typeOrFunc)['__annotations__'][0];
}
// API of tsickle for lowering decorators to properties on the class.
if ((<any>typeOrFunc).decorators) {
return convertTsickleDecoratorIntoMetadata((<any>typeOrFunc).decorators)[0];
}
// API for metadata created by invoking the decorators.
if (Reflect && Reflect.getOwnMetadata) {
return Reflect.getOwnMetadata('annotations', typeOrFunc)[0];
}
return null;
}
function convertTsickleDecoratorIntoMetadata(decoratorInvocations: any[]): any[] {
if (!decoratorInvocations) {
return [];
}
return decoratorInvocations.map(decoratorInvocation => {
const decoratorType = decoratorInvocation.type;
const annotationCls = decoratorType.annotationCls;
const annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : [];
return new annotationCls(...annotationArgs);
});
}