【共创季稿事节】秒表应用开发:ArktS 中高精度计时与数组记录
一、引言秒表Stopwatch是日常生活中常用的计时工具广泛用于运动训练、科学实验、烹饪计时等场景。从技术实现角度看秒表应用的核心挑战在于如何实现高精度的计时以及如何管理和显示圈数记录。二、需求分析2.1 功能需求功能 说明开始计时 从零开始正向计时暂停计时 暂停当前计时保留已计时间重置清零 将计时归零同时清空圈数记录计圈功能 记录当前时间作为一圈的耗时圈数列表 显示所有记录的圈数2.2 计时精度设计普通秒表的精度通常为百分之一秒0.01s我们使用厘秒centisecond, 1cs 0.01s作为计时单位1 秒 100 厘秒使用厘秒作为基本单位而非毫秒是因为百分之一秒的精度对绝大多数场景已经足够显示格式更符合日常习惯MM:SS.cs三、核心实现3.1 状态设计State elapsed: number 0; // 经过的厘秒数State isRunning: boolean false;State laps: number[] []; // 圈数记录也是厘秒private timerId: number -1;3.2 计时实现使用 setInterval 每 10ms 触发一次每次增加 1 厘秒this.timerId setInterval(() {this.elapsed;}, 10);为什么是 10ms 而不是 1ms因为 JavaScript/TypeScript 引擎的单线程模型决定了 setInterval 的实际触发间隔不可能精确到 1ms10ms 的间隔在实际运行中误差约 ±2ms对于秒表应用完全可以接受。3.3 时间格式化formatTime(cs: number): string {let minutes Math.floor(cs / 6000);let seconds Math.floor((cs % 6000) / 100);let centiseconds cs % 100;return${minutes 10 ? 0 : }${minutes}:${ seconds 10 ? 0 : }${seconds}.${ centiseconds 10 ? 0 : }${centiseconds};}换算关系1 分钟 6000 厘秒60 × 1001 秒 100 厘秒3.4 计圈功能Button(‘⏺ 计圈’).onClick(() {if (this.isRunning) {this.laps.push(this.elapsed);}})每点击一次计圈按钮将当前的 elapsed 值记录到 laps 数组中。由于 State 的响应式特性laps 数组的变化会自动更新圈数列表 UI。四、圈数列表渲染List() {ForEach(this.laps, (lap: number, idx: number) {ListItem() {Text(第 ${idx 1} 圈)Text(this.formatTime(lap))}})}使用 ForEach 遍历圈数记录将每条记录渲染为列表项。五、生命周期管理5.1 组件销毁时清除定时器Button(‘ 返回’).onClick(() {clearInterval(this.timerId);router.back();})返回主页面时必须清除定时器这是 ArkTS 开发中极易被忽略的细节。如果定时器未被清除即使页面已不可见定时器仍然在后台运行耗费系统资源。六、扩展方向6.1 显示毫秒级精度如果需要更高精度的计时可以将计时单位改为毫秒this.timerId setInterval(() {this.elapsed;}, 1); // 每 1ms 触发但这会带来两个问题一是 setInterval 在单线程环境下无法保证 1ms 精度二是频繁的 UI 刷新会消耗更多资源。通常 10ms厘秒精度是性能和体验的最佳平衡点。6.2 后台计时当应用进入后台时鸿蒙系统可能暂停 setInterval 的执行。对于需要精确计时的场景建议使用系统时间戳Date.now()来计算实际经过的时间startTimer() {this.startTime Date.now();this.timerId setInterval(() {this.elapsed Math.floor((Date.now() - this.startTime) / 10);}, 10);}这样即使定时器被短暂挂起恢复后也能准确计算出经过的时间。七、总结秒表应用的精髓不在于复杂的业务逻辑而在于对定时器的精确控制和对数组数据的有效管理。通过这个案例我们学习了setInterval 实现正向计时厘秒与分钟/秒之间的换算圈数记录的数组管理组件生命周期对定时器的影响秒表背后的记录-存储-展示模式同样适用于运动追踪、实验记录、时间日志等应用场景。