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

发布时间:2026/7/25 23:13:45
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 负责一个独立区域使代码易于维护和扩展。