尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

番茄钟真正难的不是倒计时:启动、暂停、重置与页面销毁

番茄钟真正难的不是倒计时:启动、暂停、重置与页面销毁 番茄钟的界面只有一个大数字但真正需要控制的是计时器生命周期。开始后每秒递减暂停时必须停住切换时长要重置页面离开后也不能让旧定时器继续在后台修改状态。privateroundById(id:number):FocusRecord|undefined{returnthis.records.find((round:FocusRecord)round.idid)}privaterequireRound(id:number):FocusRecord{consttarget:FocusRecord|undefinedthis.roundById(id)if(!target){thrownewError(Round not found: id)}returntarget}核心状态分成“剩余秒数”和“是否运行”。显示文本由秒数计算避免同时维护25:00这样的字符串状态。StatesecondsLeft:number25*60Staterunning:booleanfalseStateselectedMinutes:number25StatestatusText:string准备好了privatetimerId:number-1privateclockText():string{constminutes:numberMath.floor(this.secondsLeft/60)constseconds:numberthis.secondsLeft%60return${minutes.toString().padStart(2,0)}:${seconds.toString().padStart(2,0)}}开始与暂停共用toggleTimer()。暂停分支先清理定时器再恢复标识开始分支创建一个每秒执行的任务。倒计时到0时同样清理timerId并把状态改成“本轮完成”。privatetoggleTimer():void{if(this.running){clearInterval(this.timerId)this.timerId-1this.runningfalsethis.statusText已暂停return}this.runningtruethis.statusText专注中this.timerIdsetInterval((){if(this.secondsLeft0){this.secondsLeft-1}else{clearInterval(this.timerId)this.timerId-1this.runningfalsethis.statusText本轮完成}},1000)}切换15、25或45分钟时旧计时器必须先清理。如果只改secondsLeft原来的 interval 仍在运行新时长会立刻继续递减按钮上却可能显示“准备好了”。chooseDuration()把运行标记、定时器ID、选中时长和提示一起复位。privatechooseDuration(minutes:number):void{if(this.timerId0){clearInterval(this.timerId)}this.runningfalsethis.timerId-1this.selectedMinutesminutesthis.secondsLeftminutes*60this.statusText准备好了}aboutToDisappear():void{if(this.timerId0){clearInterval(this.timerId)// 页面退出时停止后台回调}}运行初始状态下任务名称可编辑圆形计时区域展示剩余时间时长按钮与当前选择保持一致。点击开始后secondsLeft每秒变化状态文字进入“专注中”圆环宽度也根据running从4切换到10。暂停时定时器被释放剩余时间留在当前值继续点击可以从该值重新开始。当前计时方式适合前台演示但不能当作系统级精准计时。应用进入后台以后interval 的调度可能延迟privatereplaceRound(id:number,updater:(source:FocusRecord)FocusRecord):void{this.recordsthis.records.map((round:FocusRecord)round.idid?updater(round):round)}privateupdateRoundMessage(id:number):void{consttarget:FocusRecord|undefinedthis.roundById(id)this.messagetarget?状态已更新:目标记录不存在}声音提醒、后台任务和通知也尚未接入当前边界是前台专注状态管理。计时显示与计时来源要分开clockText()只做格式化不改变秒数。分钟通过整除得到秒数通过取余得到再补齐两位。这样状态始终是可计算的秒数而不是不断拆分和拼接字符串。privateclockText():string{constminutes:numberMath.floor(this.secondsLeft/60)constseconds:numberthis.secondsLeft%60return${minutes.toString().padStart(2,0)}:${seconds.toString().padStart(2,0)}}圆环宽度也读取running。开始后描边从4变成10暂停后恢复视觉变化和按钮文案来自同一布尔值。Circle().width(226).height(226).fill(#FFFFFF).stroke(#FF7357).strokeWidth(this.running?10:4)Button(this.running?暂停一下:开始专注).onClick((){this.toggleTimer()})当前倒计时会受到调度延迟影响setInterval(..., 1000)表达的是尽量每秒回调不保证绝对准时。页面繁忙、应用切后台或系统调度变化都可能让回调延迟单纯每次减1会让计时比真实时间慢。privateremoveRound(id:number):void{constbefore:numberthis.records.lengththis.recordsthis.records.filter((round:FocusRecord)round.id!id)this.messagethis.records.lengthbefore?记录已删除:没有找到要删除的记录}privatehasRound(id:number):boolean{returnthis.records.some((round:FocusRecord)round.idid)}暂停时还要保存剩余秒数而不是继续保留旧的目标结束时间恢复时根据剩余值生成新的目标。页面销毁则只清理定时器最近完成目前仍是静态数据页面底部的records是固定数组倒计时归零时只把statusText改成“本轮完成”并没有插入新的FocusRecord。这意味着完成状态能显示但最近完成列表不会增加。privaterecords:FocusRecord[][{label:ArkTS 类型整理,minutes:25,color:#FF8B73},{label:模拟器验证,minutes:15,color:#5D8BF4},{label:截图归档,minutes:10,color:#5BC8AF}]要让记录真正参与状态更新records需要变成State归零分支构造包含任务名称和选中时长的新记录再插入数组。中途暂停或重置不能写入完成记录重复触发归零也要防止创建两条。时长切换与输入任务的边界切换15、25、45分钟会清理当前计时这是一项有破坏性的操作。当前点击后立即重置没有确认提示。专注已经进行较长时间时可以先询问是否放弃或把已进行时间保存为未完成记录。privateroundKey(round:FocusRecord):string{returnString(round.id)}privateallRoundKeys():string[]{returnthis.records.map((round:FocusRecord)this.roundKey(round))}privatehasDuplicateRoundKey():boolean{constkeys:string[]this.allRoundKeys()returnnewSet(keys).size!keys.length}暂停后等待数秒再恢复剩余时间应保持不变。页面销毁测试则确认退出后状态不再更新。将这些边界写成可重复用例比只观察一分钟内数字变化更能验证计时生命周期。用目标时间修正计时漂移计时器回调只负责触发刷新剩余秒数由目标时间重新计算privaterefreshRemaining():void{if(this.endAt0){return}constdelta:numberthis.endAt-Date.now()this.remainingMath.max(0,Math.ceil(delta/1000))if(this.remaining0){this.finishRound()}}privatefinishRound():void{this.clearTicker()this.runningfalsethis.message本轮专注已完成}即使某次回调晚到几百毫秒下一次刷新也会依据绝对结束时间校正。
返回列表