我正在创建一个 Angular 响应式应用程序,其中有超过 10 个断点,我必须将元素分组到不同的容器中。考虑到这一点,我相信我无法利用 css mediaQueris,并且我希望在组件中拥有窗口的 innerWidth 属性。
为了获得它,我创建了以下指令,并用它扩展了组件:
import { Directive, NgZone, OnDestroy } from "@angular/core";
import { Subject, fromEvent } from "rxjs";
import { debounceTime, distinctUntilChanged, map, takeUntil } from "rxjs/operators";
@Directive()
export abstract class WindowResizeDirective implements OnDestroy {
winWidth: number = window.innerWidth;
protected destroy$: Subject<boolean> = new Subject();
constructor(private _zone: NgZone) {
this._zone.runOutsideAngular(() => {
fromEvent(window, 'resize').pipe(
debounceTime(300),
map((ev: any) => ev.target.innerWidth),
distinctUntilChanged(),
takeUntil(this.destroy$)
).subscribe(width => {
this._zone.run(() => {
this.winWidth = width;
})
});
});
}
ngOnDestroy(): void {
this.destroy$.next(true);
this.destroy$.complete();
}
}
然而,很多时候我需要使用页面组件的这个指令一次,而不是在页面组件的许多子组件上使用,因此,由于同一个原因 -> 调整窗口大小,会触发很多更改检测周期。您能建议一种提高性能的方法吗?
如有任何建议,我们将不胜感激。
我想这里有一个服务会更好,创建一个调整大小服务来处理跨多个组件的窗口调整大小事件。
使用BehaviorSubject来保存当前窗口宽度
类似这样的:
import { Injectable, NgZone, OnDestroy } from '@angular/core';
import { BehaviorSubject, fromEvent } from 'rxjs';
import { debounceTime, map, takeUntil } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class ResizeService implements OnDestroy {
private windowSize = new BehaviorSubject<number>(window.innerWidth);
private destroy$ = new Subject<void>();
constructor(private zone: NgZone) {
this.zone.runOutsideAngular(() => {
fromEvent(window, 'resize').pipe(
debounceTime(300),
map((event: any) => event.target.innerWidth),
takeUntil(this.destroy$),
).subscribe(width => {
this.zone.run(() => {
this.windowSize.next(width);
});
});
});
}
getWindowSize(): BehaviorSubject<number> {
return this.windowSize;
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
}
将其注入到您的组件中
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
import { ResizeService } from './resize.service';
@Component({
selector: 'app-some-component',
template: `<!-- Your template here -->`,
})
export class SomeComponent implements OnInit, OnDestroy {
private resizeSubscription: Subscription;
winWidth: number;
constructor(private resizeService: ResizeService) {}
ngOnInit() {
this.resizeSubscription = this.resizeService.getWindowSize().subscribe(width => {
this.winWidth = width;
});
}
ngOnDestroy() {
if (this.resizeSubscription) {
this.resizeSubscription.unsubscribe();
}
}
}