HarmonyOs应用《日记本》开发第10篇 - @Builder 构建器与组件复用

发布时间:2026/7/25 23:14:00

HarmonyOs应用《日记本》开发第10篇 - @Builder 构建器与组件复用
在 ArkUI 开发中Builder是实现 UI 片段复用的核心装饰器。它让开发者可以将复杂的 UI 拆分为多个可维护的方法提高代码的可读性和复用性。本篇将以日记项目的三个页面为例深入探讨 Builder 的使用模式和最佳实践。Builder 基本语法BuilderMethodName(parameters):void{// UI 描述}基本示例Componentstruct Index{BuilderHeaderBar():void{Row(){Text(我的日记).fontSize(22).fontWeight(FontWeight.Bold).fontColor(#333).margin({left:20})Blank()Button(){...}}.width(100%).height(56).backgroundColor(#FFF)}build():void{Column(){this.HeaderBar()// 调用 Builder 方法}}}日记项目中的 Builder 全景Index 页面 — 4 个 BuilderEntryComponentstruct Index{build():void{Column(){this.HeaderBar()// 顶部标题栏if(this.isLoading){// 内联加载状态}elseif(this.diaries.length0){this.EmptyView()// 空状态视图}else{this.DiaryList()// 日记列表}}}BuilderHeaderBar():void{...}// 1. 标题栏BuilderEmptyView():void{...}// 2. 空状态BuilderDiaryList():void{...}// 3. 列表容器BuilderDiaryCard(item:DiaryItem):void{...}// 4. 日记卡片}DiaryEdit 页面 — 6 个 BuilderEntryComponentstruct DiaryEdit{build():void{Column(){this.NavBar()// 1. 导航栏Scroll(){Column(){this.DateSection()// 2. 日期选择区this.WeatherSection()// 3. 天气选择区this.MoodSection()// 4. 心情选择区this.TitleSection()// 5. 标题输入区this.ContentSection()// 6. 内容输入区}}}}}DiaryDetail 页面 — 3 个 BuilderEntryComponentstruct DiaryDetail{build():void{Column(){this.NavBar()// 1. 导航栏if(this.loading){// 内联加载状态}elseif(this.diary){this.DetailContent()// 2. 详情内容}else{// 内联不存在状态}}.bindContentCover($$this.showDeleteDialog,this.DeleteDialog())// 3. 删除弹窗}}Builder 进阶用法1. 带参数的 BuilderBuilderDiaryCard(item:DiaryItem):void{Column(){// 日期行Row(){Text(item.date).fontSize(14).fontWeight(FontWeight.Medium).fontColor(#FF6B6B)Blank()Text(getWeatherByKey(item.weather).emoji).fontSize(18).margin({right:8})Text(getMoodByKey(item.mood).emoji).fontSize(18)}.width(100%).alignItems(VerticalAlign.Center)// 标题Text(item.title).fontSize(17).fontWeight(FontWeight.Bold).fontColor(#333).maxLines(1).textOverflow({overflow:TextOverflow.Ellipsis}).margin({top:8})// 内容预览Text(item.content).fontSize(14).fontColor(#888).maxLines(2).textOverflow({overflow:TextOverflow.Ellipsis}).margin({top:6})// 底部信息Row(){Text(diaryStore.formatDateTime(item.updateTime)).fontSize(11).fontColor(#CCC)}.width(100%).margin({top:8})}.width(100%).padding(16).backgroundColor(#FFF).borderRadius(16).shadow({radius:8,color:#0D000000,offsetX:0,offsetY:2})}在ForEach中使用BuilderDiaryList():void{List({space:12}){ForEach(this.diaries,(item:DiaryItem){ListItem(){this.DiaryCard(item)// 传递参数}.onClick((){router.pushUrl({url:pages/DiaryDetail,params:{id:item.id}});})},(item:DiaryItem)item.id)}.width(100%).layoutWeight(1).padding({top:12,bottom:20,left:16,right:16})}2. 条件渲染的 BuilderBuilderNavBar():void{Row(){Text(返回).fontSize(16).fontColor(#666).onClick((){router.back();})Blank()if(this.diary){// 条件渲染只有日记数据存在时才显示编辑按钮Text(编辑).fontSize(16).fontColor(#FF6B6B).fontWeight(FontWeight.Medium).onClick((){router.pushUrl({url:pages/DiaryEdit,params:{id:this.diaryId}});})}}.width(100%).height(56).backgroundColor(#FFF).padding({left:20,right:20}).alignItems(VerticalAlign.Center)}3. 事件绑定的 BuilderBuilderWeatherSection():void{Column(){Text(天气).fontSize(15).fontColor(#666).margin({top:16,left:4})Row(){ForEach(WeatherList,(item:MoodWeatherItem){Column(){Text(item.emoji).fontSize(28)Text(item.label).fontSize(12).fontColor(this.weatheritem.key?#FF6B6B:#999).margin({top:4})}.width(18%).height(70).borderRadius(10).backgroundColor(this.weatheritem.key?#FFF0F0:#FFF).border(this.weatheritem.key?{width:1.5,color:#FF6B6B}:{width:0,color:#FFF}).onClick((){this.weatheritem.key;// 事件处理})})}}}4. 嵌套调用的 BuilderBuilderDetailContent():void{Scroll(){Column(){// 日记主体卡片Column(){// 日期行Row(){...}// 分隔线Divider().color(#F0F0F0).margin({top:16,bottom:16})// 标题if(this.diary!.title){Text(this.diary!.title)...}// 正文Text(this.diary!.content)...// 底部时间Column(){...}}.shadow({...})// 删除按钮Button(删除此日记).onClick((){this.showDeleteDialogtrue;// 触发弹窗})}}}5. 全屏弹窗 BuilderBuilderDeleteDialog():void{Column(){Column(){Text(确认删除).fontSize(18).fontWeight(FontWeight.Bold).fontColor(#333).margin({top:24})Text(删除后无法恢复确定删除这篇日记吗).fontSize(14).fontColor(#888).margin({top:12,bottom:24})Divider().color(#F0F0F0)Row(){Text(取消).layoutWeight(1).onClick((){this.showDeleteDialogfalse;})Divider().vertical(true).height(48)Text(删除).layoutWeight(1).onClick((){this.showDeleteDialogfalse;this.deleteDiary();})}}.width(80%).backgroundColor(#FFF).borderRadius(16)}.width(100%).height(100%).justifyContent(FlexAlign.Center).backgroundColor(#99000000)// 半透明遮罩}Builder 的设计模式模式 1区域划分将页面按功能区域拆分DiaryEdit 页面 ├── NavBar() → 导航区域 ├── DateSection() → 日期区域 ├── WeatherSection() → 天气区域 ├── MoodSection() → 心情区域 ├── TitleSection() → 标题区域 └── ContentSection() → 内容区域模式 2状态分支根据状态渲染不同 UIIndex 页面 ├── HeaderBar() → 始终显示 ├── [加载中] → 内联 ├── EmptyView() → 空状态 └── DiaryList() → 有数据时模式 3列表项模板ForEach(this.diaries,(item:DiaryItem){ListItem(){this.DiaryCard(item)// 每个列表项复用同一模板}},(item:DiaryItem)item.id)模式 4弹窗模板.bindContentCover($$this.showDeleteDialog,this.DeleteDialog())Builder 与组件通信通过 State 共享Builder 方法可以访问组件的 State 变量Stateweather:stringsunny;BuilderWeatherSection():void{// 直接访问 this.weather.backgroundColor(this.weatheritem.key?#FFF0F0:#FFF).onClick((){this.weatheritem.key;// 修改 State})}通过参数传递BuilderDiaryCard(item:DiaryItem):void{Text(item.title)// 使用传入的参数Text(item.content)}Builder 最佳实践1. 单一职责每个 Builder 只负责一个 UI 区域// ✅ 好的做法BuilderNavBar():void{...}BuilderDateSection():void{...}BuilderWeatherSection():void{...}// ❌ 不好的做法BuilderBigChunk():void{// 导航栏 日期 天气 心情 标题 内容全写在一起}2. 合理命名使用描述性名称让人一看就知道 Builder 渲染什么// ✅ 清晰的命名BuilderHeaderBar():void{...}BuilderEmptyView():void{...}BuilderDiaryCard(item:DiaryItem):void{...}BuilderDeleteDialog():void{...}// ❌ 模糊的命名BuilderView1():void{...}BuilderBuild():void{...}3. 避免过深嵌套// ✅ 扁平化结构build():void{Column(){this.NavBar()this.DateSection()this.WeatherSection()this.MoodSection()this.TitleSection()this.ContentSection()}}小结Builder是 ArkUI 中实现 UI 复用和代码组织的利器特性说明参数传递支持传入参数实现模板化状态访问可访问组件 State 变量条件渲染支持内部 if-else事件绑定支持 onClick 等事件嵌套调用Builder 可调用其他 Builder弹窗构建可配合 bindContentCover 实现弹窗通过合理使用 Builder日记项目将复杂的 UI 拆分为清晰的小块每个 Builder 负责一个独立区域使代码易于维护和扩展。

相关新闻

LinkedIn资料完整,为什么还是很少收到招聘人员联系?|蒸汽求职分享

LinkedIn资料完整,为什么还是很少收到招聘人员联系?|蒸汽求职分享

2026/7/25 23:14:00

**摘要:**LinkedIn资料完整,只能说明页面信息较齐全,并不代表招聘人员能快速判断候选人适合什么岗位。Headline、About、经历标题和项目描述需要共同传递清楚的职业方向,同时保持信息真实,并与简历和实际能力一致。 学…

为什么你的AI采集系统总在凌晨崩?揭秘内存泄漏×JS沙箱逃逸×Token轮换失效的三重连锁故障(附热修复补丁)

为什么你的AI采集系统总在凌晨崩?揭秘内存泄漏×JS沙箱逃逸×Token轮换失效的三重连锁故障(附热修复补丁)

2026/7/25 23:04:00

更多请点击: https://kaifayun.com 第一章:AI自动化 数据采集 AI驱动的数据采集正逐步取代传统手动爬取与人工录入模式,其核心在于将感知、决策与执行能力嵌入采集流程中。现代AI自动化采集系统通常融合自然语言处理(NLP&#xf…

从0到1理解snake-ai-pytorch:DQN算法在贪吃蛇游戏中的应用

从0到1理解snake-ai-pytorch:DQN算法在贪吃蛇游戏中的应用

2026/7/25 23:04:00

从0到1理解snake-ai-pytorch:DQN算法在贪吃蛇游戏中的应用 【免费下载链接】snake-ai-pytorch 项目地址: https://gitcode.com/gh_mirrors/sn/snake-ai-pytorch snake-ai-pytorch是一个基于PyTorch和Pygame实现的贪吃蛇游戏AI项目,通过深度Q网络…

OpenClaw本地AI助手:隐私优先的自主执行架构解析

OpenClaw本地AI助手:隐私优先的自主执行架构解析

2026/7/26 0:14:03

1. 项目概述:OpenClaw的革新理念OpenClaw项目正在重新定义个人AI助手的边界。与依赖云端服务的传统方案不同,它采用"本地优先自主执行"的双重设计理念,将数据处理和任务执行完全保留在用户设备端。这种架构带来的不仅是隐私保护层面…

2026甄选:3家宁波语文小升初机构综合评测

2026甄选:3家宁波语文小升初机构综合评测

2026/7/26 0:14:03

在宁波,每一个面临小升初、中考、高考的家庭,几乎都绕不开同一个困境——优质教育资源高度集中,但真正懂本地考情、能解决孩子个体差异的辅导机构却凤毛麟角。尤其是镇海、海曙、鄞州这些教育强区,家长们的升学焦虑并不逊于一线城…

Hackintosh终极指南:从硬件兼容到系统伪装的完整解决方案

Hackintosh终极指南:从硬件兼容到系统伪装的完整解决方案

2026/7/26 0:14:03

Hackintosh终极指南:从硬件兼容到系统伪装的完整解决方案 【免费下载链接】Hackintosh Hackintosh long-term maintenance model EFI and installation tutorial 项目地址: https://gitcode.com/gh_mirrors/ha/Hackintosh gh_mirrors/ha/Hackintosh项目是黑苹…

面试官皱眉:“RAG 答错了,你就改 Prompt、换模型、调大 Top-K?“我摇头:“连证据在哪层丢的都不知道,改参数就是碰运气“

面试官皱眉:“RAG 答错了,你就改 Prompt、换模型、调大 Top-K?“我摇头:“连证据在哪层丢的都不知道,改参数就是碰运气“

2026/7/26 0:14:03

RAG 回答错了,最常见的第一反应是什么? 改 Prompt,换大模型,或者把 Top-K 调大。 这三个动作都可能有用,但它们不应该成为排查起点。 因为最终答案只是链路最后一层。错误可能早在文档解析时就发生,也可…

大模型 Agent 三面被问:怎么解决 Skill 的依赖关系?我是这么答的

大模型 Agent 三面被问:怎么解决 Skill 的依赖关系?我是这么答的

2026/7/26 0:14:03

前段时间有个读者去面某大厂的 Agent 岗位,三面被甩出来一道题当场卡壳。题目听着挺朴素:“如果你的 Agent 里面有很多 Skill,Skill 之间还存在依赖关系的话,你打算怎么去设计来解决这个问题?” 他跟我复盘的时候说&a…

向量数据库选型实战:Milvus、FAISS与PGVector的取舍

向量数据库选型实战:Milvus、FAISS与PGVector的取舍

2026/7/26 0:04:02

引言:AI应用的基础设施之选 当企业决定搭建RAG系统或智能推荐平台时,第一个技术决策往往都是:选什么向量数据库? 这个看似基础的选择,直接影响着检索精度、系统性能和运维复杂度。2024年,向量数据库市场已经…

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

2026/7/26 0:04:02

目标:电脑作为RTSP 服务端,循环推送 H264/H265 视频流; RDK X5 通过 rtsp2display 拉流预览,完全不需要在开发板编译 live555。 提供两套成熟方案: ✅ 方案 A:FFmpeg(最简单,优先推…

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

2026/7/26 0:04:02

一、背景与测试方案 在实际项目交付中,PDF文件合并与版权保护水印的叠加是一个高频但容易被低估的技术需求。典型的处理链路涉及:多源PDF的文件流合并、页面级水印渲染(含透明度混合与图层叠加)、输出文件体积控制。看似简单的操作…

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

2026/7/26 0:04:02

说实话,提到PDF拆分再压缩,我真是被折腾得够呛。 上个月公司年度合同归档,一份300多页的PDF总合同,需要按年份拆分成三个独立文件,再分别压缩到10MB以内方便邮件发送各部门确认。我心想这还不简单?先找个海…

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

2026/7/26 0:04:02

目标:电脑作为RTSP 服务端,循环推送 H264/H265 视频流; RDK X5 通过 rtsp2display 拉流预览,完全不需要在开发板编译 live555。 提供两套成熟方案: ✅ 方案 A:FFmpeg(最简单,优先推…

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

2026/7/26 0:04:02

一、背景与测试方案 在实际项目交付中,PDF文件合并与版权保护水印的叠加是一个高频但容易被低估的技术需求。典型的处理链路涉及:多源PDF的文件流合并、页面级水印渲染(含透明度混合与图层叠加)、输出文件体积控制。看似简单的操作…

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

2026/7/26 0:04:02

说实话,提到PDF拆分再压缩,我真是被折腾得够呛。 上个月公司年度合同归档,一份300多页的PDF总合同,需要按年份拆分成三个独立文件,再分别压缩到10MB以内方便邮件发送各部门确认。我心想这还不简单?先找个海…