news 2026/6/14 3:26:53

鸿蒙原生应用开发实战(三):数据管理与多页面交互——渔获记录、装备管理与个人中心

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
鸿蒙原生应用开发实战(三):数据管理与多页面交互——渔获记录、装备管理与个人中心

鸿蒙原生应用开发实战(三):数据管理与多页面交互——渔获记录、装备管理与个人中心

前言

上一篇我们完成了首页的开发,本篇文章将继续构建三个重要页面:

  • 渔获记录页(CatchRecordPage):展示每次出钓的鱼获信息
  • 装备管理页(GearPage):管理钓鱼装备清单
  • 个人中心页(ProfilePage):用户统计信息和设置

通过这三个页面,我们将深入学习List组件的高级用法组件复用@Prop父子组件通信分类筛选等核心技巧。


一、渔获记录页:List组件的深度应用

渔获记录页是一个典型的列表页面,展示用户每次钓鱼的成果:鱼种、重量、长度、钓点和日期。

1.1 数据模型

interfaceCatchRecord{id:number;date:string;// 日期spot:string;// 钓点fishType:string;// 鱼种weight:string;// 重量length:string;// 长度}

1.2 List vs Scroll + ForEach

很多新手会问:什么时候用List,什么时候用Scroll + ForEach

场景推荐方案原因
简单垂直排列,数量少Scroll + ForEach轻量,无复用
长列表,性能敏感List + ListItem列表项复用,滑动性能更好
卡片之间有特殊间距List + ListItem支持space属性
需要侧滑删除List内置侧滑能力

渔获记录页使用List + ListItem方案:

List(){ForEach(this.records,(record:CatchRecord)=>{ListItem(){// 卡片内容Column(){Row(){Text('🐟').fontSize(28)Column(){Text(record.fishType).fontSize(18).fontWeight(FontWeight.Medium)Text(record.spot).fontSize($r('app.float.small_font_size')).fontColor($r('app.color.text_hint')).margin({top:2})}.margin({left:12})Blank()Column(){Text(record.weight).fontSize($r('app.float.body_font_size')).fontWeight(FontWeight.Medium).fontColor($r('app.color.primary'))Text(record.length).fontSize($r('app.float.small_font_size')).fontColor($r('app.color.text_secondary'))}.alignItems(HorizontalAlign.End)}Text(record.date).fontSize(12).fontColor($r('app.color.text_hint')).margin({top:6})}.padding($r('app.float.padding_medium')).backgroundColor($r('app.color.card_bg')).borderRadius($r('app.float.card_corner_radius'))}.padding({left:16,right:16,top:6,bottom:6})},(record:CatchRecord)=>record.id.toString())}.width('100%').layoutWeight(1)

ListItem 的 padding 技巧

  • ListItem 本身设置padding控制卡片之间的间距
  • 内部的 Column 设置padding控制卡片内边距
  • 通过内外两层 padding 实现精准的间距控制

1.3 空状态设计

if(this.records.length===0){Column(){Text('🐟').fontSize(60)Text('暂无渔获记录').fontSize($r('app.float.body_font_size')).fontColor($r('app.color.text_hint')).margin({top:16})}.width('100%').height('80%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)}else{List(){/* ... */}}

1.4 标题栏与操作按钮

Row(){Button('←').fontSize(22).fontColor($r('app.color.text_primary')).backgroundColor(Color.Transparent).onClick(()=>{router.back();})Text($r('app.string.title_catch_record')).fontSize($r('app.float.page_title_font_size')).fontWeight(FontWeight.Bold).margin({left:12})Blank()Button($r('app.string.add_record')).fontSize($r('app.float.small_font_size')).fontColor(Color.White).backgroundColor($r('app.color.primary')).borderRadius(16).padding({left:12,right:12,top:4,bottom:4})}

设计亮点

  • 返回按钮使用Color.Transparent背景,点击无闪烁
  • 右侧"添加记录"按钮使用主题色,吸引用户操作
  • BorderRadius(16)配合padding实现圆角胶囊按钮

二、装备管理页:分类渲染与状态颜色

装备管理页展示用户的钓鱼装备,按类型分组显示,并标注每件装备的状态。

2.1 数据模型

interfaceGearItem{id:number;name:string;// 装备名称type:string;// 类型:鱼竿/鱼轮/鱼线/鱼钩/鱼饵spec:string;// 规格status:string;// 状态:良好/充足/需更换}

2.2 分类展示策略

不同于渔获记录的简单列表,装备页需要按类型分组展示。我们采用 Scroll + Column + 多次 ForEach 的方案:

Column(){// 分类标题 - 鱼竿Text('🎣 鱼竿').fontSize($r('app.float.body_font_size')).fontWeight(FontWeight.Medium).width('100%').margin({bottom:8})ForEach(this.gearList.filter((g:GearItem)=>g.type==='鱼竿'),(item:GearItem)=>{// 渲染鱼竿})// 分类标题 - 配件Text('🛠️ 配件').fontSize($r('app.float.body_font_size')).fontWeight(FontWeight.Medium).width('100%').margin({top:8,bottom:8})ForEach(this.gearList.filter((g:GearItem)=>g.type!=='鱼竿'),(item:GearItem)=>{// 渲染配件})}

知识点filter()在ArkTS中完全可用,配合 ForEach 实现分类渲染。如果数据量很大,建议在 getter 中预处理分类数据。

2.3 状态标签颜色映射

根据不同状态显示不同颜色的标签:

Text(item.status).fontSize($r('app.float.badge_font_size')).fontColor(item.status==='良好'?$r('app.color.status_delivered'):item.status==='充足'?$r('app.color.status_normal'):$r('app.color.status_exception')).backgroundColor(item.status==='良好'?'#FFE8F5E9':// 绿色背景item.status==='充足'?'#FFE3F2FD':// 蓝色背景'#FFFFEBEE'// 红色背景).padding({left:8,right:8,top:2,bottom:2}).borderRadius(10)

视觉设计原则

  • 良好/充足:正面状态用绿色/蓝色
  • 需更换:警告状态用红色
  • 圆角标签 + 浅色背景,视觉友好不刺眼

2.4 装备卡片布局

Row(){Column(){Text(item.name).fontSize($r('app.float.body_font_size')).fontWeight(FontWeight.Medium)Text(item.spec).fontSize($r('app.float.small_font_size')).fontColor($r('app.color.text_hint')).margin({top:2})}Blank()Text(item.status)// 状态标签}

三、个人中心页:@Prop子组件通信

个人中心页包含用户信息、统计数据和设置菜单。这里我们引入子组件的概念。

3.1 页面整体结构

build(){Column(){// 标题栏Row(){/* 个人中心 */}Scroll(){Column(){// 用户信息卡片Column(){Circle().width(72).height(72).fill($r('app.color.primary'))Text('钓鱼爱好者').fontSize(20).fontWeight(FontWeight.Medium)Text('🎣 享受每一次抛竿').fontSize($r('app.float.small_font_size')).fontColor($r('app.color.text_hint'))}.alignItems(HorizontalAlign.Center)// 统计卡片StatsCard()// 封装为子组件// 设置菜单MenuCard()}}}}

3.2 统计卡片:Row + layoutWeight 三等分

Row(){Column(){Text('12').fontSize(28).fontWeight(FontWeight.Bold).fontColor($r('app.color.primary'))Text($r('app.string.total_catch')).fontSize($r('app.float.small_font_size'))}.layoutWeight(1).alignItems(HorizontalAlign.Center)Column(){Text('3.2kg').fontSize(28).fontWeight(FontWeight.Bold).fontColor($r('app.color.rating_star'))Text($r('app.string.best_record'))}.layoutWeight(1).alignItems(HorizontalAlign.Center)Column(){Text('4').fontSize(28).fontWeight(FontWeight.Bold).fontColor($r('app.color.status_delivered'))Text('探钓点数')}.layoutWeight(1).alignItems(HorizontalAlign.Center)}

layoutWeight(1)实现三列等分,无需手动计算宽度。

3.3 @Prop 子组件:MenuItemRow

这是本页最重要的知识点——父子组件通信。我们先定义一个复用性高的菜单行组件:

@Componentstruct MenuItemRow{@Proplabel:string='';@Propvalue:string='';build(){Row(){Text(this.label).fontSize($r('app.float.body_font_size')).fontColor($r('app.color.text_primary'))Blank()if(this.value.length>0){Text(this.value).fontSize($r('app.float.small_font_size')).fontColor($r('app.color.text_hint')).margin({right:8})}Text('>').fontSize(18).fontColor($r('app.color.text_hint'))}.width('100%').height(52).padding({left:16,right:16})}}

在父组件中使用:

Column(){MenuItemRow({label:'我的装备',value:'5件'})Divider().width('100%')MenuItemRow({label:'个人最佳记录',value:'草鱼 3.2kg'})Divider().width('100%')MenuItemRow({label:'通知设置',value:''})Divider().width('100%')MenuItemRow({label:'关于',value:'v1.0.0'})}

@Prop 的核心特性

特性说明
单向数据流父→子,子组件不能修改父组件数据
默认值@Prop label: string = ''提供默认值
必须初始化使用组件时必须传递或使用默认值
触发更新@Prop 变化会触发子组件重新渲染

对比 @State vs @Prop

  • @State:组件内部状态,变化触发自身渲染
  • @Prop:从父组件接收的状态,变化触发自身渲染
  • @Link:双向绑定(后续文章会介绍)

3.4 Divider 分割线

Divider().width('100%')// 默认横向

Divider 默认高度为 1px,颜色使用$r('app.color.divider')。我们可以在 color.json 中统一配置:

{"name":"divider","value":"#FFE0E0E0"}

四、页面路由与导航架构

4.1 路由跳转方式汇总

项目中使用了两种路由跳转模式:

// 1. 返回上一页router.back()// 2. 跳转到新页面(不带参数)router.pushUrl({url:'pages/GearPage'})// 3. 跳转到新页面(带参数)router.pushUrl({url:'pages/SpotDetailPage',params:{spotData:spot}})

4.2 导航流程设计

Index (首页) ├── SpotDetailPage (点击钓点卡片 → pushUrl 传参) ├── CatchRecordPage (底部导航 → pushUrl) ├── GearPage (底部导航 → pushUrl) └── ProfilePage (底部导航 → pushUrl) 各子页面 → back() 返回首页

4.3 返回按钮统一模式

所有子页面的返回按钮采用统一风格:

Button('←').fontSize(22).fontColor($r('app.color.text_primary')).backgroundColor(Color.Transparent).onClick(()=>{router.back();})

五、ArkTS 严格模式实战避坑

在开发这三个页面时,有几个严格模式的常见坑需要注意:

5.1 非推断数组字面量

// ❌ 错误:无法推断数组元素类型privaterecords=[{id:1,date:'2025-01-12',spot:'清溪河下游'}];// ✅ 正确:显式声明类型privaterecords:CatchRecord[]=[{id:1,date:'2025-01-12',spot:'清溪河下游',fishType:'鲫鱼',weight:'0.8kg',length:'28cm'}];

5.2 对象字面量类型声明

// ❌ 错误:未类型化的对象字面量letp={spotData:spot};// ✅ 正确:声明接口类型letp:SpotParams={spotData:spot};

5.3 router.getParams 的类型断言

// 使用 as 类型断言constparams=router.getParams()asSpotDetailParams;

六、性能优化小技巧

6.1 ForEach 的 key 生成

为每个列表项生成唯一且稳定的 key:

// ✅ 使用 idForEach(arr,fn,(item)=>item.id.toString())// ✅ 使用唯一索引(如果顺序不变)ForEach(arr,fn,(item,index)=>index.toString())

6.2 List 的复用机制

List + ListItem拥有列表项复用能力。当列表滑动时,移出屏幕的 ListItem 会被回收,移入屏幕时复用。这与Scroll + ForEach每项都创建的机制不同,在长列表中性能差距显著。

6.3 条件渲染减少节点

// ✅ 空状态和列表互斥,只渲染一种if(condition){// 空状态}else{// 列表}// ❌ 不要同时渲染再用 visible 隐藏

七、小结

本篇我们完成了三个核心页面的开发:

页面核心技术点难度
渔获记录 CatchRecordPageList + ListItem, 空状态, 列表项复用⭐⭐
装备管理 GearPage分类渲染, filter过滤, 状态颜色映射⭐⭐⭐
个人中心 ProfilePage@Prop子组件, 布局Weight分配, 统计卡片⭐⭐⭐

下一篇我们将开发项目中最复杂的两个页面——鱼种百科(分类筛选+搜索)和钓点详情(动态参数接收+评分交互),敬请期待!


项目源码:基于 HarmonyOS API 23 + Stage模型 + ArkTS
系列目录

  • 第一篇:项目初始化与环境配置
  • 第二篇:首页与钓点列表开发
  • 第三篇:数据管理与多页面交互(本篇)
  • 第四篇:复杂页面与交互体验
  • 第五篇:地图可视化与性能优化
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/14 3:12:58

从手机快充到电动汽车:不同场景下MOSFET选型思路全解析

从手机快充到电动汽车:不同场景下MOSFET选型思路全解析在电子设备功率转换的核心地带,MOSFET如同精密交响乐团的指挥家,以每秒数百万次的开关动作调控能量流动。当65W氮化镓充电器能在30分钟内为手机充满电,当无人机电调实现毫秒级…

作者头像 李华
网站建设 2026/6/14 3:10:01

用MATLAB手把手仿真QPSK、OQPSK和IJF-OQPSK:从眼图到星座图的完整对比分析

MATLAB实战:QPSK、OQPSK与IJF-OQPSK调制技术的可视化对比指南通信工程师工具箱里最实用的技能之一,就是能通过仿真直观比较不同调制技术的优劣。记得我第一次用MATLAB对比QPSK和OQPSK时,眼图中那个微妙的相位跳变差异让我瞬间理解了教科书上十…

作者头像 李华