Sekali waktu, saya menulis artikel tentang bekerja dengan EventManager di Angular . Di dalamnya, saya berbicara tentang bagaimana Anda dapat menyimpan sintaks yang biasa untuk langganan acara, sambil menghindari pemicu yang tidak perlu memeriksa perubahan pada acara yang sering dan sensitif.
Namun, metode yang saya jelaskan rumit dan sulit dipahami. Saatnya menulis ulang penyaringan pada dekorator.

Ulangan singkat
Bagi yang belum membaca dan tidak ingin membaca artikel sebelumnya, ringkasan masalahnya:
- Sudut memungkinkan deklaratif berlangganan acara di templat (
(eventName)
) dan melalui dekorator ( @HostListener(โeventNameโ)
). - Dengan strategi validasi perubahan,
OnPush
Angular akan menjalankan pemeriksaan jika terjadi peristiwa yang kami langgani dengan cara ini. - Acara seperti
scroll
, mousemove
, drag
dipicu sangat sering. Dalam praktiknya, Anda hanya perlu merespons beberapa di antaranya (misalnya, ketika pengguna menggulir wadah ke akhir - memuat elemen baru). - Sudut menangani pemrosesan acara
EventManager
menggunakan yang disediakan EventManagerPlugin
. - Angular , .
. . .
Angular (keydown.ctrl.enter
).
, EventManager
. . Angular , EVENT_MANAGER_PLUGINS
. , , . addEventListener
, , , , , . .
preventDefault
stopPropagation
. , , , :
@Injectable()
export class StopEventPlugin {
supports(event: string): boolean {
return event.split('.').includes('stop');
}
addEventListener(
element: HTMLElement,
event: string,
handler: Function
): Function {
const wrapped = (event: Event) => {
event.stopPropagation();
handler(event);
};
return this.manager.addEventListener(
element,
event
.split('.')
.filter(v => v !== 'stop')
.join('.'),
wrapped,
);
}
}
. , :
- Angular, .
- .
- .
, NgZone
:
@Injectable()
export class SilentEventPlugin {
supports(event: string): boolean {
return event.split('.').includes('silent');
}
addEventListener(
element: HTMLElement,
event: string,
handler: Function
): Function {
return this.manager.getZone().runOutsideAngular(() =>
this.manager.addEventListener(
element,
event
.split('.')
.filter(v => v !== 'silent')
.join('.'),
handler,
),
);
}
}
, .
, -. /, this
.
, , . โ - , , . $event
@HostListener
. :
export function shouldCall<T>(
predicate: Predicate<T>
): MethodDecorator {
return (_target, _key, desc: PropertyDescriptor) => {
const {value} = desc;
desc.value = function(this: T, ...args: any[]) {
if (predicate.apply(this, args)) {
value.apply(this, args);
}
};
};
}
. โ - Angular, .
Angular 10 Ivy , markDirty(this)
. , - NgZone
. . , . , NgZone
, :
@Injectable()
export class ZoneEventPlugin {
supports(event: string): boolean {
return event.split('.').includes('init');
}
addEventListener(
_element: HTMLElement,
_event: string,
handler: Function
): Function {
const zone = this.manager.getZone();
const subscription = zone.onStable.subscribe(() => {
subscription.unsubscribe();
handler(zone);
});
return () => {};
}
}
โ .init
, ( , ). @HostListener(โprop.initโ, [โ$eventโ])
:
export function shouldCall<T>(
predicate: Predicate<T>
): MethodDecorator {
return (_, key, desc: PropertyDescriptor) => {
const {value} = desc;
desc.value = function() {
const zone = arguments[0] as NgZone;
Object.defineProperty(this, key, {
value(this: T, ...args: any[]) {
if (predicate.apply(this, args)) {
zone.run(() => {
value.apply(this, args);
});
}
},
});
};
};
}
, . , . Ivy.

, , :
https://stackblitz.com/edit/angular-event-filter-decorator
, , , . , , . async
Observable
:
<p *ngFor="let item of service.items$ | async">{{item}}</p>
, :
export function scrolledToBottom(
{scrollTop, scrollHeight, clientHeight}: HTMLElement
): boolean {
return scrollTop >= scrollHeight - clientHeight - 20;
}
@Component({
selector: 'awesome-component',
templateUrl: './awesome-component.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AwesomeComponent {
constructor(@Inject(Service) readonly service: Service) {}
@HostListener('scroll.silent', ['$event.currentTarget'])
@HostListener('init.onScroll', ['$event'])
@shouldCall(scrolledToBottom)
onScroll() {
this.service.loadMore();
}
}
. :
https://stackblitz.com/edit/angular-event-filters-scroll
, . CustomEvent
, . .
(1 gzip) open-source- @tinkoff/ng-event-filters
. Angular 10 2.0.0, markDirty(this)
, Angular 4.
npm-
-, open source, ? Angular Open-source Library Starter, . CI, , , CHANGELOG, .