هذا الصيف ، أطلقت أنا وروما سلسلة من التغريدات مع النصائح والحيل الزاويّة المفيدة. هذه المبادرة لقيت ترحيبا حارا من قبل المجتمع وقررت كتابة مقال موجز. فيما يلي توصياتي الخمس لمشاركتها مع المطورين. سيتم دعم هذه النصائح بأمثلة محددة من تويتر الخاص بي . سوف يساعدونك في تحسين مهاراتك ، أو على الأقل يقدمون لك بعض النصائح العملية.

1. فهم آلية التحقق من التغيير
هناك العديد من المقالات المتعمقة الرائعة على الإنترنت حول التحقق من التغييرات في Angular. على سبيل المثال ، هذا. لذلك دعونا فقط نركز على الأساسيات ونصل إلى النصائح.
أساسيات
Angular : Default OnPush. tick . Zone.js, . view , .
Default vs OnPush
, Default. , , OnPush. . , OnPush .
@HostListener Angular OnPush. , RxJS? ChangeDetectorRef markForCheck(), . async , . .
:
<div *ngIf="stream$ | async as result">
…
</div>, falsy-? ngIf . , :
@Directive({
selector: "[ngLet]"
})
export class LetDirective<T> {
@Input()
ngLet: T;
constructor(
@Inject(ViewContainerRef) container: ViewContainerRef,
@Inject(TemplateRef) templateRef: TemplateRef<LetContext<T>>
) {
container.createEmbeddedView(templateRef, new LetContext<T>(this));
}
}NgZone
OnPush, . NgZone .runOutsideAngular(). . Default . , mousemove scroll. RxJS- : — , — , :
class ZonefreeOperator<T> implements Operator<T, T> {
constructor(private readonly zone: NgZone) {}
call(observer: Observer<T>, source: Observable<T>): TeardownLogic {
return this.zone.runOutsideAngular(
() => source.subscribe(observer)
);
}
}
export function zonefull<T>(zone: NgZone): MonoTypeOperatorFunction<T> {
return map(value => zone.run(() => value));
}
export function zonefree<T>(zone: NgZone): MonoTypeOperatorFunction<T> {
return source => source.lift(new ZonefreeOperator(zone));
},
@HostListener, —EventManagerPlugin. open-source- ng-event-plugins. . .
2. RxJS
RxJS — . , . , —
— . , , :
, , . CSS RxJS:
@Directive({
selector: "[sticky]",
providers: [DestroyService]
})
export class StickyDirective {
constructor(
@Inject(DestroyService) destroy$: Observable<void>,
@Inject(WINDOW) windowRef: Window,
renderer: Renderer2,
{ nativeElement }: ElementRef<HTMLElement>
) {
fromEvent(windowRef, "scroll")
.pipe(
map(() => windowRef.scrollY),
pairwise(),
map(([prev, next]) => next < THRESHOLD || prev > next),
distinctUntilChanged(),
startWith(true),
takeUntil(destroy$)
)
.subscribe(stuck => {
renderer.setAttribute(
nativeElement,
"data-stuck",
String(stuck)
);
});
}
}RxJS Angular- . RxJS , . , , .
, . , RxJS, — . - . ( ).
3. TypeScript
Angular- TypeScript. , , . strict: true. . cannot read property of null undefined is not a function.
TypeScript — , , , . , API. . RxJS- fromEvent:
// currentTarget
export type EventWith<
E extends Event,
T extends FromEventTarget<E>
> = E & {
readonly currentTarget: T;
};
// fromEvent
export function typedFromEvent<
E extends keyof GlobalEventHandlersEventMap,
T extends FromEventTarget<EventWith<GlobalEventHandlersEventMap[E], T>>
>(
target: T,
event: E,
options: AddEventListenerOptions = {},
): Observable<EventWith<GlobalEventHandlersEventMap[E], T>> {
return fromEvent(target, event, options);
} , , currentTarget — , .
API, , , . , .
TypeScript. , . : any. , unknown.
TypeScript, . . , , , : , , — number. TypeScript , runtime :
export function assert<T, K extends keyof T>(
assertion: (input: T[K]) => boolean,
messsage: string
): PropertyDecorator {
return (target, key) => {
Object.defineProperty(target, key, {
set(this: T, initialValue: T[K]) {
let currentValue = initialValue;
Object.defineProperty(this, key, {
get(): T[K] {
return currentValue;
},
set(this: T, value: T[K]) {
console.assert(assertion(value), messsage);
currentValue = value;
}
});
}
});
};
} , super()? Angular , :
— . Web Audio API Angular, . .
4. Dependency Injection.
DI — , Angular . , . .
, DI, .
RxJS
, RxJS. , , , . Angular :
@Injectable()
export class DestroyService extends Subject<void> implements OnDestroy {
ngOnDestroy() {
this.next();
this.complete();
}
} DI. requestAnimationFrame . . , :
DI — . window navigator — Angular Universal . , . . . WINDOW DOCUMENT:
export const WINDOW = new InjectionToken<Window>(
'An abstraction over global window object',
{
factory: () => {
const {defaultView} = inject(DOCUMENT);
if (!defaultView) {
throw new Error('Window is not available');
}
return defaultView;
},
},
);, open-source-, . Angular Universal - . , , - .
. DI . .
5. ,
Angular . . . : . , , .

— « »? ngOnChanges . -, , , - .
— . - , .
— , . . , . , — , .
, , .
Template reference variables
Angular @ViewChild. , :
<input #input>
<button (click)="onClick(input)">Focus</button>template reference variable , . . .
, DOM-, ? @ViewChild(MyComponent, {read: ElementRef}), , exportAs:
@Directive({
selector: '[element]',
exportAs: 'elementRef',
})
export class ElementDirective<T extends Element> extends ElementRef<T> {
constructor(@Inject(ElementRef) {nativeElement}: ElementRef<T>) {
super(nativeElement);
}
} ComponentFactoryResolver . , ngComponentOutlet? . — , Dependency Injection. ngComponentOutlet Injector, .
, , . . .
, . open-source- ng-polymorpheus. , , ngTemplateOutlet, ngContentOutlet . , ! .
. , . !