指令
申远 2021-03-22
# 指令
# 简介
@Directive()
装饰的类被称为指令。指令可以修改 DOM 结构或修改 DOM 和组件数据模型中某些属性。总体可分为三类:
- 组件:
@Component()
继承自@Directive()
,为某个类关联模板 - 属性型指令:改变元素、组件或其它指令的外观和行为,例如
NgStyle
,NgClass
- 结构型指令:添加和移除 DOM 元素改变 DOM 布局,例如
NgFor
,NgIf
,ngSwitch
# 装饰器
常用选项 | 说明 |
---|---|
selector | css选择器,一般使用属性选择器[attribute] |
# 属性指令
# 初始化指令
使用装饰器初始化指令,ElementRef
可以让此指令获得访问宿主DOM元素的能力,以下指令可以将宿主元素的背景变为黄色
import { Directive, ElementRef } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor(el: ElementRef) {
el.nativeElement.style.backgroundColor = 'yellow';
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 监听事件
@HostListener
装饰器可为DOM添加监听事件,并在事件触发时运行处理方法
- eventName:监听的事件名
- args:事件发生时传递的参数
当然也可以通过原生js的绑定方法进行事件监听,但是当指令销毁时必须卸载事件,否则会内存泄漏。
以下指令可以为宿主DOM添加点击事件,并为事件传递参数$event
和指令的传入参数name
,虽然执行方法中可以直接通过this访问,不过我这里是为了测试参数中name指向的问题🥶
@Directive({ selector: '[appHighlight]' })
export class HighlightDirective{
@Input('appHighlight') name:string;
constructor() { }
@HostListener('click',['$event','name'])
click(e:MouseEvent,params){
console.log(e.target);
console.log(params);
}
@HostListener('window:keydown', ['$event'])
handleKeyDown(event: KeyboardEvent) {
console.log(event)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 添加属性、样式
@HostBinding
装饰器可以为宿主元素添加样式、属性等。
@HostBinding('class.valid') get valid(){
return true
}
@HostBinding('attr.haha') haha = 'haha'
@HostBinding('style.color') color = 'red'
1
2
3
4
5
2
3
4
5
# 为指令输入参数
如上面的例子,使用@Input
装饰属性。用法与组件一致,输出属性@Output
的用法也是一致的
@Directive({ selector: '[appHeight]' })
export class NameDirective implements OnInit {
@Input('appHeight') name:string;
@Output() costumeClick = new EventEmitter<any>();
@HostListener('click',['$event','name']) click(e:MouseEvent,params){
this.costumeClick.emit(e.target)
}
}
// <div [appHeight]="params" (costumeClick)="methods($event)"></div>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 结构指令
结构型指令的职责是 HTML 布局。 它们塑造或重塑 DOM 的结构,比如添加、移除或维护这些元素
# *ngIf的原理
首先做一下*ngIf
(移除)和[style.display]
(隐藏)的区别说明
*ngIf | [style.display] | |
---|---|---|
显示/隐藏 | 添加/删除DOM | block/none |
内存和性能 | 负担较小 | 负担较大 |
响应速度 | 慢(相对而言) | 快 |
对于简单段落而言,隐藏和移除差异不大。但是隐藏元素时,组件的行为还在继续,如绑定的事件、变更检测。虽然不可见,但还是占用资源。从响应速度看,因为之前的状态一直保留,所以可以随时显示,不需要做初始化。
# 星号*前缀
angular内部会自己翻译带*的指令
<div *ngIf="hero" class="name">{{hero.name}}</div>
<--等于-->
<ng-template [ngIf]="hero">
<div class="name">
{{hero.name}}
</div>
</ng-template>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 自定义结构指令
定义一个与*ngIf
相反的unless
结构指令,在参数为flase
时显示内容。通过上面的方法创建一个指令,不同的是任何结构指令都会需要@input
、TemplateRef
、 ViewContainerRef
@Directive({ selector: '[appUnless]' })
export class UnlessDirective{
constructor(
private view:ViewContainerRef,
private temp:TemplateRef<any>
){}
@Input() set appUnless(val:Boolean){
if (!val) {
this.view.createEmbeddedView(this.temp);
}else if(val){
this.view.clear()
}
};
}
// <div *appUnless="flag">test</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 案例:输入框限制首位空格
import { Directive, ElementRef, HostListener } from '@angular/core';
import { NgControl } from '@angular/forms';
@Directive({ selector: '[input-trim]' })
export class InputTrimDirective {
constructor(private el: ElementRef, private control: NgControl) {}
@HostListener('keyup') onkeyup() {
this.control.control.setValue(this.el.nativeElement.value.trim());
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10