angular插槽总结

  • 1、ng-content

作用:内容投影,将组建内部写的组件或者html覆盖父组件的ng-content

使用场景:编写组件中需要融入其他组件(类似vue slot)

例:app-d3chart中需要加入app-new-small-card组件,app-new-small-card需要加入app-small-panel组件,只需要在app-d3chart中加<ng-content></ng-content>标签即可。

    <app-d3chart [height]="633" [type]="'world'" [cardId]="'card_dashboard_map'">
      <app-new-small-card [totalHeight]="600">
       <app-small-panel #smallPanel [timeer]="timeer"></app-small-panel>
      </app-new-small-card>
    </app-d3chart>

ng-content有个select属性,可以做一些判断,满足条件再显示要填充的外部内容,支持 CSS 选择器(my-element.my-class[my-attribute],...)来匹配你想要的内容。如果不设置就全部接受。

例:

    /*父组件*/
   <app-parent>
      <app-child class="red"></app-child>
      <app-child name="child"></app-child>
    </app-parent>
    /*子组件 对号入座*/
    <div style="background: cyan">
      <ng-content select="[name=child]"></ng-content>
    </div>
    <div style="background: pink">
      <ng-content select=".red"></ng-content>
    </div>

ng-content有@ContentChild装饰器,可以用来调用投影内容了,和@ViewChild非常类似。异同点如下:

相同点

  1. 都是属性装饰器
  2. 都有对应的复数形式装饰器:ContentChildren、ViewChildren
  3. 都支持 Type

不同点

  1. ContentChild 用来从通过 Content Projection 方式 (ng-content) 设置的视图中获取匹配的元素
  2. ViewChild 用来从模板视图中获取匹配的元素
  3. 在父组件的 ngAfterContentInit 生命周期钩子中才能成功获取通过 ContentChild 查询的元素
  4. 在父组件的 ngAfterViewInit 生命周期钩子中才能成功获取通过 ViewChild 查询的元素

参考:https://www.cnblogs.com/yw0219/p/7789211.html

  • 2、ng-template

作用:用来渲染 HTML,它永远不会直接显示出来。 事实上,在渲染视图之前,Angular 会把 <ng-template>及其内容替换为一个注释。一般和判断指令一起使用。符合条件才渲染。

不会渲染

      <ng-template>
          <div>Loading...</div>
      </ng-template>

会渲染 

<div class="lessons-list" *ngIf="lessons else loading">
  ... 
</div>

<ng-template #loading>
    <div>Loading...</div>
</ng-template>

使用场景:

1、模板引用,使用ViewChild 装饰器注入

例:defaultTabButtons这块可以

@Component({
  selector: 'app-root',
  template: `      
      <ng-template #defaultTabButtons>
          <button class="tab-button" (click)="login()">
            {{loginText}}
          </button>
          <button class="tab-button" (click)="signUp()">
            {{signUpText}}
          </button>
      </ng-template>
`})
export class AppComponent implements OnInit {
    @ViewChild('defaultTabButtons')
    private defaultTabButtonsTpl: TemplateRef<any>;

    ngOnInit() {
        console.log(this.defaultTabButtonsTpl);
    }
}

2、通过 @Input 导入部分模板(组合模式),与其他模板组合在一起,以形成最终的组件模板。一般和ngTemplateOutlet(实例化模板)一起使用,用于动态填充或插入相应的内容。

例:如果父组件nzTitle配置的是字符串,就显示字符串内容,如果不是,通过ngTemplateOutlet指令动态去创建。

    <ng-template #titleTemplate>
      <ng-template [ngTemplateOutlet]="nzTitle"></ng-template>
    </ng-template>
    <div class="ant-card-head" *ngIf="nzTitle||nzExtra||tab">
      <div class="ant-card-head-wrapper">
        <div class="ant-card-head-title" *ngIf="nzTitle">
          <ng-container *ngIf="isTitleString; else titleTemplate">{{ nzTitle }}</ng-container>
        </div>
      </div>
    </div>
     <nz-card [nzBordered]="false" [nzTitle]="titleRiskTrendTop10">
        <ng-template #titleRiskTrendTop10>
          风险趋势排行TOP10
        </ng-template>
        <app-risk-trend-top10 #riskTrendTop10 [timeer]="timeer"></app-risk-trend-top10>
      </nz-card>

