了解可重用组件中的 ngTemplateOutlet、@ContentChild、ng-container

Edd*_*man 3 javascript angular

我花了更多时间试图理解以下博客文章在 Angular 中使用 NgTemplateOutlet 创建可重用组件

上面帖子的工作代码可以在stackblitz找到。

UsageExample组件的卡或列表视图组件调用。提供了我非常理解的项目模式输入参数。

现在我不明白的是如何

<ng-container *cardItem="let item">
        <h1>{{item.header}}</h1>
        <p>{{item.content}}</p>
      </ng-container>
      <span *listItem="let item">
        <h1>{{item.header}}</h1>
        <p>{{item.content}}</p>
      </span>
Run Code Online (Sandbox Code Playgroud)

UsageExample模板中替换

<ng-container *ngSwitchCase="'card'">
    <div *ngFor="let item of items" style="margin: 5px;border: black 1px solid">
      <ng-container *ngTemplateOutlet="cardItemTemplate; context: {$implicit: item}">
      </ng-container>
    </div>
  </ng-container>
  <ul *ngSwitchCase="'list'">
    <li *ngFor="let item of items">
      <ng-container *ngTemplateOutlet="listItemTemplate; context: {$implicit: item}"></ng-container>
    </li>
  </ul>
Run Code Online (Sandbox Code Playgroud)

CardOrListViewComponent组件模板中。在CardOrListViewComponent组件中,声明了两个指令

@ContentChild(CardItemDirective, {read: TemplateRef}) cardItemTemplate;
  @ContentChild(ListItemDirective, {read: TemplateRef}) listItemTemplate;
Run Code Online (Sandbox Code Playgroud)

并在其模板中使用*ngTemplateOutlet.

这些指令如何被替换

<ng-container *cardItem="let item">
        <h1>{{item.header}}</h1>
        <p>{{item.content}}</p>
      </ng-container>
      <span *listItem="let item">
        <h1>{{item.header}}</h1>
        <p>{{item.content}}</p>
      </span>
Run Code Online (Sandbox Code Playgroud)

UsageExample组件中。

如何*cardItem*listItem连接到这两个 @ContentChild中的指令CardOrListViewComponent组件。他们的名字甚至都不相似。

yur*_*zui 5

首先,Angular 结构指令有两种形式我们可以使用:

1) 加糖版本

<div *ngIf="foo">bar</div>
Run Code Online (Sandbox Code Playgroud)

2) 脱糖版

<ng-template [ngIf]="foo">
  <div>bar</div>
</ng-template>
Run Code Online (Sandbox Code Playgroud)

回到你的例子:

<ng-container *cardItem="let item">
  <h1>{{item.header}}</h1>                            sugar
  <p>{{item.content}}</p>
</ng-container>

       ||
       \/

<ng-template cardItem let-item>
  <ng-container>
    <h1>{{item.header}}</h1>                         de-sugar
    <p>{{item.content}}</p>
  </ng-container>
</ng-template>
Run Code Online (Sandbox Code Playgroud)

其次,通常的做法是通过@ViewChild(-dren)|获取对模板中某些内容的引用。@ContentChild(-dren) 装饰器。

我们可以查询匹配模板元素的指令。Angular 总是匹配我们模板的脱糖版本。所以指令:

@Directive({
  selector: '[cardItem]'
})
export class CardItemDirective {}
Run Code Online (Sandbox Code Playgroud)

匹配模板:

  selector: '[cardItem]' 
               ||
               \/
<ng-template cardItem let-item>
Run Code Online (Sandbox Code Playgroud)

如果您不想要有关我们可以查询的所有可能情况,请遵循以下答案

现在我们知道通过使用@ContentChild 查询:

@ContentChild(CardItemDirective) cardItemTemplate;
Run Code Online (Sandbox Code Playgroud)

我们得到CardItemDirective实例,但我们想要得到TemplateRef以便在*ngTemplateOutlet.

这是read选项可以解决的地方:

@ContentChild(CardItemDirective, {read: TemplateRef}) cardItemTemplate;
                                     \/
         please give us TemplateRef instance from the element 
         that matches CardItemDirective selector
Run Code Online (Sandbox Code Playgroud)

最后TemplateRef我们可以在ngTemplateOutlet指令的帮助下渲染它并传递我们想要的任何上下文:

<div *ngFor="let item of items">
  <ng-container *ngTemplateOutlet="cardItemTemplate; context: {$implicit: item}">
Run Code Online (Sandbox Code Playgroud)