HarmonyOS《柚兔学伴》项目实战11-倒计时组件封装与控制器模式

发布时间:2026/11/5 6:21:54

HarmonyOS《柚兔学伴》项目实战11-倒计时组件封装与控制器模式 第11篇倒计时组件封装与控制器模式在柚兔学伴中番茄钟倒计时是核心功能之一。倒计时组件需要满足外部可设置时间、可远程重置、可监听状态变化。这就引出了一个经典的组件设计问题——如何让父组件从外部控制子组件的行为本篇从TimerComponent.ets的 202 行源码出发详解控制器模式Controller Pattern在 ArkUI 中的实现。一、控制器模式的核心思想ArkUI 的Component是一个封闭的作用域State、Prop等状态装饰器只能在组件内部修改。如果父组件想要主动触发子组件的某个行为如重置倒计时单纯通过属性传递是做不到的。控制器模式的解法是子组件在初始化时将自身的方法注册到控制器对象上父组件持有控制器通过调用控制器方法间接驱动子组件。父组件 ──调用── Controller.reset() ──回调── 子组件.onResetFromController()二、TimerComponentController 实现exportclassTimerComponentController{privateresetCallback:(()void)|nullnull;setResetCallback(callback:()void){this.resetCallbackcallback;}reset(){if(this.resetCallback){this.resetCallback();}}}控制器非常简洁只做两件事setResetCallback注册回调函数由子组件调用reset执行回调函数由父组件调用这种注册-执行的模式本质是将子组件的方法引用提升到了控制器中打破了组件边界对方法调用的限制。三、TimerComponent 组件详解3.1 属性定义Componentexportstruct TimerComponent{controller:TimerComponentController|nullnull;PropWatch(onTotalTimeChange)totalTime:number60;onTotalTimeChange(){this.resetTimer();this.currentTimethis.totalTime;}onTimeUp?:()void;onTimeChange?:(currentTime:number)void;StatecurrentTime:number60;StateisRunning:booleanfalse;privatetimer:number-1;privategradientColor:LinearGradientnewLinearGradient([{color:$r(app.color.color_color_1),offset:0.5},{color:$r(app.color.color_color_2),offset:1.0}])}关键设计点属性装饰器说明totalTimeProp Watch从父组件单向传入变化时自动重置计时器currentTimeState当前剩余时间驱动 UI 刷新isRunningState运行状态控制按钮文字和颜色onTimeUp普通属性回调函数时间归零时通知父组件onTimeChange普通属性回调函数每秒通知父组件时间变化controller普通属性控制器实例父组件通过它远程控制Prop保证totalTime从父组件单向流入Watch则监听其变化当外部重新设置时间时自动重置。3.2 控制器绑定aboutToAppear(){this.currentTimethis.totalTime;if(this.controller){this.controller.setResetCallback(this.onResetFromController.bind(this));}}onResetFromController(){this.resetTimer();this.currentTimethis.totalTime;}aboutToAppear是组件的生命周期回调在组件首次创建时执行。此时将onResetFromController方法通过bind(this)绑定正确的this指向后注册到控制器。为什么需要.bind(this)因为setResetCallback存储的是函数引用当控制器调用resetCallback()时this可能丢失。bind确保无论谁调用这个函数this都指向组件实例。3.3 倒计时核心逻辑toggleTimer(){if(this.isRunning){clearInterval(this.timer);this.isRunningfalse;}else{this.isRunningtrue;this.timersetInterval((){if(this.currentTime0){this.currentTime--;if(this.onTimeChange){this.onTimeChange(this.currentTime);}}else{this.isRunningfalse;clearInterval(this.timer);if(this.onTimeUp){this.onTimeUp();}}},1000);}}每 1000ms1秒执行一次剩余时间 0递减currentTime触发onTimeChange回调剩余时间 0停止定时器标记为未运行触发onTimeUp回调toggleTimer是一个切换函数——运行时暂停暂停时开始。clearInterval确保不会产生多个定时器叠加。3.4 重置逻辑resetTimer(){clearInterval(this.timer);this.isRunningfalse;this.currentTimethis.totalTime;}重置操作包含三个步骤清除定时器 → 停止运行状态 → 恢复初始时间。无论是本地重置还是通过控制器远程重置最终都调用此方法。四、时间格式化formatTime(seconds:number):string{consthoursMath.floor(seconds/3600);constminutesMath.floor((seconds%3600)/60);constsecsseconds%60;return${hours.toString().padStart(2,0)}:${minutes.toString().padStart(2,0)}:${secs.toString().padStart(2,0)};}将总秒数转换为HH:MM:SS格式。padStart(2, 0)确保个位数补零如5显示为05。五、UI 构建5.1 圆形进度条Stack(){Progress({value:this.getProgress(),total:this.totalTime,type:ProgressType.ScaleRing}).width(100%).height(100%).style({strokeWidth:10,}).color($r(app.color.app_primary))Column(){Text(this.formatTime(this.currentTime)).fontSize(20).fontWeight(FontWeight.Bolder).textAlign(TextAlign.Center)Text(剩余时间).fontSize(14).fontColor(Color.Gray).margin({top:10})}}ProgressType.ScaleRing是圆环进度条value为已用时间totalTime - currentTimetotal为总时间。Stack 布局将时间文字叠加在进度环中心。5.2 控制按钮Row({space:12}){Button(重置).fontSize(12).height(30).backgroundColor(#F0F0F0).fontColor(Color.Black).borderRadius(25).onClick((){this.resetTimer();})Button(this.isRunning?暂停:开始).fontSize(12).height(30).backgroundColor(this.isRunning?$r(app.color.app_alert):$r(app.color.app_primary)).fontColor(Color.White).borderRadius(25).onClick((){this.toggleTimer();})}按钮文字和颜色根据isRunning状态动态切换实现了开始/暂停一体化按钮。六、生命周期清理aboutToDisappear(){if(this.timer!-1){clearInterval(this.timer);}}组件销毁时必须清除定时器否则会持续消耗资源并可能导致对已销毁组件的状态修改。timer初始值为-1仅在有活跃定时器时清理。七、父组件中的使用在TodoView中倒计时组件的完整使用方式timerController:TimerComponentControllernewTimerComponentController()StatesettingTime:number25*60;onTimerFinishedasync(){this.alarmVisibletrue// 播放提醒音}onTimeChanged(currentTime:number){console.log(剩余时间:${currentTime}秒);}// 在 build 中使用TimerComponent({totalTime:this.settingTime,onTimeUp:this.onTimerFinished,onTimeChange:this.onTimeChanged,controller:this.timerController})当用户在弹窗中确认关闭闹钟时通过控制器重置IBestDialog({visible:$alarmVisible,defaultBuilder:():voidthis.alarmBuild(),onConfirm:((){this.alarmVisiblefalsethis.timerController.reset()// 远程重置倒计时})})八、控制器模式的适用场景场景说明需要远程重置弹窗确认后重置计时器需要远程暂停/恢复页面切换时暂停返回时恢复需要跨组件通信兄弟组件间通过共享控制器协调行为控制器模式的扩展方向添加更多回调setPauseCallback、setResumeCallback支持多实例每个控制器绑定一个组件实例结合Watch控制器修改某个State子组件通过Prop Watch响应九、小结控制器模式在 ArkUI 中解决了父组件主动驱动子组件行为的需求其核心三步定义 Controller 类声明回调属性和注册/执行方法子组件注册回调在aboutToAppear中controller.setResetCallback(this.method.bind(this))父组件调用方法controller.reset()间接触发子组件行为相比Link双向绑定控制器模式更语义化——它表达的是命令而非数据同步适合倒计时重置、播放器控制、动画触发等命令式交互场景。
延伸阅读

更多相关文章

2026/11/4 9:55:17

反重力特效制作全解析:从动作捕捉到CGI合成的电影VFX技术

这次我们来看一个名为"三哥最新的反重力动作电影来袭"的项目,从标题看这应该是一部印度动作电影,主打反重力特效和视觉冲击力。这类电影通常以夸张的物理效果、高难度动作场面和独特的视觉风格为特色,在特效制作和动作设计上往往有…

2026/11/2 5:03:07

L-BFGS-B:从理论到实践,解析大规模有界约束优化的高效算法

1. 初识L-BFGS-B:当优化问题遇到边界约束想象你在玩一个迷宫游戏,但这次有个特殊规则——某些通道被设置了"禁止通行"的标志。这就是带边界约束的优化问题:我们既要找到最优解,又要确保变量不越界。L-BFGS-B算法就像是这…

2026/11/4 7:51:24

树莓派+YOLOv8n+Edge TPU实时目标检测实战指南

1. 项目概述:为什么在树莓派上跑YOLOv8Edge TPU不是“炫技”,而是真实落地的刚需你有没有遇到过这样的场景:在仓库角落部署一个智能分拣终端,它需要实时识别纸箱上的条形码类型、胶带缠绕方向和破损区域,但供电只有5V/…

2026/11/5 8:18:14

CY8CMBR3116触摸驱动与CT1642显示实战:从I2C时序到避坑指南

简介:这份资源面向使用8051系列单片机的嵌入式开发者,提供CY8CMBR3116电容触摸传感器在C51平台上的完整驱动实现,并配套CT1642液晶驱动,解决触摸按键检测与键值显示的一体化控制问题。压缩包共30个文件,约54KB&#xf…

2026/11/5 8:18:14

Android SQLite学生成绩管理:Java源码实现与避坑指南

简介:这份资源面向Android初学者与移动开发课程学习者,提供一套可直接运行的「学生成绩管理系统」完整工程,用于练习SQLite本地存储与Java业务逻辑的配合。系统围绕学生信息与科目成绩的增删改查展开,涵盖SQLiteOpenHelper建表与版…

2026/11/5 8:18:14

C++算法学习路线与核心知识体系详解

1. 为什么C算法学习需要方向性规划 作为从大学ACM竞赛一路走来的老选手,我见过太多初学者在C算法学习上踩坑。最常见的就是盲目刷题,看到什么学什么,最后知识点零散不成体系。这种学习方式效率极低,往往投入上百小时却收效甚微。 …

2026/11/5 8:18:14

C8051F头文件包:从寄存器定义到工程验证的完整指南

简介:这份资源面向使用Silicon Labs C8051F系列单片机进行嵌入式开发的工程师与学习者,集中提供编程时不可或缺的头文件集合,解决开发中寄存器定义、外设接口与内核函数声明缺失或版本不全的问题。压缩包共48个文件,全部为h头文件…

2026/11/5 8:18:14

LLM与知识图谱结合的时尚推荐系统优化实践

1. 项目背景与核心价值 去年在帮某时尚电商平台优化推荐系统时,我们发现一个有趣现象:当用户搜索"适合海边度假的裙子"时,常规推荐算法只会匹配关键词"裙子",却无法理解"海边度假"隐含的材质轻薄、…

2026/11/5 8:13:12

冥府技术体系架构:业力计算与轮回调度系统解析

1. 冥府技术体系架构解析 在冥府技术团队中,我们建立了一套融合硅谷工程文化与东方玄学智慧的技术架构。这套系统需要处理每秒数百万级的因果事件,同时保证六道轮回的绝对公平性。作为从阳间晋升而来的技术管理者,我深刻理解两个世界的技术差…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 0:02:07

多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中…

2026/11/5 0:02:07

大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#…

2026/11/5 0:02:07

鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