HarmonyOs应用《日记本》开发第16篇 - 日记列表页面 Index 详解
本篇深入剖析鸿蒙日记应用的核心入口页面——Index 日记列表页的完整实现涵盖页面结构、状态管理、数据加载与交互逻辑。一、页面概述Index 页面是整个日记应用的首页用户打开应用后首先看到的就是日记列表。该页面负责展示所有已创建的日记条目提供新建日记的入口FAB 浮动按钮支持点击进入日记详情支持长按删除日记空列表状态展示二、页面结构设计2.1 整体布局┌─────────────────────────┐ │ 标题栏 (日记) │ ├─────────────────────────┤ │ │ │ 日记列表 (List) │ │ ┌─────────────────┐ │ │ │ 日期 | 天气心情 │ │ │ │ 内容预览... │ │ │ └─────────────────┘ │ │ ┌─────────────────┐ │ │ │ 日期 | 天气心情 │ │ │ │ 内容预览... │ │ │ └─────────────────┘ │ │ │ │ ┌───┐ │ │ │ │ FAB │ │ └───┘ │ └─────────────────────────┘2.2 状态变量定义EntryComponentstruct Index{Statediaries:DiaryInfo[][]StateisLoading:booleanfalseprivatediaryStore:DiaryStoreDiaryStore.getInstance()aboutToAppear(){this.loadDiaries()}}关键点解析State diaries日记数组是页面的核心状态数据变化时自动触发 UI 刷新State isLoading加载状态标志控制加载动画的显示diaryStore通过单例模式获取数据存储实例避免重复创建三、数据加载逻辑3.1 aboutToAppear 生命周期aboutToAppear(){this.loadDiaries()}privateasyncloadDiaries(){this.isLoadingtruetry{this.diariesawaitthis.diaryStore.getAllDiaries()// 按日期降序排序this.diaries.sort((a,b){returnnewDate(b.date).getTime()-newDate(a.date).getTime()})}catch(error){console.error(加载日记失败: error)}finally{this.isLoadingfalse}}执行流程页面即将显示时自动触发aboutToAppear调用loadDiaries()从 Preferences 异步读取数据按日期降序排序最新的日记显示在最前面异常处理确保网络或存储错误不会导致页面崩溃3.2 页面刷新机制当用户从编辑页面返回时需要刷新列表数据onPageShow(){this.loadDiaries()}这确保了新建或编辑日记后列表能及时反映最新数据。四、列表渲染4.1 List 与 ForEachList({space:12}){ForEach(this.diaries,(diary:DiaryInfo,index:number){ListItem(){this.DiaryCard(diary)}.onClick((){this.goToDetail(diary.id)})},(diary:DiaryInfo)diary.id)}.width(100%).layoutWeight(1)ForEach 参数说明参数说明第一个参数数据源数组this.diaries第二个参数子项生成函数接收item和index第三个参数键值生成函数用于 Diff 算法的唯一标识关键提示键值生成函数返回diary.id确保列表项的唯一性在数据更新时能精确匹配并高效更新 DOM。4.2 日记卡片组件BuilderDiaryCard(diary:DiaryInfo){Row({space:12}){// 左侧日期Column(){Text(diary.day).fontSize(28).fontWeight(FontWeight.Bold)Text(diary.monthYear).fontSize(12).fontColor(#999)}.width(60).alignItems(HorizontalAlign.Center)// 右侧内容Column({space:6}){Row({space:8}){Text(diary.weather)Text(diary.mood)}Text(diary.content).fontSize(14).maxLines(2).textOverflow({overflow:TextOverflow.Ellipsis})}.layoutWeight(1).alignItems(HorizontalAlign.Start)}.width(100%).padding(16).backgroundColor(#FFFFFF).borderRadius(12).shadow({radius:4,color:rgba(0,0,0,0.08)})}卡片设计要点左右布局日期信息在左内容预览在右层次分明阴影效果轻微阴影提升卡片立体感圆角设计12px 圆角符合现代 UI 风格文本截断maxLines(2)Ellipsis确保内容过长时优雅截断五、空状态处理当没有日记时展示友好的空状态提示if(this.diaries.length0){Column({space:16}){Image($r(app.media.empty)).width(120).height(120)Text(还没有日记点击 开始记录吧).fontSize(16).fontColor(#999)}.width(100%).height(100%).justifyContent(FlexAlign.Center)}else{// 正常列表展示}空状态设计原则提供视觉引导插图或图标文案友好引导用户操作居中布局视觉平衡六、导航跳转6.1 跳转到详情页privategoToDetail(id:string){router.pushUrl({url:pages/DiaryDetail,params:{id:id}})}6.2 跳转到编辑页privategoToEdit(){router.pushUrl({url:pages/DiaryEdit,params:{mode:create}})}路由参数传递通过params对象传递参数目标页面通过router.getParams()获取支持字符串、数字、对象等多种类型七、浮动按钮 FABButton(){Image($r(app.media.add)).width(28).height(28)}.width(56).height(56).backgroundColor(#007DFF).borderRadius(28).position({right:20,bottom:20}).shadow({radius:8,color:rgba(0,125,255,0.3)}).onClick((){this.goToEdit()})FAB 实现要点使用position绝对定位固定在右下角圆形按钮borderRadius 宽度的一半蓝色阴影增强浮动感醒目的图标引导用户操作八、下拉刷新Refresh({refreshing:$$this.isRefreshing}){List({space:12}){ForEach(this.diaries,(diary:DiaryInfo){ListItem(){this.DiaryCard(diary)}},(diary:DiaryInfo)diary.id)}}.onRefreshing((){this.loadDiaries()})九、性能优化9.1 懒加载对于大量日记数据可以使用LazyForEach替代ForEachLazyForEach(this.diaryDataSource,(diary:DiaryInfo){ListItem(){this.DiaryCard(diary)}},(diary:DiaryInfo)diary.id)9.2 数据分页privateasyncloadDiaries(page:number0,pageSize:number20){constallDiariesawaitthis.diaryStore.getAllDiaries()conststartpage*pageSizeconstendstartpageSizeconstpageDataallDiaries.slice(start,end)if(page0){this.diariespageData}else{this.diariesthis.diaries.concat(pageData)}}十、总结Index 页面作为应用的首页承担了数据展示和导航枢纽的双重职责。其核心设计要点包括声明式 UI通过State驱动界面自动更新Builder 复用日记卡片通过Builder实现代码复用生命周期管理在aboutToAppear和onPageShow中处理数据加载用户体验空状态、加载状态、下拉刷新等细节完善性能考量ForEach 键值、懒加载等优化手段这些模式在鸿蒙 ArkUI 开发中非常通用掌握它们可以快速构建高质量的列表页面。