Angular 2 — Таймер обратного отсчета

Я хочу сделать таймер обратного отсчета в Angular 2, который начинается с 60 (т.е. 59, 58,57 и т. д.)

Для этого у меня есть следующее:

constructor(){
  Observable.timer(0,1000).subscribe(timer=>{
  this.counter = timer;
});
}

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


person Folky.H    schedule 11.06.2017    source источник


Ответы (2)


Есть много способов добиться этого, основным примером является использование оператора take.

import { Observable, timer } from 'rxjs';
import { take, map } from 'rxjs/operators';

@Component({
   selector: 'my-app',
   template: `<h2>{{counter$ | async}}</h2>`
})
export class App {
   counter$: Observable<number>;
   count = 60;

   constructor() {
     this.counter$ = timer(0,1000).pipe(
       take(this.count),
       map(() => --this.count)
     );
   }
}

Лучший способ - создать встречную директиву!

import { Directive, Input, Output, EventEmitter, OnChanges, OnDestroy } from '@angular/core';

import { Subject, Observable, Subscription, timer } from 'rxjs';
import { switchMap, take, tap } from 'rxjs/operators';

@Directive({
  selector: '[counter]'
})
export class CounterDirective implements OnChanges, OnDestroy {

  private _counterSource$ = new Subject<any>();
  private _subscription = Subscription.EMPTY;

  @Input() counter: number;
  @Input() interval: number;
  @Output() value = new EventEmitter<number>();

  constructor() {

    this._subscription = this._counterSource$.pipe(
      switchMap(({ interval, count }) =>
        timer(0, interval).pipe(
          take(count),
          tap(() => this.value.emit(--count))
        )
      )
    ).subscribe();
  }

  ngOnChanges() {
    this._counterSource$.next({ count: this.counter, interval: this.interval });
  }

  ngOnDestroy() {
    this._subscription.unsubscribe();
  }

}

Использование:

<ng-container [counter]="60" [interval]="1000" (value)="count = $event">
  <span> {{ count }} </span>
</ng-container>

Вот живой stackblitz

person Murhaf Sousli    schedule 11.06.2017
comment
Изменение внешнего состояния изнутри составного наблюдаемого редко бывает хорошей идеей, а здесь в этом нет необходимости. Альтернатива: Observable.timer(0, 1000).map(value => 60 - value).takeWhile(value => value > 0) - person cartant; 12.06.2017
comment
@cartant это не штат. это просто таймер обратного отсчета - person Murhaf Sousli; 12.06.2017
comment
как я могу добиться этого, когда счетчик достигает 0, он снова будет пересчитывать до 10. я имею в виду на моем дисплее. я использую для отображения числа 10 и запускаю обратный отсчет до 9, 8, 7, 6, 5, 4 ... и так далее, пока он не достигнет 0. и когда он достигнет нуля, он снова начнет обратный отсчет до 10. - person Jydon Mah; 20.11.2017
comment
@JydonMah есть оператор repeat(), который можно использовать в конце цепочки. - person Murhaf Sousli; 20.11.2017
comment
спасибо за этого человека, я добавляю его в конец кода, но он по-прежнему имеет отрицательное значение. Можете ли вы предоставить рабочий пример для него? кажется, у меня проблемы с выяснением. кстати, я просто новичок в angular и машинописном тексте :) - person Jydon Mah; 21.11.2017
comment
@MurhafSousli Есть ли какое-то встроенное свойство или что-то альтернативное, которое я мог бы использовать для минут и секунд? как обратный отсчет MM:SS? - person Murlidhar Fichadia; 16.01.2018
comment
Могу ли я добиться этого без реализации ‹h2›{{countDown | асинхронно}}‹/h2› в html? - person IntoTheDeep; 19.01.2018
comment
@MurlidharFichadia, ты можешь сделать трубу, которая превратит секунды в минуты. - person karoluS; 29.08.2018
comment
Как проверить, достиг ли счетчик 0? - person Shrinivas; 06.07.2020
comment
@Shrinivas Добавьте оператора для проверки счета map(() => if (this.count === 0)) - person Murhaf Sousli; 07.07.2020

Импортировать в компонент:

import { Observable } from "rxjs/Observable";
import "rxjs/add/observable/timer";
import "rxjs/add/operator/finally";
import "rxjs/add/operator/takeUntil";
import "rxjs/add/operator/map";

Функция обратного отсчета:

countdown: number;
 startCountdownTimer() {
    const interval = 1000;
    const duration = 10 * 1000;
    const stream$ = Observable.timer(0, interval)
      .finally(() => console.log("All done!"))
      .takeUntil(Observable.timer(duration + interval))
      .map(value => duration - value * interval);
    stream$.subscribe(value => this.countdown = value);
  }

HTML:

<div class="panel panel-default">
  <div class="panel-heading">
    <h2 class="panel-title">Countdown timer</h2>
  </div>
  <div class="panel-body">
    <div>
      <label>value: </label> {{countdown}}
    </div>
    <div>
      <button (click)="startCountdownTimer()" class="btn btn-success">Start</button>
    </div>
  </div>
</div>
person Mohammad Daliri    schedule 22.01.2018
comment
Как остановить таймер? - person Asif; 16.11.2018
comment
@Asif, отписавшись от наблюдаемого потока $. - person Umair Razzaq; 28.03.2021