在 Angular 中有三种类型的指令:
1. 组件 — 拥有模板的指令。此类指令为最常用的指令。
2. 结构型指令 — 通过添加和移除 DOM 元素改变 DOM 布局的指令。如 ngFor
ngIf
等。
3. 属性型指令 — 改变元素、组件或其它指令的外观和行为的指令。如 ngStyle
等。
指令使用时要在前页加上 *
号。
该指令主要作用于防范空指针错误,比如一个未定义的变量被当成对象使用时会报错。
export class AppComponent {
}
{{currHero.name}}
上面将会抛出错误,原因是 currHero
未定义。但加上指令 ngIf
则可以避免这种错误
{{currHero.a}}
该指令当表达式不为 false
时 DOM 元素不会存在 Document 中。
export class AppComponent {
data: Array = [
{name: 'Tom', age: 18},
{name: 'Sam', age: 15},
{name: 'Lucy', age: 28}
];
getKeys(item){
return Object.keys(item);
}
}
<ul *ngFor='let obj of data">
{{obj.name}}
*ngFor
指令默认不支持循环对象,所以如果需要循环的数据源为对象时,可以使用 Object.keys(item)
的方法将对象的属性转换成数组。
<ul *ngFor="let obj of data">
<li *ngFor="let key of getKeys(obj)">{{key}}li>
ul>
在 ngFor
中可以通过 let
关键字创建了一个名叫 obj
的模版输入变量。
如
模板变量:
- let idx = index
- let odd = odd
- let even = even
- let first = first
- let last = last
trackBy
ngFor指令有时候会性能较差,特别是在大型列表中。对一个条目的一丁点改动、移除或添加,都会导致级联的 DOM 操作。
比如,当通过重新从服务器来刷新通讯录,刷新后的列表可能包含很多以前显示过的联系人。但在 Angular 看来,它不知道哪些是以前就存在过的,只能清理旧列表、舍弃那些DOM元素,并用新的DOM元素来重建一个新列表。
解决这个问题,可以通过追踪函数来避免这种折腾。追踪函数会告诉 Angular 当重新获取数据时,由于id没有变,Angular 就不会去删除原来的dom,只会更新其中的内容,不同的id再添加新的dom。效率就能提升了
trackByName(index, obj) {
return obj.name;
}
<ul *ngFor="let obj of data; trackBy:trackByName">
<span>{{obj.name}}span>
ul>
ngSwitch
<span [ngSwitch]="userName">
<span *ngSwitchCase="'张三'">张三span>
<span *ngSwitchCase="'李四'">李四span>
<span *ngSwitchCase="'王五'">王五span>
<span *ngSwitchCase="'赵六'">赵六span>
<span *ngSwitchDefault>龙大span>
span>
highlight.directive.ts
import {Directive, ElementRef} from '@angular/core';
@Directive({
selector: '[hl]'
})
export class HighlightDirective {
constructor(el: ElementRef) {
el.nativeElement.style.backgroundColor = 'yellow';
}
}
./src/app.module.ts
中将指令添加到 declarations
数组当中import {HighlightDirective} from './directives/highlight.directive';
@NgModule({
declarations: [HighlightDirective]
})
<p hl>{{title}}p>
HostListener
在指令中要对指令的宿主元素添加事件监听需要用到 HostListener
属性装饰器
使用格式:HostListener([事件], [参数]) 事件
//['$event'] 映射到 btn
@HostListener('click', ['$event']) onclick(event) {
console.log(event);
}
上面的事件只作用于当前指令的宿主元素,Angular
也可以监听宿主元素外其它对象的事件。如 window
或 document
对象
//['$event'] 映射到 btn
@HostListener('document:click', ['$event']) onclick(event) {
console.log(event.target);
}
除了用 HostListener
属性装饰器外也可以在指令配置信息中设定:host: {'(document:click)': 'onClick($event)'}
import {Directive, ElementRef} from '@angular/core';
@Directive({
selector: '[hl]',
host: {
'(document:click)': 'onClick($event)'
}
})
export class HighlightDirective {
constructor(el: ElementRef) {
el.nativeElement.style.backgroundColor = 'yellow';
}
onClick(event){
console.log(event.target);
}
}
HostBinding
可以在定义指令的时候动态给指令宿主添加属性
@HostBinding('attr.role') role = 'admin';
也可以在指令配置信息中设定
@Directive({
selector: '[hl]',
host: {
'name': 'dk'
}
})
<p hl="a" attr1="b" attr2="c">{{title}}p>
要想获得指令元素的属性,要用到 @Input
装饰器
export class HighlightDirective {
@Input() hl: string;
@Input() attr1: string;
@Input() attr2: string;
@Input()
set attr3(name: string){
this._name = (name && name.trim()) || 'no name set';
}
get attr3(): string{
return this._name;
}
constructor(el: ElementRef) {
el.nativeElement.style.backgroundColor = 'yellow';
}
@HostListener('click', ['$event']) onclick(event) {
console.log(this.hl, this.attr1, this.attr2);
}
}
当然也可以对属性给别名
export class HighlightDirective {
@Input('hl') attr1: string;
@Input('attr1') attr2: string;
@Input('attr2') attr3: string;
constructor(el: ElementRef) {
el.nativeElement.style.backgroundColor = 'yellow';
}
@HostListener('click', ['$event']) onclick(event) {
console.log(this.attr1, this.attr2, this.attr3);
}
}