内联内容的角度组件

当您在Angular上进行开发时创建新组件时,您将努力以使其可以多次重复使用的方式来创建它们。 就像软件开发一样,程序员努力使他的代码尽可能地可重用。 同时,我希望具有灵活但不太复杂的组件。



通常,需要使组件尽可能笨拙,以便于维护和测试。 但是同时,它们是可定制的且灵活的,因此您可以多次重用它们,而不用克隆外观和功能相似但仍然有所不同的组件。 或者不要在组件上添加一堆参数,基于它们来启用或禁用组件的任何行为,但实际上在100种情况中,有1种会使用该参数。

要制造一艘潜艇,该潜艇应沉入蔚蓝的海底,而不会危及船员的生命,然后在飞越蓝天之前对其进行改装并不是一件容易的事。

角度组件是应该执行一项简单任务且仅此而已的用户界面的最小单元。 在所有情况下创建组件都是不明智的做法。 因此,您必须在灵活性和简单性之间找到折衷方案。

假设您要创建一个由某种包装器组成的组件,其中包含一个标头和某种开关,以及在其下的某些内容。 像这样:



整个组件(将被称为小部件)以绿色概述。 标头开关以红色突出显示,内容以蓝色突出显示。 Angular是一个非常强大的框架;创建与图片中的组件相似的组件对于Angular来说是一件非常琐碎的任务。

但是,例如,如果使此组件更灵活,使内容根据小部件组件的参数而变化,该怎么办?

您可以基于小部件参数来解析内容的外部表示形式,例如,使用ngIf结构指令。 您可以在不同的视图之间切换。 如果提交的内容过多,则可以使用另一个ngSwitch结构指令。

并且,如果不同的视图对用户操作的反应不同? 然后,组件代码还将具有一堆条件语句。 但是随着时间的流逝,其中包含许多条件语句的代码将变得难以维护,修复错误或扩展功能……

您可以以接收任何内容的方式创建窗口小部件组件,但是与此同时,它会将过滤器面板的选定值扔到内容区域的组件中。 而且,我还希望能够将参数从小部件的父组件转发到内容,而不会影响小部件组件本身。 为了解决这个问题,您可以使用精美的ngTemplateOutlet指令,该指令可以“解析”组件的外观。 有关其他信息,您可以参考文档 ,尽管我认为此处没有显示其所有功能。

在这种情况下,小部件组件可以表示如下:

// widget.component.ts … private widgetContentTemplate: TemplateRef<any>; //      @ContentChild(WidgetContentTemplateDirective, { read: TemplateRef }) set WidgetContentTemplate(value: TemplateRef<any>) { this.widgetContentTemplate = value; } get WidgetContentTemplate(): TemplateRef<any> { return this.widgetContentTemplate; } … 

 <!-- widget.component.html --><div class="widget__content"> <!--      ,      context.   ,     --> <ng-container *ngTemplateOutlet="WidgetContentTemplate || DefaultWidgetContentTemplate; context: { post: SelectedPost }"> </ng-container> </div> <ng-template #DefaultWidgetContentTemplate> <div>[    ]</div> </ng-template> 

ngTemplateOutlet指令接受使用@ContentChild在组件中读取的TemplateRef对象。 为此,您需要创建一个简单的指令。 这是她的代码:

 // widget-content-template.directive.ts import { Directive, TemplateRef } from '@angular/core'; @Directive({ selector: '[appWidgetContentTemplate]' }) export class WidgetContentTemplateDirective { get Template(): TemplateRef<any> { return this.template; } constructor(private readonly template: TemplateRef<any>) {} } 

可以使用上下文对象将小部件开关中的参数传递给内容。 为了使上下文参数能够被组件正确读取,在父组件中是必要的,在我们的示例中为AppComponent,请不要忘记对它们进行如下描述:

 <!-- app.component.html --> <app-widget-component Title="  (  )"> <!-- let-post="post" ,         --> <ng-template appWidgetContentTemplate let-post="post"> <app-post-view [Post]="post"></app-post-view> </ng-template> </app-widget-component> <br> <br> <app-widget-component Title="  (  )"> <!--  let-post="post"     ,  ShowPostInfo  AppComponent --> <ng-template appWidgetContentTemplate let-post="post"> <app-post-view [Post]="post" [ShowPostInfo]="ShowPostInfo"></app-post-view> </ng-template> </app-widget-component> 

因此,我们有一个小部件组件可以接受并显示任何内容,而小部件组件本身不必知道任何有关内容的信息。 它只是转发开关选项。 是否阅读它们只是一个内容问题。



完整的代码版本可以在这里看到。

Source: https://habr.com/ru/post/zh-CN478886/


All Articles