尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
番茄钟真正难的不是倒计时:启动、暂停、重置与页面销毁
番茄钟的界面只有一个大数字但真正需要控制的是计时器生命周期。开始后每秒递减暂停时必须停住切换时长要重置页面离开后也不能让旧定时器继续在后台修改状态。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本轮专注已完成}即使某次回调晚到几百毫秒下一次刷新也会依据绝对结束时间校正。
RELATED

相关推荐

Supabase 实战指南:从登录、RLS 到 Storage 签名链接

Supabase 实战指南:从登录、RLS 到 Storage 签名链接

Supabase 实战指南:从登录、RLS 到 Storage 签名链接 本文不依赖特定的项目代码,侧重于梳理使用 Supabase 过程中通用的核心逻辑与踩坑记录。无论你是在做班级同学录、个人博客还是其他小应用,这些经验都值得参考。 本文源于作者一次制作同学…

📅 2026/10/11 1:29:01
Z型钢直销厂家排行榜新鲜出炉,这份榜单帮你避开选购陷阱

Z型钢直销厂家排行榜新鲜出炉,这份榜单帮你避开选购陷阱

近期,网络上各类“Z型钢直销厂家排行榜”层出不穷,为采购方提供了参考,但也因信息真伪难辨,让不少工程负责人挑花了眼。榜单看似直观,实则隐藏着商业推广逻辑与信息滞后风险。对于需要大宗采购或长期合作的单位而言&am…

📅 2026/9/21 0:56:50
基于SpringBoot的社区团购小程序的设计与实现源码+文档+讲解视频

基于SpringBoot的社区团购小程序的设计与实现源码+文档+讲解视频

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

📅 2026/9/24 19:00:59
MORE NEWS

更多资讯

📰

MariaDB 预处理语句加 CAST 后查询大幅提速的原因

一条带绑定参数的查询,仅仅给参数套上一层看起来毫无必要的 CAST,耗时就从 0.083 秒降到 0.005 秒。在真实数据上是 1.5 秒对 0.3 秒。差别不在 CAST 的计算成本,而在优化器是否愿意把条件下推到视图内部。 问题现象 表与视图定义如下: CREATE DATABASE cast_demoCHARAC…

📰

R 数据框按组内条件动态重置参考日期计算天数差

同一受试者有多条日期记录,需要判断哪些记录属于同一次事件、哪些已经相隔太久应当算作新事件。参考日期默认是组内第一条记录,一旦出现间隔超过阈值的记录,基准就切换到那条记录上。 问题现象 原始数据: dfi <- structure(list(ID = c(1, 1, 2, 2, 2,

📰

BP神经网络在低算力路面裂缝识别中的工程实践

简介&#xff1a;本资源是一篇聚焦工程实践与算法落地的学术论文&#xff0c;面向交通工程、智能检测及人工智能应用领域的高校师生与行业技术人员&#xff0c;旨在解决沥青路面图像噪声强、传统边缘检测易误判裂缝等实际难题。论文提出基于BP神经网络的裂缝识别方法&#xff1…

📰

R 中调用 DuckDB 报 IO Error 无法创建临时目录的排查与修复

在 macOS 上用 R 做地址地理编码时,很多包会组合 duckdb 与 callr:duckdb 负责本地列式计算,callr 负责把重活丢到独立的 R 子进程里跑。这类组合一旦临时目录配置出问题,报错会发生在子进程内部,主会话只能看到一个被包装过的 callr 错误,排查起来很绕。 问题现象 主脚…

📰

IL-6:炎症网络与免疫代谢调控的核心节点分子,信号转导模式与疾病机制全解析

炎症微环境重塑、免疫细胞命运决定与组织损伤修复机制是感染免疫学、肿瘤生物学及代谢性疾病研究的核心方向。白细胞介素- 6&#xff08;Interleukin- 6&#xff0c;IL- 6&#xff09;是机体调控急性期应答、Th17/Treg平衡与肿瘤免疫逃逸的核心多效性细胞因子&#xff0c;也是解…

📰

openSCADA的jar部署与依赖管理:从classpath到模块加载避坑指南

简介&#xff1a;面向Java环境下OpenSCADA二次开发及OPC模块调试的工程师&#xff0c;这套资源将项目启动阶段最繁琐的依赖收集工作一次做完&#xff0c;按OpenSCADA/Java工程实际使用场景归拢全部必需组件。压缩包共480个文件&#xff0c;体积约30.92MB&#xff0c;主体为129个…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