1.ng-template指令介绍--<ng-template></ng-template>
ng-template表示一个模板,标签内是模板的内容,模板的内容可以与其它模板一起组成组件模板。
在Angular中,我们用过的许多结构指令都使用了ng-template,如ngIf、ngFor和ngSwitch。
ngTemplate中的内容可以自定义,并且一开始不会被渲染,除非满足一定的条件。我们必须使用结构指令去渲染它。
<ng-template>
<button class="tab-button" (click)="login()">{{loginText}}</button>
<button class="tab-button" (click)="signUp()">{{signUpText}}</button>
</ng-template>
上面代码在页面中并没有被渲染。
2.ng-template使用
2.1ng-template与ngIf
我们见的最多的可能是与ngIf一块使用,当if条件不成立时,将显示else中的内容。下面代码中else语句被指向了一个名为loading的模板,通过模板引用#loading的方式。
1 <div class="lessons-list" *ngIf="lessons else loading">
2 ...
3 </div>
4
5 <ng-template #loading>
6 <div>Loading...</div>
7 </ng-template>
其实,ngIf指令也是ng-template的包装。
1 <ng-template [ngIf]="lessons" [ngIfElse]="loading">
2 <div class="lessons-list">
3 ...
4 </div>
5 </ng-template>
6
7 <ng-template #loading>
8 <div>Loading...</div>
9 </ng-template>
[ngIf]和[ngIfElse]为模板输入变量。
2.2同一元素使用多个结构指令
1 <div class="lesson" *ngIf="lessons"
2 *ngFor="let lesson of lessons">
3 <div class="lesson-detail">
4 {{lesson | json}}
5 </div>
6 </div>
这样会报错:
Uncaught Error: Template parse errors:
Can't have multiple template bindings on one element. Use only one attribute
named 'template' or prefixed with *
这意味着不能在同一个元素使用两个或多个结构指令。
1 <div *ngIf="lessons">
2 <div class="lesson" *ngFor="let lesson of lessons">
3 <div class="lesson-detail">
4 {{lesson | json}}
5 </div>
6 </div>
7 </div>
可以在ngFor指令的外面包一层ngIf指令,这样就解决了上面的问题;但这样会额外创一个一个元素。因此,我们可以使用ng-container指令。
1 <ng-container *ngIf="lessons">
2 <div class="lesson" *ngFor="let lesson of lessons">
3 <div class="lesson-detail">
4 {{lesson | json}}
5 </div>
6 </div>
7 </ng-container>
ng-container的一种用途是,给我们提供一个附加指令的元素而不会创建一个额外的元素。另一种用途是,配合ngTemplateOutlet使用。
3.ngTemplateOutlet使用介绍
ngTemplateOutlet也是一个指令,它使用模板引用和上下文对象作为参数动态实例化模板。作为一个结构指令,我们可以使用它在DOM的各个部分插入模板(由ng-template创建)。
1 <ng-container *ngTemplateOutlet="loading">This text is not displayed</ng-container>
ngTemplateOutlet包含的任何内部内容都不会被渲染;我们可以根据需要向页面添加任意数量的ngTemplateOutlet标签,并实例化许多不同的模板。
1 <div *ngTemplateOutlet="loading"></div>
上面代码中的div并不会被渲染,因为angular将上述内容替换成ng-template语法,
1 <ng-template [ngTemplateOutlet]="template1"><div></div></ng-template>
3.1传递数据给ngTemplateOutlet
我们可以通过ngTemplateOutletContext属性传递数据
1 <ng-template let-value="value" #messageTemplate>
2 <p>Value Received from the Parent is {{value}}</p>
3 </ng-template>
1 <ng-container [ngTemplateOutlet]="messageTemplate"
2 [ngTemplateOutletContext] ="{value:'1000'}">
3 </ng-container>
当然,也可以使用简写属性--context:
1 <ng-container *ngTemplateOutlet="messageTemplate; context:{value:100}"></ng-container> 传递多个数据:
1 <ng-template let-name="nameVar" let-message="messageVar" #template>
2 <p>Dear {{name}} , {{message}} </p>
3 </ng-template>
4
5
6 <ng-container [ngTemplateOutlet]="template"
7 [ngTemplateOutletContext] ="{nameVar:'Guest',messageVar:'Welcome to our site'}">
8 </ng-container>
传递对象:
1
2 <ng-template let-person="person" #template>
3 <p>Dear {{person.name}} , {{person.message}} </p>
4 </ng-template>
5
6
7 <ng-container [ngTemplateOutlet]="template"
8 [ngTemplateOutletContext] ="{ person:{name:'Guest',message:'Welcome to our site'} }">
9 </ng-container>
使用$implicit:
可以在上下文对象中使用$implicit将其值设置为所有局部变量的默认值。
1 <ng-template let-name let-message="message" #template3>
2 <p>Dear {{name}} , {{message}} </p>
3 </ng-template>
4
5 <ng-container [ngTemplateOutlet]="templates"
6 [ngTemplateOutletContext] ="{$implicit:'Guest',message:'Welcome to our site'}">
7 </ng-container>
上面代码中,我们没有给 let-name 赋值,因此它从$implicit中获取值。
3.2模板上下文
每个模板可以定义自己的输入变量;实际上,每个模板都关联了一个上下文对象,其中包含所有特定于模板的输入变量。
1 @Component({
2 selector: 'app-root',
3 template: `
4 <ng-template #estimateTemplate let-lessonsCounter="estimate">
5 <div> Approximately {{lessonsCounter}} lessons ...</div>
6 </ng-template>
7 <ng-container
8 *ngTemplateOutlet="estimateTemplate;context:ctx">
9 </ng-container>
10 `})
11 export class AppComponent {
12
13 totalEstimate = 10;
14 ctx = {estimate: this.totalEstimate};
15
16 }
说明:lessonsCounter为输入变量,通过ng-template属性使用前缀 let- 定义的
lessonsCounter对ng-template模板里面的内容是可见的,对模板外是不可见的。
lessonsCounter的值是由 estimate 决定的,故context 对象必须有一个estimate 的属性。
3.3 模板引用
我们可以使用ViewChild装饰器将模板直接注入到组件中:
1 @Component({
2 selector: 'app-root',
3 template: `
4 <ng-template #defaultTabButtons>
5 <button class="tab-button" (click)="login()">
6 {{loginText}}
7 </button>
8 <button class="tab-button" (click)="signUp()">
9 {{signUpText}}
10 </button>
11 </ng-template>
12 `})
13 export class AppComponent implements OnInit {
14
15 @ViewChild('defaultTabButtons')
16 private defaultTabButtonsTpl: TemplateRef<any>;
17
18 ngOnInit() {
19 console.log(this.defaultTabButtonsTpl); //undefined; ngAfterViewInit()才会打印
20 }
21
22 }
模板可以被注入,就像DOM元素和组件一样,通过将模板引用传给ViewChild装饰器。
我们还可以将模板作为一个输入变量:
1 @Component({
2 selector: 'app-root',
3 template: `
4 <ng-template #customTabButtons>
5 <div class="custom-class">
6 <button class="tab-button" (click)="login()">
7 {{loginText}}
8 </button>
9 <button class="tab-button" (click)="signUp()">
10 {{signUpText}}
11 </button>
12 </div>
13 </ng-template>
14 <tab-container [headerTemplate]="customTabButtons"></tab-container>
15 `})
16 export class AppComponent implements OnInit {
17
18 }
1 @Component({
2 selector: 'tab-container',
3 template: `
4
5 <ng-template #defaultTabButtons>
6
7 <div class="default-tab-buttons">
8 ...
9 </div>
10
11 </ng-template>
12 <ng-container
13 *ngTemplateOutlet="headerTemplate ? headerTemplate: defaultTabButtons">
14
15 </ng-container>
16 ... rest of tab container component ...
17 `})
18 export class TabContainerComponent {
19 @Input()
20 headerTemplate: TemplateRef<any>;
21 }
当我们传入自定义模板时(#customTabButtons),就显示这个自定义模板;否则,显示默认的模板。
3.4 ngTemplateOutlet、ng-template 与内容投影
父组件使用内容投影传递一个模板给子组件:
1 import { Component, TemplateRef, Input, OnInit, ViewChild, AfterViewInit } from '@angular/core';
2
3 @Component({
4 selector: 'parent1',
5 template: `
6
7 <h1>Parent Component </h1>
8
9 <child1>
10 <p>This Template is Projected to the Child</p>
11 </child1>
12 `
13 })
14 export class Parent1Component {
15 }
子组件:
1 import { Component, TemplateRef, Input, OnInit, ViewChild, AfterViewInit } from '@angular/core';
2
3 @Component({
4 selector: 'child1',
5 template: `
6
7 <h1>Child Component </h1>
8
9 <ng-template #parentTemplate>
10 <ng-content></ng-content>
11 </ng-template>
12
13 <ng-template [ngTemplateOutlet]="parentTemplate"></ng-template>
14
15 `
16 })
17 export class Child1Component {
18 }
19
4.总结
ng-template、ng-container和ngTemplateOutlet指令结合使用,可以创建高度动态和可定制的组件。
来源:https://www.cnblogs.com/sparkler/p/15490689.html |