前面提到了Angular的Directive指令。现在用指令完成一个小功能。

新建指令

ng genrate directive directiveName

1
2
3
4
5
6
7
8
@Directive({
selector: '[appClickOutSide]'
})
export class ClickOutSideDirective {

constructor(
) { }
}

在构造函数中导入ElementRef来获取对实际DOM的引用

改造后👇

1
2
3
4
5
6
7
8
9
@Directive({
selector: '[appClickOutSide]'
})
export class ClickOutSideDirective {

constructor(
private el: ElementRef
) { }
}

[scode type=”blue”]
因为官方不推荐直接操控DOM,如果非要操控也建议使用Renderer2,这里因为只涉及判断是否当前宿主DOM所以不冲突
[/scode]

事件发射

监听到宿主DOM以外的点击事件时。需要朝外部发射信号需要用到EventEmitter()

1
2
@Output()
public clickOutSide = new EventEmitter();

绑定监听点击事件

需要监听宿主外的点击事件这里需要用到 @Hostlisener修饰器,因为需要全局监听,这里用到@Hostlistener的document: || window:指令
因为还需要判断当前点击DOM是否在宿主DOM内。用到了DOM-API的contains
代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { Directive, ElementRef, HostListener, Output, EventEmitter } from '@angular/core';

@Directive({
selector: '[appClickOutSide]'
})
export class ClickOutSideDirective {

constructor(
private el: ElementRef
) { }

@Output('appClickOutSide')
public clickOutside = new EventEmitter();

@HostListener('document:click', ['$event.target'])
public onMouseClick(targetElement) {
const clickedInside = this.el.nativeElement.contains(targetElement);
if(!clickedInside) {
this.clickOutside.emit(null);
}
}
}

调用

html:
<p appHighlight (appClickOutSide)="demo('xxx')">测试代码</p>
TS:

1
2
3
demo(xx){
console.log('点击了外部', xx);
}

因为指令中的EventEmitter弹出为NUll,这里可以附加自定义参数做更多事情.