我正在进行一个角形9测试应用程序,我使用RxJS作为倒计时计时器(在containers\scoreboard\time\time.component.ts中),而计时器似乎没有显示。stopTimer()函数应该在停止计时器的秒数上停止它。在正确的答案被选择之后,计时器应该停止,计时器应该在问题之间重置。每个问题经过的时间应该保存到elapsedTimes数组中。请在Stackblitz: TimeComponent上看到我的定时器代码:https://stackblitz.com/edit/angular-9-quiz-app。谢谢。
下面的代码是我第一次开始用RxJS构建一个倒计时时钟。我最近的代码是在Stackblitz上的。
countdownClock() {
this.timer = interval(1000)
.pipe(
takeUntil(this.isPause),
takeUntil(this.isStop)
);
this.timerObserver = {
next: (_: number) => {
this.timePerQuestion -= 1;
...
}
};
this.timer.subscribe(this.timerObserver);
}
goOn() {
this.timer.subscribe(this.timerObserver);
}
pauseTimer() {
this.isPause.next();
// setTimeout(() => this.goOn(), 1000)
}
stopTimer() {
this.timePerQuestion = 0;
this.isStop.next();
}我在我的stopTimer()中使用了stopTimer()和pauseTimer(),这样就可以从不同的组件调用它们。
发布于 2020-05-31 20:59:38
我已经修好了你的垃圾桶。基于对时间服务方法的调用,您的计时器将运行。
也不需要在拆卸逻辑中设置经过的时间。当计时器停止时,它会自动推送。
Stackblitz网址:- https://stackblitz.com/edit/angular-9-quiz-app-er3pjn
倒计时方法:-
countdownClock() {
const $ = document.querySelector.bind(document);
const start$ = this.timerService.isStart.asObservable().pipe(shareReplay(1));
const reset$ = this.timerService.isReset.asObservable();
const stop$ = this.timerService.isStop.asObservable();
const markTimestamp$ = fromEvent($("#mark"), "click");
const continueFromLastTimestamp$ = fromEvent($("#continue"), "click");
start$.subscribe((data) => console.log(data));
this.timeLeft$ = concat(start$.pipe(first()), reset$).pipe(
switchMapTo(
timer(0, 1000).pipe(
scan((acc, crt) => acc > 0? acc - 1: acc, this.timePerQuestion),
)
),
takeUntil(stop$.pipe(skip(1))),
repeatWhen(completeSbj =>
completeSbj.pipe(
switchMapTo(
start$.pipe(
skip(1),
first()
)
)
)
)
).pipe(tap((value)=>this.timerService.setElapsed(this.timePerQuestion-value)));在记分板组件参数订阅中,我已经重置了计时器,所以每当问题发生变化时,它都会重置。
发布于 2020-05-18 08:08:25
就像每一个复杂的问题一样,你必须把它分解成更小的、可消化的问题。
因此,我创建了一个StackBlitz演示,该演示重新创建了基本功能:
以下是此代码:
const $ = document.querySelector.bind(document);
const start$ = fromEvent($('#start'), 'click').pipe(shareReplay(1));
const reset$ = fromEvent($('#reset'), 'click');
const stop$ = fromEvent($('#stop'), 'click');
const markTimestamp$ = fromEvent($('#mark'), 'click');
const continueFromLastTimestamp$ = fromEvent($('#continue'), 'click');
const src$ = concat(
start$.pipe(first()),
reset$
).pipe(
switchMapTo(
timer(0, 1000)
.pipe(
takeUntil(markTimestamp$),
repeatWhen(
completeSbj => completeSbj.pipe(switchMapTo(
continueFromLastTimestamp$.pipe(first())
))
),
scan((acc, crt) => acc + 1000, 0)
)
),
takeUntil(stop$),
repeatWhen(completeSbj => completeSbj.pipe(switchMapTo(start$.pipe(skip(1), first()))))
).subscribe(console.log)让我们看看每一个相关的部分。
concat(
start$.pipe(first()),
reset$
).pipe(switchMapTo(timer(...)))只有当timer之前还没有启动(start$.pipe(first()))或者用户希望重置所有内容(reset$)时,它才会从0开始计数。
concat(a$, b$)确保b$不能发出,除非a$完成。
timer(0, 1000)
.pipe(
takeUntil(markTimestamp$),
repeatWhen(
completeSbj => completeSbj.pipe(switchMapTo(
continueFromLastTimestamp$.pipe(first())
))
),
scan((acc, crt) => acc + 1000, 0)
)我们希望计时器处于活动状态,直到markTimestamp$发出。当发生这种情况时,源(timer(0, 1000))将被取消订阅。使用repeatWhen,我们可以决定何时重新订阅timer。也就是说,当continueFromLastTimestamp$.pipe(first())发射的时候。重要的是我们使用first(),否则源可能会被多次重新订阅。
将scan((acc, crt) => acc + 1000, 0)放在repeatWhen之后确保最后一个时间戳不会丢失。例如,计时器可能从X开始,在X+5,用户触发markTimestamp$,然后在X + 100,用户触发continueFromLastTimestamp$。发生这种情况时,定时器将发出X+6。
takeUntil(stop$),
repeatWhen(completeSbj => completeSbj.pipe(switchMapTo(start$.pipe(skip(1), first()))))计时器应该处于活动状态,直到stop$发出。然后,只有当用户再次触发start$时,它才能重新启动。之所以使用skip(1),是因为我们不使用start$的shareReplay使用的ReplaySubject所缓存的值,而使用first()是因为源只应该是一次。
https://stackoverflow.com/questions/61855688
复制相似问题