Angular2: как использовать наблюдаемые для окна debounce: изменить размер

поэтому я пытаюсь выяснить способ дебюта окна: изменить размер событий с помощью наблюдаемых, поэтому некоторая функция будет вызываться только после того, как пользователь остановил окно изменения размера или какое-то время прошло без изменения размера (скажем, 1 сек.).

https://plnkr.co/edit/cGA97v08rpc7lAgitCOd

import {Component} from '@angular/core'

@Component({
  selector: 'my-app',
  providers: [],
  template: `
    <div (window:resize)="doSmth($event)">
      <h2>Resize window to get number: {{size}}</h2>

    </div>
  `,
  directives: []
})
export class App {
  size: number;
  constructor() {
  }

  doSmth(e: Event) {
    this.size = e.target.innerWidth;
  }
}

- просто простой пример, который использует окно: изменение размера и показывает, что он реагирует мгновенно (используйте "Предварительный запуск в отдельном окне" ).

Ответ 1

Я думаю, что вы не можете разгадать этот путь с помощью наблюдаемого. На самом деле, такие вещи не поддерживаются прямо сейчас, но для этого есть открытая проблема:

Чтобы достичь своей цели, вы можете напрямую использовать Observable.fromEvent для получения наблюдаемого для этого события. Таким образом, вы можете применить оператор debounceTime к этому наблюдаемому.

Вот пример:

@Component({
  (...)
})
export class App {
  size: number;
  constructor() {
    Observable.fromEvent(window, 'resize')
        .debounceTime(1500)
        .subscribe((event) => {
          this.doSmth(event);
        });
  }

  doSmth(e: Event) {
    console.log('do smth');
    this.size = e.target.innerWidth;
  }
}

Смотрите этот plunkr: https://plnkr.co/edit/uVrRXtnZj8warQ3qUTdN?p=preview

Ответ 2

В одном из наших приложений у нас также была реализация, которую предлагает Thierry Templier, но я заметил, что обнаружение угловых изменений запускает (много) при изменении размера окна, что замедляет изменение нашего приложения при изменении размера.

Исправлено с помощью зоны и темы, например так:

private changeSubject = new Subject<number>();

constructor(private zone: NgZone) {
  this.zone.runOutsideAngular(() => {
    Observable.fromEvent(window, 'resize')
    .debounceTime(1500).distinctUntilChanged().subscribe((e: Event) => {
      this.zone.run(() => {
        this.changeSubject.next(e);
      })
    }
    )
  });
  this.changeSubject.subscribe((e: Event) => { this.doSmth(e); });
}

Смотрите plunker с проблемой здесь (измените размер экрана и посмотрите консоль).

И плункер с исправлением этой проблемы здесь (измените размер экрана и посмотрите консоль).

Ответ 3

Вы можете использовать @HostListener decorator. Это распространенный способ подписки на подобные события.

@Component({
   // ...
})
export class App {
  private changeSize = new Subject();

  constructor() {
    this.changeSize
    .asObservable()
    .pipe(
      throttleTime(1000)
    )
    .subscribe(innerWidth => console.log('innerWidth:', innerWidth));
  }

  @HostListener('window:resize', ['$event.target'])
  public onResize(target) {
    this.changeSize.next(target.innerWidth);
  }
}

Вы можете прочитать больше о @HostListener здесь или здесь.