实现思路
- 指令定义:使用Angular的
@Directive
装饰器定义一个新的指令。
- 属性绑定:利用
@Input()
装饰器绑定输入属性,用于从组件传递数据到视图。
- 事件绑定:使用
@Output()
装饰器绑定输出属性,用于从视图传递数据变化通知到组件。
- 变化检测:合理利用Angular的变化检测机制,避免不必要的循环。例如,使用
ChangeDetectorRef
来手动触发变化检测,并且通过NgZone
控制检测的执行范围。
- 性能优化:在复杂场景下,通过减少不必要的DOM操作和变化检测频率来提升性能。例如,使用防抖(Debounce)或节流(Throttle)技术处理频繁触发的事件。
关键代码点
- 指令定义与输入输出绑定:
import { Directive, Input, Output, EventEmitter } from '@angular/core';
@Directive({
selector: '[myTwoWayBinding]'
})
export class MyTwoWayBindingDirective {
@Input('myTwoWayBinding') value: any;
@Output('myTwoWayBindingChange') valueChange = new EventEmitter<any>();
constructor() {}
}
- 在模板中使用指令:
<input type="text" [myTwoWayBinding]="data" (myTwoWayBindingChange)="data = $event">
- 处理视图变化并通知组件:
import { Directive, Input, Output, EventEmitter, ElementRef, HostListener } from '@angular/core';
@Directive({
selector: '[myTwoWayBinding]'
})
export class MyTwoWayBindingDirective {
@Input('myTwoWayBinding') value: any;
@Output('myTwoWayBindingChange') valueChange = new EventEmitter<any>();
constructor(private el: ElementRef) {}
@HostListener('input', ['$event.target.value'])
onInputChange(newValue: string) {
if (this.value!== newValue) {
this.value = newValue;
this.valueChange.emit(newValue);
}
}
}
- 手动触发变化检测(可选):
import { Directive, Input, Output, EventEmitter, ElementRef, HostListener, ChangeDetectorRef } from '@angular/core';
@Directive({
selector: '[myTwoWayBinding]'
})
export class MyTwoWayBindingDirective {
@Input('myTwoWayBinding') value: any;
@Output('myTwoWayBindingChange') valueChange = new EventEmitter<any>();
constructor(private el: ElementRef, private cdRef: ChangeDetectorRef) {}
@HostListener('input', ['$event.target.value'])
onInputChange(newValue: string) {
if (this.value!== newValue) {
this.value = newValue;
this.valueChange.emit(newValue);
this.cdRef.markForCheck(); // 手动标记变化检测
}
}
}
- 利用NgZone控制变化检测范围(可选):
import { Directive, Input, Output, EventEmitter, ElementRef, HostListener, ChangeDetectorRef, NgZone } from '@angular/core';
@Directive({
selector: '[myTwoWayBinding]'
})
export class MyTwoWayBindingDirective {
@Input('myTwoWayBinding') value: any;
@Output('myTwoWayBindingChange') valueChange = new EventEmitter<any>();
constructor(private el: ElementRef, private cdRef: ChangeDetectorRef, private ngZone: NgZone) {}
@HostListener('input', ['$event.target.value'])
onInputChange(newValue: string) {
this.ngZone.run(() => {
if (this.value!== newValue) {
this.value = newValue;
this.valueChange.emit(newValue);
this.cdRef.markForCheck();
}
});
}
}