news 2026/6/14 20:30:10

【鸿蒙原生应用开发实战】第四篇:详情页与收藏交互 — 动态数据切换与用户交互设计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【鸿蒙原生应用开发实战】第四篇:详情页与收藏交互 — 动态数据切换与用户交互设计

【鸿蒙原生应用开发实战】第四篇:详情页与收藏交互 — 动态数据切换与用户交互设计

前言

详情页是内容型App中最关键的页面,它承载着对内容的深度展示和用户交互。在"宇宙探索"App中,DetailPage不仅要展示8个天体的详细数据,还要处理收藏交互、路由传参、动态数据切换等复杂逻辑。

本篇你将学到:

  • 路由参数接收与动态数据加载
  • 信息网格布局设计
  • 收藏按钮的状态切换
  • 趣味知识模块展示
  • 从详情页返回的数据一致性

一、页面功能总览

DetailPage包含以下内容模块:

模块内容实现方式
顶部返回← 返回按钮router.back()
天体名称区中文名 + 英文名 + 类型标签垂直居中布局
描述区天体详细文字描述多行文本
基本信息质量/直径/距离/温度2×2 网格卡片
趣味知识一个冷知识特殊底色区块
收藏按钮收藏/取消收藏@State 状态切换

二、完整代码实现

2.1 InfoItem 组件

importrouterfrom'@ohos.router';import{CelestialData,CELESTIAL_LIST,FavoriteManager}from'../model/CelestialData';@Componentstruct InfoItem{label:string='';value:string='';build(){Column(){Text(this.value).fontSize($r('app.float.app_small_size')).fontColor($r('app.color.app_color_white')).fontWeight(FontWeight.Bold);Text(this.label).fontSize($r('app.float.app_caption_size')).fontColor($r('app.color.app_color_text_secondary')).margin({top:4});}.width('45%').padding(12).backgroundColor('rgba(255, 255, 255, 0.05)').borderRadius(10).alignItems(HorizontalAlign.Center);}}

设计解读

  • width('45%')— 两个 Item 并排布局,留出10%间隔
  • 半透明白色背景rgba(255,255,255,0.05)— 卡片感但不抢眼
  • 值大标题、标签小字 — 对比强化阅读层次

2.2 接口定义

interfaceInfoPair{label:string;value:string;}

这个接口在文件末尾定义(不在@Component内),用于infoItems数组的类型声明。

2.3 详情页主组件

