Angular 2 - 倒计时计时器

16

我愿意在Angular 2中制作一个倒计时器,从60开始(即59、58、57等)

为此,我有以下代码:

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

上述代码每秒钟都会执行一次,这很好; 但是,它升序计时到无限数字。我不确定是否有一种方法可以调整它,以便我可以拥有一个倒计时器。

2个回答

38

有许多方法可以实现这一点,基本示例是使用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


1
在组合的可观察对象内更改外部状态很少是一个好主意,在这里也是不必要的。一种替代方法:Observable.timer(0, 1000).map(value => 60 - value).takeWhile(value => value > 0) - cartant
@cartant 这不是一个状态,它只是一个倒计时计时器。 - Murhaf Sousli
1
@JydonMah 在链的末尾可以使用repeat()运算符。 - Murhaf Sousli
1
谢谢你的帮助,我把它添加到代码末尾,但它仍然是负值。你能提供一个可行的例子吗?似乎我还有些困惑。顺便说一下,我刚开始学习Angular和TypeScript :) - Jydon Mah
@MurlidharFichadia 你可以创建一个管道,将秒转换为分钟。 - karoluS
显示剩余5条评论

2

组件导入:

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>

如何停止计时器? - Asif
通过取消订阅 "stream$" 可观察对象来取消订阅。 - Umair Razzaq

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接