
今天,我们将研究Angular的ng-template、ng-templateOutlet及ng-container指令。在此之前,相信你们已经遇到过Angular中的一些指令,比如用过的ngIf跟ngSwitch指令。
Angular中的ng-template指令和与之相关的ngTemplateOutlet指令,如果使用得到,将会事半功倍。下面我们通过对这三个指令提供相应常见的 来学习及了解他们的使用。
- ng-template指令
见名知意,ng-template指令是一个包容性指令,类比学习你可以将它与vue中的slot比较,但是区别是有的,这里不详细展开。在Angular框架本身的组件或指令中,也经常会看到ng-template影子,比如ngIf、ngFor及ngSwitch。下面我们来看一个例子:
@Component({
selector: 'app-root',
template: `
<ng-template>
<button class="tab-button"
(click)="login()">{{loginText}}</button>
<button class="tab-button"
(click)="signUp()">{{signUpText}}</button>
</ng-template>
`})
export class AppComponent {
loginText = 'Login';
signUpText = 'Sign Up';
lessons = ['Lesson 1', 'Lessons 2'];
login() {
console.log('Login');
}
signUp() {
console.log('Sign Up');
}
}
当你运行上面的组件时,其实组件什么也没有渲染,这是为什么呢?这是因为ng-template只是声明了一个组件模板,而我们还没有用它。你可能会见过这样的模板写法:
<div class="lessons-list" *ngIf="lessons else loading">
...
</div>
<ng-template #loading>
<div>Loading...</div>
</ng-template>
这是一个很常见的写法,当我们在ajax请求数据的时候,可能需要一些loading效果。所以在这里是相当于在请求完成之前,声明使用由ng-template声明的模板。当然,这种写法也可以:
<div class="lessons-list" [ngIf]="lessons" [ngIfElse]="loading">
...
</div>
<ng-template #loading>
<div>Loading...</div>
</ng-template>
- 多重指令
当我们同时使用ngIf与ngFor指令的时候,猜猜会怎样呢?
<div class="lesson" *ngIf="lessons"
*ngFor="let lesson of lessons">
<div class="lesson-detail">
{{lesson | json}}
</div>
</div>
试试运行下,你会发现控制台会报错:
Uncaught Error: Template parse errors:
Can't have multiple template bindings on one element. Use only one attribute
named 'template' or prefixed with *
简单理解下就是不能同时在同一个dom元素上的。开发vue组件时,如果没有用一个root容器包裹就会报错。显然,这些会增加多余的dom元素。那么在Angular中,使用ng-container就不会存在这个问题,如下:
<ng-container *ngIf="lessons">
<div class="lesson" *ngFor="let lesson of lessons">
<div class="lesson-detail">
{{lesson | json}}
</div>
</div>
</ng-container>
- 动态插槽ngTemplteOutlet
熟悉vue开发的同学知道,vue中有一个插槽的概念,这里是做类别学习,借用这个概念会增加你对ngTemplateOutlet的理解。使用ng-container跟ngTemplateOutlet,可以在组件的任何地方动态插入你想要的模板:
<ng-container *ngTemplateOutlet="loading"></ng-container>
这里同时要说的是ngTemplateOutlet跟声明它的组件享有同一个作用域。