鸿蒙实战:ArchivePage 档案管理页——875 行最复杂页面完整拆解

📅 2026/7/12 5:44:23
鸿蒙实战:ArchivePage 档案管理页——875 行最复杂页面完整拆解
鸿蒙实战ArchivePage 档案管理页——875 行最复杂页面完整拆解前言图鸿蒙实战第92篇ArchivePage 档案管理页——875 行最复杂页面完整拆解 运行效果截图HarmonyOS NEXT在整个项目的 19 个页面中ArchivePage以875 行位居代码量第一。它是鹿鹿的核心数据管理界面集合了子页签过滤、防抖搜索、创建对话框、右滑删除 AlertDialog 确认、交错入场动画、底部毛玻璃 TabBar、名字哈希头像颜色等众多实用技术。本篇将从页面架构、核心交互、数据管理三个维度全面拆解这 875 行代码的设计智慧。系列导航91 AnalyzingPage · 93 TrendPage 情绪趋势相关文档List swipeAction · AlertDialog · ArchiveDao一、页面架构全景1.1 组件树结构ArchivePage buildColumn 根Row 状态栏Row 标题栏档案 ⊕ 新建Row 子页签TA的/我的/全部Row 搜索框List 档案列表ForEach ArchiveCardswipeAction 右滑删除Row 底部 TabBarbackdropBlur毛玻璃自定义对话框 createDialogtranslate y:300→0 入场1.2 状态变量清单EntryComponentstruct ArchivePage{Statearchives:ArchiveEntity[][]// 档案列表完整StatefilteredArchives:ArchiveEntity[][]// 过滤后搜索子页签StatecurrentTab:number0// 0TA的 1我的 2全部StatesearchText:string// 搜索关键词StateshowCreateDialog:booleanfalse// 新建对话框显示StatenewArchiveName:string// 新建对话框输入StatenewArchiveRelation:string// 关系可选StatedialogOffset:number300// 对话框入场偏移StateisLoading:booleanfalseprivatesearchTimer:number-1// 防抖定时器privateuserId:number-1}二、子页签三态过滤2.1 过滤逻辑子页签TA 的档案 / 我的 / 全部通过relation字段区分privateapplyFilter():void{letfiltered[...this.archives]// ① 子页签过滤if(this.currentTab0){// TA 的档案relation 非空且非未设置filteredfiltered.filter(aa.relationa.relation!未设置a.relation.trim()!)}elseif(this.currentTab1){// 我的没有 relation 或 relation 为未设置filteredfiltered.filter(a!a.relation||a.relation未设置||a.relation.trim())}// tab2全部不过滤// ② 搜索关键词过滤if(this.searchText.trim()){constkwthis.searchText.trim().toLowerCase()filteredfiltered.filter(aa.name.toLowerCase().includes(kw))}this.filteredArchivesfiltered}2.2 数据分布说明子页签对应数据relation值TA 的档案为他人分析的记录伴侣/朋友/家人等我的自我分析记录null//未设置全部不过滤任意三、防抖搜索3.1 搜索框实现TextInput({placeholder:搜索档案...,text:$$this.searchText}).onChange((val:string){this.searchTextval// 防抖延迟 300ms 后才执行过滤if(this.searchTimer!-1){clearTimeout(this.searchTimer)}this.searchTimersetTimeout((){this.applyFilter()},300)})为什么需要防抖用户快速输入张三时会触发张、张三两次 onChange不防抖会执行两次过滤操作效率低下。300ms 防抖后只执行最后一次的过滤。四、右滑删除 AlertDialog 确认4.1 swipeAction 配置ListItem().swipeAction({end:(){// 右侧滑出的删除按钮this.SwipeDeleteButton(archive)}})4.2 删除按钮 BuilderBuilderSwipeDeleteButton(archive:ArchiveEntity){Column(){Text(️).fontSize(22)Text(删除).fontSize(11).fontColor(Color.White)}.width(72).height(100%).justifyContent(FlexAlign.Center).backgroundColor(#FF4444).onClick((){AlertDialog.show({title:删除档案,message:确认删除${archive.name}的所有分析记录此操作不可恢复。,primaryButton:{value:取消,action:(){}// 取消不操作},secondaryButton:{value:删除,fontColor:Color.Red,action:async(){awaitArchiveDao.delete(archive.id)awaitthis.loadArchives()// 重新加载列表}}})})}特性实现方式说明滑出操作区swipeAction.end右侧显示红色删除按钮二次确认AlertDialog.show防止误操作删除后刷新loadArchives()重新查 DB确保列表同步五、名字哈希头像颜色5.1 算法实现每个档案卡片的头像用名字首字 哈希颜色实现无需图片资源privategetAvatarColor(name:string):string{// 简单哈希对字符串每个字符 ASCII 码累积运算lethash0for(leti0;iname.length;i){hash(hash5)-hashname.charCodeAt(i)hashhashhash// 转为 32 位整数}constcolors[#D9A689,// 暖棕#9BAEA8,// 灰绿#C9A0A0,// 玫瑰#A8C4D9,// 天蓝#C4D9A8// 草绿]returncolors[Math.abs(hash)%colors.length]}效果相同名字始终显示相同颜色确定性不同名字颜色分布均匀伪随机。六、新建档案对话框底部上滑6.1 入场动画// 对话框容器Column(){// ... 对话框内容}.translate({y:this.dialogOffset})// 初始偏移 300屏幕下方.animation({duration:350,curve:Curve.FastOutSlowIn})// 触发入场privateopenCreateDialog():void{this.showCreateDialogtrue// 延迟一帧让组件先渲染到 y:300再动画到 y:0setTimeout((){this.dialogOffset0},16)}// 触发退场privatecloseCreateDialog():void{this.dialogOffset300setTimeout((){this.showCreateDialogfalse},350)}为什么需要setTimeout(16ms)ArkUI 的渲染是异步的。如果直接在showCreateDialog true的同一帧设置dialogOffset 0组件还没渲染动画无法触发。16ms 延迟约 1 帧确保组件已挂载在y:300位置后再触发动画。6.2 关系标签选择器// 预设关系标签可扩展privatereadonlyRELATION_TAGS[伴侣,好友,家人,同事,]Wrap({space:8}){ForEach(this.RELATION_TAGS,(tag:string){Text(tag||无关系).padding({left:12,right:12,top:6,bottom:6}).backgroundColor(this.newArchiveRelationtag?AppColors.PRIMARY:AppColors.CARD).fontColor(this.newArchiveRelationtag?Color.White:AppColors.TEXT).borderRadius(AppRadius.ROUND).animation({duration:200}).onClick((){this.newArchiveRelationtag})})}七、交错入场动画7.1 卡片交错入场privatestartListAnimation():void{// 每张卡片延迟 80ms最多延迟到前 8 张this.filteredArchives.forEach((_,index){setTimeout((){animateTo({duration:400,curve:Curve.FastOutSlowIn},(){this.cardOpacities[index]1this.cardOffsets[index]0})},Math.min(index,8)*80)// 超过第8张不再增加延迟})}Math.min(index, 8) * 80限制最大延迟为 640ms——避免列表很长时最后几张卡片等太久才出现。八、底部 TabBar 毛玻璃Row(){this.TabItem(,首页,0)this.TabItem(,档案,1)this.TabItem(,趋势,2)this.TabItem(,我的,3)}.width(100%).height(56).backdropBlur(20)// ← 毛玻璃效果.backgroundColor(rgba(255,252,247,0.85))// ← 半透明底色.position({y:100%,x:0})// 固定底部.translate({y:-56})// 上移自身高度backdropBlur(20)对下层内容进行高斯模糊配合半透明背景色营造 iOS 风格的毛玻璃效果。值越大模糊越强20 是较常用的适中值。十、最佳实践与性能优化10.1 代码组织规范以下规范可显著提升代码可读性与可维护性分层解耦UI 逻辑pages/与数据操作DAO/Service严格分离不在 build() 中调用数据库组件拆分单个Component保持 100~200 行以内大型组件拆分为Builder子函数令牌约束颜色、字号、间距统一引用AppColors/AppFonts/AppAnimations禁止魔数错误处理异步方法统一返回PromiseT | null异常时hilog.error记录并返回null10.2 性能优化要点以下是常见性能优化措施的对比分析优化维度优化前优化后效果列表渲染ForEach全量渲染LazyForEach按需渲染内存降低 40-60%图片加载不指定尺寸指定width/height减少布局重计算数据库查询每次重新查询合理缓存 精确 Predicates查询速度提升 5-10x动画实现逐帧手动绘制animateTo属性动画稳定 60fps状态更新全局刷新State精细化作用域减少无效渲染总结ArchivePage 的 875 行代码覆盖了鸿蒙应用开发中最常用的交互组合子页签 搜索防抖relation字段三态过滤 300ms 防抖两种过滤机制组合swipeAction右滑删除配合AlertDialog二次确认防止误操作名字哈希颜色hash5-hash简单哈希 5 色数组确定性美观头像底部对话框入场translate(y:300→0) 16ms 延迟触发底部上滑效果backdropBlur毛玻璃 TabBarArkUI 一行代码实现 iOS 质感下一篇预告第93篇 TrendPage——情绪趋势折线图与关键词云生成如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源List swipeAction APIAlertDialog 文档TextInput 防抖方案backdropBlur 毛玻璃animateTo 显式动画ArchiveDao 档案数据操作 → 第84篇入场动画设计 → 第59篇AppStorage 全局状态 → 第72篇七、ArchivePage 核心技术汇总7.1 防抖搜索实现StatesearchText:string;privatesearchTimer:number-1;onSearchChange(value:string){this.searchTextvalue;clearTimeout(this.searchTimer);this.searchTimersetTimeout((){this.filterArchives(value);// 300ms 防抖},300);}7.2 名字哈希头像颜色privategetAvatarColor(name:string):string{// 根据名字第一个字的 Unicode 码点取模constcodename.charCodeAt(0)%6;constcolors[#C4956A,#7BAE7F,#8BB4D4,#D4A478,#A488C4,#D47878];returncolors[code];}7.3 右滑删除 确认弹窗ListItem(){/* 档案卡片 */}.swipeAction({end:{builder:()this.deleteButton(archive.id),onAction:()this.confirmDelete(archive)}})privateconfirmDelete(archive:ArchiveInfo){AlertDialog.show({title:确认删除,message:删除「${archive.name}」档案将同时删除所有相关笔迹和报告此操作不可撤销,secondaryButton:{value:删除,fontColor:AppColors.errorRed,action:async(){awaitArchiveDao.delete(archive.id);this.loadArchives();}}});}ArchivePage 工程价值875 行代码综合运用了 ArkUI 几乎所有常用能力是学习鸿蒙工程化 UI 开发的最佳实战样本之一。防抖搜索、哈希头像色、滑动删除三个技术点可直接复用到其他项目。延伸阅读第84篇 ArchiveDao · 第85篇 HandwritingDao如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力