TypeScript秒表返回NaN及续跑功能异常问题求助
修复StopWatch的两个问题:毫秒显示NaN和暂停后继续计时
问题1:毫秒值显示NaN的原因及修复
原代码中start方法的定时器内有一行错误赋值:
this.minute, this.second, this.milliSecond = Number(this.currentWatch());
- 逗号运算符无法完成多变量赋值,且会忽略前两个表达式,仅执行最后一步赋值
currentWatch()返回数组,用Number()转换数组会得到NaN,直接导致毫秒值异常- 另外,
currentWatch()内部已将计算好的时分毫秒值赋值给实例变量,这行赋值完全多余,直接删除即可。
问题2:暂停后继续计时的实现
原代码再次启动时会重置计时起点,无法累计之前的时长。修复逻辑:
- 停止计时时,已将累计时长存在
this.duration中 - 再次调用
start时,将this.currentTime设为Date.now() - this.duration,后续计算Date.now() - this.currentTime会自动包含之前的累计时长,实现续计时 - 将显示计时的p标签移到构造函数中创建,避免每次启动都生成新标签。
修复后的完整TypeScript代码
class StopWatch { private duration: number; private status: string; private currentTime: number; private domRef: HTMLElement | null; private interval: number | null; private milliSecond: number; private second: number; private minute: number; private displayEl: HTMLElement | null; constructor(wrapper: string) { this.duration = 0; this.milliSecond = 0; this.second = 0; this.minute = 0; this.interval = null; this.domRef = document.getElementById(wrapper); this.status = 'stopped'; if (!this.domRef) throw new Error('Wrapper element does not exist'); // 初始化显示元素,避免重复创建 this.displayEl = document.createElement("p"); this.displayEl.id = "stopwatch-display"; document.body.appendChild(this.displayEl); this.render(); } private render() { this.domRef!.append( createBtn('start', () => this.start()), createBtn('stop', () => this.stop()), createBtn('reset', () => this.reset()), ) } private start() { if(this.status === 'started') throw new Error('Stopwatch already started'); // 计算计时起点:当前时间减去已累计时长,实现续计时 this.currentTime = Date.now() - this.duration; this.status = 'started'; this.interval = setInterval(() => { this.currentWatch(); this.displayEl!.innerHTML = `${this.minute} : ${this.second} : ${this.milliSecond}`; }, 10); // 改为10毫秒间隔,让毫秒显示更平滑 } private currentWatch() { // 计算从起点到现在的总时长 const elapsed = Date.now() - this.currentTime; this.duration = elapsed; if(this.status === 'stopped') this.stop(); this.minute = Math.floor(elapsed / (1000 * 60)); this.second = Math.floor((elapsed % (1000 * 60)) / 1000); this.milliSecond = Math.floor(elapsed % 1000); } stop() { if(this.interval) clearInterval(this.interval); if(this.status === 'stopped') throw new Error('Stopwatch already stopped'); // 停止时更新累计时长 this.duration = Date.now() - this.currentTime; this.status = 'stopped'; return this.duration; } reset(){ if(this.status === 'started') this.stop(); this.duration = 0; this.minute = 0; this.second = 0; this.milliSecond = 0; this.displayEl!.innerHTML = `${this.minute} : ${this.second} : ${this.milliSecond}`; } } function createBtn(name: string, listener: () => void) { const btn = document.createElement('button'); btn.innerText = name; btn.addEventListener('click', listener); return btn; } (function() { const btns = document.getElementsByClassName('add-btn'); btns[0].addEventListener('click', () => { new StopWatch(btns[0].getAttribute('data-idw') as string); }); })();
额外优化点
- 将定时器间隔从100毫秒改为10毫秒,让毫秒数更新更平滑
- 给显示元素设置明确ID
stopwatch-display,避免与其他元素冲突 - 给
interval添加number | null类型,符合TypeScript类型规范 - 重置时同步重置时分毫秒实例变量,确保显示准确
内容的提问来源于stack exchange,提问作者arta
相关产品推荐
相关产品推荐

