首页 > 解决方案 > 计时器(用于倒计时)

问题描述

我创建了一个从 5 到 0 的倒计时。它在您单击“开始”按钮时开始:

<html>
 <head>
  <meta charset="utf-8"/>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.js">
  </script>
 </head>
 <body>
<button id="start">START</button>
COUNTDOWN:<span id="countdown"></span>
  <script>
    let start = document.getElementById('start');
    let start_click = rxjs.fromEvent(start, 'click');
    start_click.subscribe(x => console.log('click'));

start_click.pipe(rxjs.operators.first()).subscribe(
  ()=> {
    let time = rxjs.timer(0, 1000).pipe(
      rxjs.operators.skip(0)
    , rxjs.operators.take(6)
    , rxjs.operators.map(x => 5-x)
      );

    time.subscribe(x => console.log('instant', x));
    let countdown = document.getElementById('countdown');
    time.subscribe(x => countdown.innerText = x);
    start.disabled = true;

    let end = time.pipe(
    rxjs.operators.last()
    , rxjs.operators.repeatWhen(() => start_click)
    );

    end.subscribe(x=>start.disabled = false);
    start_click.subscribe(x => start.disabled = true);
    });
  </script>
 </body>
</html>

当再次按下“开始”按钮时,我很难找到如何重置倒计时。我试图添加:

start_click.subscribe(x => countdown.innerText = 5);

但价值是静态的。谢谢。

标签: html

解决方案


第二次单击“开始”后它不起作用的原因是因为您在observablefirst()上使用了运算符。start_click

这意味着 observable 仅在第一次单击时发出,然后完成。

只需删除.pipe(rxjs.operators.first()),您的代码将在您每次单击按钮时工作。

但是,尽可能避免嵌套订阅通常是个好主意。这可以帮助您避免内存泄漏(由于未正确退订)并使代码更易于理解。

您可以通过使用“高阶映射运算符”链接之一来避免使用嵌套订阅。这只是一种奇特的说法:将传入值映射到另一个可观察对象、订阅它并发出这些值的运算符。他们还自动管理这些“内部订阅”。

switchMap每当接收到新值时,操作员将“切换”到新的 observable 。因此,在您的情况下,每当收到新的点击时,都会创建一个新的 5 秒计时器 observable。

简化的代码可能看起来像这样:Working StackBlitz

const start     = document.getElementById('start');
const countdown = document.getElementById('countdown');

const start_click = rxjs.fromEvent(start, 'click');

const time = start_click.pipe(
  tap(() => start.disabled = true),
  switchMap(() => timer(0, 1000).pipe(
    map(x => 5-x),
    take(6),
    finalize(() => start.disabled = false)
  )),
);

time.subscribe(
  x => countdown.innerText = x
);

注意现在只有一个订阅。我们定义了两个不同的 observables,start_click一个是你的点击流,time另一个是你的流,它发出计时器的当前值。time是从start_click流中定义的,因此每当收到新的点击时,都会在后台创建一个新的计时器并发出值。


推荐阅读