在上一章中介绍了如何建立客制化的 attribute directive 与使用,而本章将会介绍如何建立 structural directives,那就接着往下看吧!
本章一样会利用 Angular 官方文档的例子建立一个范例,范例内容是会建立一个 UnlessDirective
以及该如何设置他的条件值,这个 UnlessDirective
与 *ngIf 相法,当为 true 时会显示 NgIf 的内容反之则显示 UnlessDirective
的
首先利用 Angular CLI 建立一个 directive
ng generate directive unless
ng g d unless
在 @angular/core
中引入 Input
, TemplateRef
, ViewContainerRef
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({ selector: '[appUnless]'})
export class UnlessDirective {
}
在 unless.directive.ts 的 constructor 中 inject TemplateRef 与 ViewContainerRef 成为他的私有变量
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({ selector: '[appUnless]' })
export class UnlessDirective {
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef
) {}
}
UnlessDirective 会从 Angular 生成的 <ng-template>
中创建一个 embedded view 并将他插入到宿主 element 相邻的地方,而 TemplateRef
可以让你访问到 <ng-template>
的内容,而 ViewContainerRef 可以让你访问 view container。
Note: embedded view 是为 ng-template 中指定的 view node 所创建的 view,简单来说他类似 component 中的 template 所创建出来的 view,但是他没有 component 的元素或数据
,不过他还是属於一个有效的 view,会在检测过程中与其他 view 一样被检测到。
在 unless.directive.ts 中添加一个 property 用来表示是否显示画面,与使用 setter 添加一个 appUnless property。
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({ selector: '[appUnless]' })
export class UnlessDirective {
private hasView = false; // (1)
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef
) {}
@Input() set appUnless(condition: boolean) { // (2)
if (!condition && !this.hasView) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.hasView = true;
} else {
this.viewContainer.clear();
this.hasView = false;
}
}
}
在 app.component.ts 中新增一个 property 与 method
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
condition = false; // (1)
onClick() { // (2)
this.condition = !this.condition;
}
}
在 app.component.html 中使用我们建立的 directive
<!-- app.component.html -->
<div *appUnless="condition">unless display area</div>
<div *ngIf="condition">ngIf display area</div>
<button (click)="onClick()">Click</button>
在画面中可以看到,我们一开始设计的逻辑就是希望要跟 ngIf 相反,所以当 condition = false 时会显示我们刚建立的 directive 满足的区域 unless display area
,反之当点击按钮将 condition 变为 true 时,则会显示 ngIf 的内容 ngIf display area
。
看完上面的例子後应该会了解该怎麽建立自己的 structural directive,但是可能有人会疑问,连自己建立的 structural directive 也要使用星号 ( * )
吗?这个星号是什麽?接着就要来讲解一下这个星号是什麽。
structural directive 上面的星号( * )语法是 Angular 将其解释为更常形式的速记,他会将星号转换成一个 <ng-template>
并将它围绕着宿主元素与他的所有子层,举例来说
<div *ngIf="hero" class="name">{{hero.name}}</div>
当 hero 为 true 时才会显示英雄的名字,而其实 Angular 看到上面的程序後会将它转变为
<ng-template [ngIf]="hero">
<div class="name">{{hero.name}}</div>
</ng-template>
可以看到 Angular 将星号变为一个 <ng-template>
,而 ngIf 变成了他的 property binding,而其他的内容会移动到 <ng-template>
之中,因为 Angular 不会真正的创建 <ng-template>
元素而是指将内部的 <div>
和 comment node placeholder
放到 DOM 中。
而如果 ngIf 为 false 的话则会连 <div>
的内容都不会放在 DOM 中。
看完了 ngIf 的速记用法後,接着来看看 ngFor 会长什麽样子,一样先举个例子
<div *ngFor="let hero of heroes; let i=index; let odd=odd; [class.odd]="odd">
({{i}}) {{hero.name}}
</div>
使用了 ngFor 将 heroes 中的内容迭代的显示在画面上,并使用了之前提到的 ngFor 的一些参数,而这个例子在经过 Angular 转换後会变成
<ng-template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd">
<div [class.odd]="odd">({{i}}) {{hero.name}}</div>
</ng-template>
可以看到他跟 ngIf 一样会将星号变为一个 <ng-template>
并且将 ngFor 变为 property binding,比较不同的是在这个 <ng-template>
中使用了 let
宣告了一个模板输入变量,让他可以被 template 中被引用,在上面的例子中的输入变量是 hero
, i
, 'odd',解析器会将 let hero、let i 和 let odd 转换为 let-hero
、 let-i
和 let-odd
,Angular 会将当前的值在适当的时间点赋予给宣告的输入变量。
<ng-template>
Angular 的 <ng-template>
定义了一个默认不渲染任何东西的 template,可以透过 structural directive 来控制是否要显示 <ng-template>
中定义的内容
<p>Hip!</p>
<ng-template>
<p>Hip!</p>
</ng-template>
<p>Hooray!</p>
可以看到,当我们使用 <ng-template>
将 <p>Hip!</p>
包住,但是没有使用 structural directive 决定他是否要被显示出来,所以在 DOM 中会看到 comment node placeholder
而不是希望呈现的数据。
本章中介绍了如何建立客制化的 structural directive,他相较於建立客制化的 attribute directive 男的多,所以需要了解更多的观念,比如说 Angular 的 view 观念其实非常复杂,这边只有稍微提到而已,如果之後有专案上的需求再回来钻研就好,这边只是大概介绍该如何使用与客制化。
本篇是 directive 的最後一篇,明天将会回头介绍 component 的最後一个例子,动态载入 component,他使用了之前讲到的满多技巧,范例的难度也比较大,那麽就明天来好好的讲解一下吧,那我们就明天见吧。
<<: Day4: Network Access Control List(NACL) 简介与布建
>>: Day16:图形搜寻-深度优先搜寻(Depth-First Search)
今天的影片内容为介绍分析项目清单与表格文件的方法 而在影片的後半部,会带大家离开新手村,爬取一个真正...
上次教到新的容器叫做集合,那听到这个名称有没有想起来在高中时期的数学也有学过集合呢?那时候教到的交集...
前言 我们在Prototypes [上]中介绍了什麽是Prototype也介绍了JavaScript...
Page & Post 傻傻分不清楚 由於前两天在研究 Menu,发现设定 Menu 的时候...
对於WordPress网站来说,快取外挂对网页载入速度的确是有帮助的。 在已经进行一些基本最佳化的网...