多行列计时器切换问题:启动新计时时旧计时无法正常暂停
嗨,我帮你搞定这个计时器问题啦!
看了你的代码后,发现问题出在你的taskService里——你现在只用了单个interval、time变量来管理所有行的计时器,这就导致每次启动新行时,会直接覆盖掉之前的计时器实例;暂停的时候也是清除这个唯一的interval,自然所有行的计时器都跟着停了。
要解决这个问题,我们得给每一行单独存一份计时器的状态、时间和interval实例,不能大家共用一组变量。下面是具体的修改方案:
第一步:重构你的 TaskService
把服务里的全局变量改成一个对象,用行的id作为键,来存储每一行的计时器数据:
// task.service.ts import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class TaskService { // 用对象存储每个行的计时器信息:key是行id,value包含interval、time、状态 private timerMap: { [key: string]: { interval: number | null; time: number; state: 'start' | 'pause' } } = {}; startTimer(data: { key: { id: string }; rowIndex: number }) { const rowId = data.key.id; // 如果该行之前有计时器,先清掉旧的,避免重复启动 if (this.timerMap[rowId]) { clearInterval(this.timerMap[rowId].interval); } // 初始化当前行的计时器数据 this.timerMap[rowId] = { interval: null, time: 0, state: 'start' }; // 启动当前行的计时器 this.timerMap[rowId].interval = window.setInterval(() => { this.timerMap[rowId].time++; // 如果需要在模板显示时间,后续可以通过get方法获取这个值 }, 1000); } pauseTimer(data: { key: { id: string }; rowIndex: number }) { const rowId = data.key.id; if (this.timerMap[rowId]) { clearInterval(this.timerMap[rowId].interval); this.timerMap[rowId].state = 'pause'; this.timerMap[rowId].interval = null; } } // 获取指定行的累计时间 getRowTime(rowId: string): number { return this.timerMap[rowId]?.time || 0; } // 获取指定行的状态(启动/暂停) getRowState(rowId: string): 'start' | 'pause' | undefined { return this.timerMap[rowId]?.state; } }
第二步:调整组件里的 startTimer 方法
现在启动新行时,我们可以精准暂停其他正在运行的行,而不是误杀所有计时器:
// 你的组件.ts文件 startTimer(data) { // 遍历所有行,把除了当前点击行之外的活跃计时器暂停 this.data.forEach(row => { const rowState = this.taskService.getRowState(row.id); if (rowState === 'start' && row.id !== data.key.id) { this.taskService.pauseTimer({ key: { id: row.id }, rowIndex: row.rowIndex }); } }); // 启动当前点击行的计时器 this.taskService.startTimer(data); } pauseTimer(data) { this.taskService.pauseTimer(data); }
为什么这样改就好使了?
- 每个行独立拥有计时器:
timerMap对象给每一行都存了专属的interval、时间和状态,再也不会出现新行启动覆盖旧行计时器的问题。 - 精准控制单个行:启动新行时,只会暂停其他正在运行的行,不会影响已经暂停的行,也不会误清所有计时器。
- 保留累计时间:之前的代码一暂停就把
time重置为0,现在修改后,暂停的行再次启动可以继续累计时间(如果需要重置的话,直接在startTimer里把time设为0就行,按需调整)。
如果你的模板需要显示每一行的时间和状态,现在可以通过taskService.getRowTime(row.id)和taskService.getRowState(row.id)来获取对应行的数据啦!
内容的提问来源于stack exchange,提问作者Mike Landers
相关产品推荐
相关产品推荐

