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

发布时间:2026/9/22 17:57:34

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/8/24 22:36:42

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

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

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

2026/8/24 22:36:42

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

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

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

2026/8/24 22:36:42

从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网络…

CANN/GE ACL数据集缓冲区添加函数

CANN/GE ACL数据集缓冲区添加函数

2026/9/21 18:38:46

aclmdlAddDatasetBuffer 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、Te…

用ffmpeg高效批量调整图片尺寸的实战指南

用ffmpeg高效批量调整图片尺寸的实战指南

2026/9/21 18:41:09

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

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

2026/9/21 18:36:40

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱 【免费下载链接】transformers 🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and mu…

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

2026/9/21 18:37:26

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system sup…

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

2026/9/21 18:40:29

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

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

2026/9/21 18:36:17

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system supporting mi…

远程协作的工作台整理

远程协作的工作台整理

2026/9/22 0:19:28

远程协作的工作台整理远程协作的核心不是再加一个工具,而是让交接信息足够完整。异步任务要写明目标、输入位置、完成标准和需要决策的人。 工作台的最小配置 将日程、待办、代码和沟通入口收拢到少数固定位置;通知按紧急程度分层。工作台不需要模仿办公…

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

2026/9/21 23:38:13

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

2026/9/22 0:48:53

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…