html - 计时器(用于倒计时)
问题描述
我创建了一个从 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);
但价值是静态的。谢谢。
解决方案
第二次单击“开始”后它不起作用的原因是因为您在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
流中定义的,因此每当收到新的点击时,都会在后台创建一个新的计时器并发出值。
推荐阅读
- php - 使事件发布在事件结束时间之后过期
- android - 数据绑定不更新视图文本
- reactjs - 如何在 React 中使用计算属性名称来设置状态
- swift - 取消初始化呈现的视图控制器
- ember.js - 强制 ember 存储跳过缓存并从 API 调用中获取数据
- java - 运行 jar 文件时在 docker 容器中加载 .so 库时出错
- kubernetes - 如何将 Kubernetes 服务类型“LoadBalancer”与特定云负载均衡器集成
- python - 扩展 code.InteractiveInterpreter 与历史,选项卡完成,
- python - Pyro4:在远程子对象上调用方法而不尝试返回子对象
- javascript - 如果我使用两个“if”语句而不仅仅是一个“if/else”语句,为什么二进制搜索算法不起作用?