提升Angular技能的5个技巧

今年夏天,我和Roma推出了一系列推文,其中包含有用的Angular技巧和窍门。这项倡议受到了社区的热烈欢迎,我决定写一篇总结文章。这是我与开发者分享的5条建议。这些技巧将通过我的Twitter上的特定示例得到支持他们将帮助您提高技能,或者至少为您提供一些实用技巧。

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 . , ! .

. , . !




All Articles