@Entry@Componentstruct DetailPage{@Statedata:CelestialData={id:0,name:'',englishName:'',type:'',description:'',mass:'',diameter:'',distance:'',temperature:'',fact:'',color:'#FFFFFF',isFavorite:false};@StateisFav:boolean=false;@StateinfoItems:InfoPair[]=[];aboutToAppear():void{// 1. 从路由参数获取天体IDconstparams=router.getParams()asRecord<string,Object>;if(params&&params['id']!==undefined){constid=Number(params['id']);// 2. 遍历数据源找到对应天体for(leti=0;i<CELESTIAL_LIST.length;i++){if(CELESTIAL_LIST[i].id===id){this.data=CELESTIAL_LIST[i];break;}}}// 3. 检查收藏状态this.isFav=FavoriteManager.isFavorite(this.data.id);// 4. 组装信息条目this.infoItems=[{label:'质量',value:this.data.mass},{label:'直径',value:this.data.diameter},{label:'距地距离',value:this.data.distance},{label:'温度',value:this.data.temperature}];}toggleFav():void{this.isFav=FavoriteManager.toggle(this.data.id);this.data.isFavorite=this.isFav;}build(){Column(){Scroll(){Column(){// ===== 顶部返回 =====Row(){Text('←').fontSize(24).fontColor($r('app.color.app_color_white')).onClick(()=>{router.back();});}.width('100%').padding({left:16,top:12});// ===== 天体名称区域 =====Column(){Text(this.data.name).fontSize(48).fontColor($r('app.color.app_color_white')).fontWeight(FontWeight.Bold);Text(this.data.englishName).fontSize($r('app.float.app_body_size')).fontColor($r('app.color.app_color_text_secondary')).margin({top:8});Text(this.data.type).fontSize($r('app.float.app_small_size')).fontColor(this.data.color).padding({left:16,right:16,top:4,bottom:4}).backgroundColor('rgba(255, 255, 255, 0.08)').borderRadius(20).margin({top:12});}.width('100%').padding({top:20,bottom:24}).alignItems(HorizontalAlign.Center);// ===== 描述 =====Text(this.data.description).fontSize($r('app.float.app_body_size')).fontColor($r('app.color.app_color_white')).lineHeight(24).padding({left:16,right:16});// ===== 基本信息(2×2网格) =====Text('基本信息').fontSize($r('app.float.app_body_size')).fontColor($r('app.color.app_color_accent')).fontWeight(FontWeight.Bold).width('100%').padding({left:16,top:24,bottom:12});Row(){ForEach(this.infoItems,(item:InfoPair)=>{InfoItem({label:item.label,value:item.value})},(item:InfoPair)=>item.label)}.width('100%').padding({left:16,right:16}).justifyContent(FlexAlign.SpaceBetween);// ===== 趣味知识 =====Text('✨ 趣味知识').fontSize($r('app.float.app_body_size')).fontColor($r('app.color.app_color_accent')).fontWeight(FontWeight.Bold).width('100%').padding({left:16,top:24,bottom:12});Text(this.data.fact).fontSize($r('app.float.app_small_size')).fontColor($r('app.color.app_color_white')).lineHeight(22).padding({left:16,right:16,top:12,bottom:12}).backgroundColor('rgba(255, 215, 0, 0.06)').borderRadius(12).margin({left:16,right:16,bottom:24});// ===== 收藏按钮 =====Button(){Text(this.isFav?'★ 已收藏':'☆ 收藏').fontSize($r('app.float.app_body_size')).fontColor($r('app.color.app_color_white'));}.width('80%').height(48).backgroundColor(this.isFav?'#FF6B6B':'#0F3460').borderRadius($r('app.float.app_button_radius')).margin({top:12,bottom:32}).onClick(()=>{this.toggleFav();});}.width('100%');}.layoutWeight(1);}.width('100%').height('100%').backgroundColor($r('app.color.app_color_background'));}}

三、关键技术点解析

3.1 路由参数接收与动态数据加载

这是详情页最核心的机制——根据不同的路由参数展示不同天体的数据

参数传递(发送端)

// 从首页热门卡片跳转router.pushUrl({url:'pages/DetailPage',params:{id:this.item.id}});// 从首页每日天文区跳转(固定展示地球)router.pushUrl({url:'pages/DetailPage',params:{id:4}});// 从收藏列表跳转router.pushUrl({url:'pages/DetailPage',params:{id:item.id}});

参数接收与数据匹配(接收端)

aboutToAppear():void{constparams=router.getParams()asRecord<string,Object>;if(params&&params['id']!==undefined){constid=Number(params['id']);// 线性查找匹配的天体for(leti=0;i<CELESTIAL_LIST.length;i++){if(CELESTIAL_LIST[i].id===id){this.data=CELESTIAL_LIST[i];break;}}}// 初始化收藏状态this.isFav=FavoriteManager.isFavorite(this.data.id);// 组装信息条目this.infoItems=[{label:'质量',value:this.data.mass},{label:'直径',value:this.data.diameter},{label:'距地距离',value:this.data.distance},{label:'温度',value:this.data.temperature}];}

数据流链路

用户点击卡片 → router.pushUrl({ params: { id: N } }) → DetailPage.aboutToAppear() → 读取 params.id → CELESTIAL_LIST 中查找 id === N → this.data = 匹配到的天体数据 → UI 自动刷新展示该天体

3.2 @State 状态管理的双重绑定

在这个页面中有三个@State变量:

@Statedata:CelestialData;// 当前展示的天体数据@StateisFav:boolean;// 收藏状态的开关@StateinfoItems:InfoPair[];// 信息条目列表

每个变量的变化都会触发对应 UI 的重新渲染:

@State 变量变更时机影响UI
dataaboutToAppear()从路由参数加载名称、描述、基本信息、趣味知识全部刷新
isFavtoggleFav()用户点击收藏按钮文字(★已收藏/☆收藏)和颜色
infoItemsaboutToAppear()初始化时组装四个 InfoItem 卡片

3.3 收藏按钮的状态切换

toggleFav():void{this.isFav=FavoriteManager.toggle(this.data.id);this.data.isFavorite=this.isFav;}

这短短两行做了三件事:

  1. 调用FavoriteManager.toggle(id)— 修改数据层,添加或移除收藏
  2. this.isFav = 返回值@State变量变化,触发UI刷新收藏按钮
  3. 同步到this.data.isFavorite— 保持数据对象一致性,防止页面间数据不同步

按钮视觉反馈

状态文字背景色含义
未收藏☆ 收藏#0F3460(深蓝)点击即可收藏
已收藏★ 已收藏#FF6B6B(红色)点击取消收藏

3.4 类型标签的专属色

天体类型标签使用了该天体的专属颜色:

Text(this.data.type).fontColor(this.data.color)

这意味着:

  • 太阳(恒星)→#FF6B35橙色标签
  • 地球(行星)→#4B7B8A蓝绿色标签
  • 银河系(星系)→#6B8EC4蓝色标签
  • 猎户座大星云(星云)→#FF69B4粉色标签

每个标签还加上了胶囊背景

.backgroundColor('rgba(255, 255, 255, 0.08)').borderRadius(20)

半透明背景让标签看起来更"立体",borderRadius(20)制造胶囊圆角效果。

3.5 趣味知识模块

Text(this.data.fact).fontSize($r('app.float.app_small_size')).fontColor($r('app.color.app_color_white')).lineHeight(22).backgroundColor('rgba(255, 215, 0, 0.06)')// 极淡金色背景.borderRadius(12)

趣味知识模块用三个细节区别于普通内容:

  • 淡金色背景rgba(255, 215, 0, 0.06)— 暗示"知识亮点"
  • ✨ 前缀— 段落标题前的emoji,增加趣味性
  • 适中行高lineHeight(22)— 确保长文本可读性

四、信息网格布局详解

4.1 2×2 网格的实现

Row(){ForEach(this.infoItems,(item:InfoPair)=>{InfoItem({label:item.label,value:item.value})},(item:InfoPair)=>item.label)}.width('100%').padding({left:16,right:16}).justifyContent(FlexAlign.SpaceBetween);

infoItems数组有4项,ForEach 会渲染4个InfoItem

  • 每个InfoItem宽度45%→ 一行放2个 → 两行正好4个
  • SpaceBetween自动在元素之间分配空间

4.2 InfoItem 组件的细节

Column(){Text(this.value)// 值(大号、白色、加粗)Text(this.label)// 标签(小号、灰色)}.width('45%').backgroundColor('rgba(255, 255, 255, 0.05)')// 半透明白色底.borderRadius(10).alignItems(HorizontalAlign.Center);

这个组件体现了视觉层次的设计原则:

  • 值比标签大两号(small_size: 14fpvscaption_size: 12fp
  • 值是白色,标签是灰色,主次分明
  • 值加粗,标签不加粗
  • 半透明背景营造卡片感

五、页面间数据一致性

5.1 从详情页返回后列表页刷新收藏状态

这是一个常见的跨页面数据同步问题。用户在详情页收藏/取消收藏后,返回列表页时需要看到最新的收藏状态。

实现方案

FavPageCelestialPage中使用onPageShow生命周期钩子:

// FavPage.ets — 收藏列表页onPageShow():void{this.loadFavorites();// 每次显示都重新加载收藏数据}// CelestialPage.ets — 天体列表页onPageShow():void{this.applyFilter();// 重新应用筛选,刷新收藏状态}

流程

DetailPage 中收藏/取消收藏 → router.back() → 返回到 FavPage / CelestialPage → onPageShow() 被触发 → 重新从 FavoriteManager 读取最新数据 → @State 更新 → UI 刷新

5.2 router.back() 的正确使用

// 详情页的返回按钮Text('←').onClick(()=>{router.back();// 返回上一页});

router.back()不需要传参,框架会自动返回到跳转到当前页的上一页。

路由栈示意图

Index → CelestialPage → DetailPage ↓ back() CelestialPage ← onPageShow() 触发刷新 收藏列表页: FavPage → DetailPage ↓ back() FavPage ← onPageShow() 触发刷新

六、完整页面展示效果

以"地球"为例,DetailPage的展示效果:

┌──────────────────────────────┐ │ ← │ │ │ │ 地 球 │ │ Earth │ │ ┌──────┐ │ │ │ 行星 │ │ │ └──────┘ │ │ │ │ 地球是太阳系中唯一已知存在 │ │ 生命的行星,拥有液态水和 │ │ 适宜的大气层... │ │ │ │ 基本信息 │ │ ┌──────────┐ ┌──────────┐ │ │ │ 5.972×10²⁴│ │ 12,742km │ │ │ │ 质量 │ │ 直径 │ │ │ └──────────┘ └──────────┘ │ │ ┌──────────┐ ┌──────────┐ │ │ │1.496亿km │ │ 平均15°C │ │ │ │ 距地距离 │ │ 温度 │ │ │ └──────────┘ └──────────┘ │ │ │ │ ✨ 趣味知识 │ │ ┌──────────────────────────┐ │ │ │ 地球是太阳系中密度最大 │ │ │ │ 的行星。约71%的表面被水 │ │ │ │ 覆盖,被称为"蓝色星球"。 │ │ │ └──────────────────────────┘ │ │ │ │ ┌────────────────┐ │ │ │ ☆ 收藏 │ │ │ └────────────────┘ │ └──────────────────────────────┘

七、本篇总结

本片完成了DetailPage详情页的完整开发,核心收获:

  1. 动态数据加载— 通过路由参数id动态切换展示不同天体的详细数据
  2. 信息网格布局— 2×2 网格展示质量/直径/距离/温度四维信息
  3. 收藏交互— 按钮状态切换的完整实现,数据层+UI层联动
  4. 趣味知识模块— 特殊视觉样式的知识点展示区块
  5. 页面间数据一致性router.back()+onPageShow()确保返回时列表页刷新
  6. InfoItem 组件复用— 可复用的信息卡片组件设计

下篇预告:最后一篇我们将完成FavPage(收藏列表页)和ProfilePage(个人中心页),包含收藏管理、空状态设计、旅行统计、功能菜单等完整功能。


本篇涉及的文件

  • entry/src/main/ets/pages/DetailPage.ets— 详情页主组件
  • entry/src/main/ets/model/CelestialData.ets— 数据源与收藏管理
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/14 20:30:07

2026年实用降AIGC网站:亲测AI率从90%降至4%的省心方案

一、前言&#xff1a;2026年毕业必过AIGC检测门槛 2026年国内高校对学术论文的AIGC疑似度审核全面收紧&#xff0c;绝大多数院校都发布了明确的AIGC检测数值要求&#xff1a;985、211院校规定本科论文AI率需低于20%&#xff0c;硕士论文AI率不得高于15%&#xff0c;普通高校也普…

作者头像 李华
网站建设 2026/6/14 20:27:46

无需训练,3分钟掌握专业级AI换脸:roop-unleashed完整指南

无需训练&#xff0c;3分钟掌握专业级AI换脸&#xff1a;roop-unleashed完整指南 【免费下载链接】roop-unleashed Evolved Fork of roop with Web Server and lots of additions 项目地址: https://gitcode.com/gh_mirrors/ro/roop-unleashed 你想过只需几张照片就能制…

作者头像 李华
网站建设 2026/6/14 20:27:03

3步诊断法:让2015年前的老Mac重获新生,运行最新macOS系统

3步诊断法&#xff1a;让2015年前的老Mac重获新生&#xff0c;运行最新macOS系统 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 你是否曾为手中性能依然强劲…

作者头像 李华
网站建设 2026/6/14 20:24:04

LRCGET终极指南:10分钟搞定离线音乐库歌词同步难题

LRCGET终极指南&#xff1a;10分钟搞定离线音乐库歌词同步难题 【免费下载链接】lrcget Utility for mass-downloading LRC synced lyrics for your offline music library. 项目地址: https://gitcode.com/gh_mirrors/lr/lrcget 你是否拥有一个庞大的本地音乐库&#x…

作者头像 李华
网站建设 2026/6/14 20:23:53

深度解析:基于视觉感知的鸣潮智能操作引擎技术实现

深度解析&#xff1a;基于视觉感知的鸣潮智能操作引擎技术实现 【免费下载链接】ok-wuthering-waves 鸣潮 后台自动战斗 自动刷声骸 一键日常 Automation for Wuthering Waves 项目地址: https://gitcode.com/GitHub_Trending/ok/ok-wuthering-waves 在当今游戏自动化领…

作者头像 李华