gpt4 book ai didi

angular - 使用结构指令将组件添加到 TemplateRef

转载 作者:太空狗 更新时间:2023-10-29 17:19:09 24 4
gpt4 key购买 nike

我们正在构建一个 angular 4 组件库,其中一个组件是 Busy 组件。该组件的目的是允许开发人员在任何包含微调器图形的给定 HTML 元素上创建叠加层。

<div *xuiBusy="isBusy">...</div>

当值isBusy是真的我们想追加到 div 的内部内容这样我们就可以在内容之上呈现叠加元素。

我们已经能够将组件附加到 ViewContainerRef然而,这会将 busy 元素作为 div 的兄弟元素插入而不是在 div 内随心所欲。

    ngOnInit(): void {
const compFactory = this._componentFactory.resolveComponentFactory(XuiBusyComponent);
const comp = this._viewContainer.createComponent(compFactory);

消费者做什么:

<div *xuiBusy="isBusy">
<span>This is the content</span>
</div>

isBusy设置为 true 我们希望将标记更改为如下所示。注意 <spinner>已添加到 div元素。

<div *xuiBusy="isBusy">
<span>This is the content</span>
<spinner>Please wait...</spinner> <-- inserted by directive
</div>

感谢任何建议!

最佳答案

演示

我已经设置了 a demo on StackBlitz .为简洁起见,Spinner 组件、Busy 指令和消费者都在 app.component.ts 中。

设置

结构指令需要注入(inject)以下内容:

  • TemplateRef , 对结构指令所在模板的引用(在脱糖语法中);
  • ViewContainerRef ,对 View 容器的引用,可以在结构指令封装的 View 内呈现;
  • ComponentFactoryResolver ,一个知道如何从代码动态创建组件实例的类。

Angular 中的注入(inject)是通过构造函数完成的。

constructor(private templateRef: TemplateRef<void>,
private vcr: ViewContainerRef,
private cfr: ComponentFactoryResolver) { }

传递 bool 值

我们需要输入以便从外部传递数据。为了使语法漂亮和明显(特别是当指令需要单个输入时,例如在本例中),我们可以将输入命名为与指令选择器完全相同的名称。

要重命名输入,我们可以传递 bindingPropertyNameInput装饰器。

@Input('xuiBusy') isBusy: boolean;

创建消费者的内容

可以使用 createEmbeddedView 动态创建消费者的内容在 ViewContainerRef 类上定义的方法。第一个参数是唯一的强制参数,它接受一个模板引用,插入的 View 将基于该模板引用:这是我们在我们的案例中注入(inject)的 templateRef

this.vcr.createEmbeddedView(this.templateRef)

创建组件

动态创建组件需要更多仪式,因为您首先需要解析知道如何跨越组件实例的工厂。

为此,我们使用 resolveComponentFactory注入(inject)的 ComponentFactoryResolver 实例上的方法。

const cmpFactory = this.cfr.resolveComponentFactory(SpinnerComponent)

现在我们可以使用生成的工厂来以与创建嵌入式 View 类似的方式createComponent

this.vcr.createComponent(cmpFactory)

当然,这只有在 isBusy 标志设置为 true 时才会发生,因此我们将其包装在一个分支中。

if (this.isBusy) {
const cmpFactory = this.cfr.resolveComponentFactory(SpinnerComponent)
this.vcr.createComponent(cmpFactory)
}

入口组件

Angular 需要先编译我们的组件,然后才能在应用程序中使用它们。如果组件从未在模板中被引用,Angular 将不知道它需要编译它。我们的 Spinner 组件就是这种情况,因为我们只是从代码中动态添加它。

要明确告诉 Angular 编译组件,请将其添加到 NgModule.entryComponents

@NgModule({
...
entryComponents: [SpinnerComponent],
...
})

完整代码

@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)
}
}

}

使用示例(也可查看 the demo)

<div *xuiBusy="true">
<span>This is some content</span>
</div>

<div *xuiBusy="false">
<span>This is some content</span>
</div>

关于angular - 使用结构指令将组件添加到 TemplateRef,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43944487/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com