3、动态加载

例如广告条场景,先使用一个名叫 AdDirective 的辅助指令来在模板中标记出有效的插入点。

import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[ad-host]',
})
export class AdDirective {
  constructor(public viewContainerRef: ViewContainerRef) { }
}

加载到模块组件位置,选择器ad-host是AdDirective服务的,ad-host不用带尖括号。

        template: `
            <div class="ad-banner">
              <h3>Advertisements</h3>
              <ng-template ad-host></ng-template>
            </div>

4、和结构型指令一起使用

例:下面俩种写法是一样的,星号是一个用来简化更复杂语法的“语法糖”。 从内部实现来说,Angular 把 *ngIf 属性 翻译成一个 <ng-template> 元素 并用它来包裹宿主元素。

  • *ngIf 指令被移到了 <ng-template> 元素上。在那里它变成了一个属性绑定 [ngIf]

  • <div> 上的其余部分,包括它的 class 属性在内,移到了内部的 <ng-template> 元素上。

<div *ngIf="hero" class="name">{{hero.name}}</div>
<ng-template [ngIf]="hero">
  <div class="name">{{hero.name}}</div>
</ng-template>

5、结构型指令

例:这个例子结构型指令会从 Angular 生成的 <ng-template> 元素中创建一个内嵌的视图,并把这个视图插入到一个视图容器中,紧挨着本指令原来的宿主元素 <p>(译注:注意不是子节点,而是兄弟节点)。

你可以使用TemplateRef取得 <ng-template> 的内容,并通过ViewContainerRef来访问这个视图容器

你可以把它们都注入到指令的构造函数中,作为该类的私有属性。

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

/**
 * Add the template content to the DOM unless the condition is true.
 */
@Directive({ selector: '[appUnless]'})
export class UnlessDirective {
  private hasView = false;

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef) { }

  @Input() set appUnless(condition: boolean) {
    if (!condition && !this.hasView) {
      this.viewContainer.createEmbeddedView(this.templateRef);
      this.hasView = true;
    } else if (condition && this.hasView) {
      this.viewContainer.clear();
      this.hasView = false;
    }
  }
}

<p *appUnless="condition" class="unless a">
  (A) This paragraph is displayed because the condition is false.
</p>

<p *appUnless="!condition" class="unless b">
  (B) Although the condition is true,
  this paragraph is displayed because appUnless is set to false.
</p>

参考:https://www.angular.cn/guide/structural-directives

  • 3、ng-container

作用:是一个分组元素,把一些兄弟元素归为一组,但它不会污染样式或元素布局。因为 Angular 不会把它渲染到 DOM 中。

使用场景:字符串拼接时,需要满足条件才显示的部分,如果用其他标签包裹起来进行判断,可能会有样式问题。

例1:字符串拼接时,如果span标签有样式,就会导致这一行字体不一样

<p>
  I turned the corner
  <span *ngIf="hero">
    and saw {{hero.name}}. I waved
  </span>
  and continued on my way.
</p>

用ng-container就不会有这种顾虑

<p>
  I turned the corner
  <ng-container *ngIf="hero">
    and saw {{hero.name}}. I waved
  </ng-container>
  and continued on my way.
</p>

例2:select根据条件排除选择框中的某个 <option>。浏览器不会显示 <span> 中的 <option>

<div>
  Pick your favorite hero
  (<label><input type="checkbox" checked (change)="showSad = !showSad">show sad</label>)
</div>
<select [(ngModel)]="hero">
  <span *ngFor="let h of heroes">
    <span *ngIf="showSad || h.emotion !== 'sad'">
      <option [ngValue]="h">{{h.name}} ({{h.emotion}})</option>
    </span>
  </span>
</select>

使用ng-container可正常显示

<div>
  Pick your favorite hero
  (<label><input type="checkbox" checked (change)="showSad = !showSad">show sad</label>)
</div>
<select [(ngModel)]="hero">
  <ng-container *ngFor="let h of heroes">
    <ng-container *ngIf="showSad || h.emotion !== 'sad'">
      <option [ngValue]="h">{{h.name}} ({{h.emotion}})</option>
    </ng-container>
  </ng-container>
</select>

猜你喜欢

转载自blog.csdn.net/ligaoming_123/article/details/81478446