Rob*_*Rob 8 angular2-directives angular
我们正在构建一个角度4组件库,其中一个组件是一个Busy组件.该组件的目的是允许开发人员在包含微调器图形的任何给定HTML元素上创建叠加层.
<div *xuiBusy="isBusy">...</div>
Run Code Online (Sandbox Code Playgroud)
当值为isBusytrue时,我们想要附加到内部内容,div以便我们可以在内容的顶部显示叠加元素.
我们已经能够将组件附加到,ViewContainerRef但是这会将busy元素作为兄弟插入div而不是div根据需要插入.
ngOnInit(): void {
const compFactory = this._componentFactory.resolveComponentFactory(XuiBusyComponent);
const comp = this._viewContainer.createComponent(compFactory);
Run Code Online (Sandbox Code Playgroud)
消费者做了什么:
<div *xuiBusy="isBusy">
<span>This is the content</span>
</div>
Run Code Online (Sandbox Code Playgroud)
当isBusy设置为true时,我们想要改变市场看起来像这样.请注意,<spinner>已添加到div元素中.
<div *xuiBusy="isBusy">
<span>This is the content</span>
<spinner>Please wait...</spinner> <-- inserted by directive
</div>
Run Code Online (Sandbox Code Playgroud)
任何建议表示赞赏!
我在StackBlitz上设置了一个演示.Spinner组件,Busy指令和消费者都是app.component.ts为了简洁.
结构指令需要注入以下内容:
TemplateRef,对结构指令所在的模板的引用(在desugared语法中);ViewContainerRef,对视图容器的引用,可以在结构指令封装的视图中呈现;ComponentFactoryResolver,一个知道如何从代码中动态创建组件实例的类.在Angular中注入是通过构造函数完成的.
constructor(private templateRef: TemplateRef<void>,
private vcr: ViewContainerRef,
private cfr: ComponentFactoryResolver) { }
Run Code Online (Sandbox Code Playgroud)
我们需要输入才能从外部传递数据.为了使语法非常明显(特别是当指令需要单个输入时,例如在这种情况下),我们可以将输入命名为与指令的选择器完全相同.
要重命名输入,我们可以传递bindingPropertyName给Input装饰器.
@Input('xuiBusy') isBusy: boolean;
Run Code Online (Sandbox Code Playgroud)
可以使用createEmbeddedView在ViewContainerRef类上定义的方法动态创建消费者的内容.第一个参数是唯一的强制参数,它接受插入视图将基于的模板引用:这是templateRef我们在案例中注入的.
this.vcr.createEmbeddedView(this.templateRef)
Run Code Online (Sandbox Code Playgroud)
动态创建组件需要更多的仪式,因为您首先需要解析知道如何跨越组件实例的工厂.
为此,我们resolveComponentFactory在注入的实例上使用该方法ComponentFactoryResolver.
const cmpFactory = this.cfr.resolveComponentFactory(SpinnerComponent)
Run Code Online (Sandbox Code Playgroud)
现在我们可以使用生成的工厂以createComponent类似的方式创建嵌入式视图.
this.vcr.createComponent(cmpFactory)
Run Code Online (Sandbox Code Playgroud)
当然,只有当isBusy标志设置为时才会发生这种情况true,所以我们将它包装在一个分支中.
if (this.isBusy) {
const cmpFactory = this.cfr.resolveComponentFactory(SpinnerComponent)
this.vcr.createComponent(cmpFactory)
}
Run Code Online (Sandbox Code Playgroud)
Angular需要先编译我们的组件,然后才能在应用程序中使用它们.如果组件从未在模板中引用,Angular将不知道它需要编译它.我们的Spinner组件就是这种情况,因为我们只是从代码中动态添加它.
要明确告诉Angular编译组件,请将其添加到NgModule.entryComponents.
@NgModule({
...
entryComponents: [SpinnerComponent],
...
})
Run Code Online (Sandbox Code Playgroud)
@Directive({selector: '[xuiBusy]'})
export class BusyDirective implements OnInit {
@Input('xuiBusy') isBusy: boolean;
constructor(private templateRef: TemplateRef<void>,
private vcr: ViewContainerRef,
private cfr: ComponentFactoryResolver) { }
ngOnInit() {
this.vcr.createEmbeddedView(this.templateRef)
if (this.isBusy) {
const cmpFactory = this.cfr.resolveComponentFactory(SpinnerComponent)
this.vcr.createComponent(cmpFactory)
}
}
}
Run Code Online (Sandbox Code Playgroud)
<div *xuiBusy="true">
<span>This is some content</span>
</div>
<div *xuiBusy="false">
<span>This is some content</span>
</div>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5680 次 |
| 最近记录: |