news 2026/6/8 15:37:29

鸿蒙原生应用实战(二):首页与诗词库页面开发——多元布局与交互实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
鸿蒙原生应用实战(二):首页与诗词库页面开发——多元布局与交互实现

鸿蒙原生应用实战(二):首页与诗词库页面开发——多元布局与交互实现

前言

在上一章中,我们完成了项目初始化和架构设计。本章将正式进入编码阶段,集中开发应用的两个核心页面:

  1. 首页(Index.ets)—— 信息聚合入口
  2. 诗词库(PoemListPage.ets)—— 搜索与筛选

这两个页面涉及了大量 ArkTS 布局技巧、组件复用和数据绑定模式,是鸿蒙开发的核心实战内容。

一、首页开发(Index.ets)

1.1 页面布局总览

首页从上到下分为五个区域:

┌──────────────────────┐ │ 标题栏 + 用户头像 │ ← Row + Column 组合 ├──────────────────────┤ │ 每日诗词推荐卡片 │ ← 渐变背景 + 引用样式 ├──────────────────────┤ │ 6 大分类入口 (Grid) │ ← 2 行 3 列网格 ├──────────────────────┤ │ 热门排行列表 │ ← 带序号和点赞数 ├──────────────────────┤ │ 为你推荐列表 │ ← 与排行相同结构 ├──────────────────────┤ │ 底部导航栏 │ ← 4 个 Tab └──────────────────────┘

1.2 数据结构定义

在 ArkTS 的严格模式下,所有对象字面量必须有显式类型声明

// 诗词条目接口interfacePoemItem{id:number;title:string;author:string;dynasty:string;content:string[];// 诗句数组type:string;// 五言绝句 / 词 / 乐府 ...likes:number;}// 每日推荐数据constdailyPoem:DailyPoem={title:'定风波',author:'苏轼',dynasty:'宋',excerpt:'竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生。'};// 热门排行数据consttopPoems:PoemItem[]=[{id:1,title:'静夜思',author:'李白',dynasty:'唐',content:['床前明月光','疑是地上霜','举头望明月','低头思故乡'],type:'五言绝句',likes:9852},// ... 更多诗词];

1.3 渐变背景卡片(每日诗词)

首页最醒目的"每日一首"卡片使用了渐变背景效果。在 ArkTS 中,可以通过background属性实现:

Column(){Text('每日一首').fontSize(12).fontColor('rgba(255,255,255,0.7)').width('100%')Text(dailyPoem.title).fontSize(22).fontWeight(FontWeight.Bold).fontColor(Color.White).width('100%').padding({top:8})Text('—— '+dailyPoem.dynasty+'·'+dailyPoem.author).fontSize(13).fontColor('rgba(255,255,255,0.8)').width('100%')// 居中展示经典名句Text(dailyPoem.excerpt).fontSize(17).fontColor(Color.White).lineHeight(28).textAlign(TextAlign.Center).padding({top:16,bottom:8})}.width('100%').padding(20)// 渐变色背景——紫色系渐变.background('linear-gradient(135deg, #667eea, #764ba2)').borderRadius(16)

技巧linear-gradient是 ArkTS 支持的背景渐变语法,适合做卡片头部装饰。

1.4 网格布局(6 大分类)

使用Grid组件实现 2 行 3 列的诗词分类入口:

Grid(){ForEach(categories,(cat:string)=>{GridItem(){this.createCategoryCard(cat)}},(cat:string)=>cat)}.columnsTemplate('1fr 1fr 1fr')// 3列等宽.rowsTemplate('1fr 1fr')// 2行.rowsGap(12).columnsGap(12).width('100%')

每个分类卡片包含 emoji 图标和文字标签,点击后跳转到诗词库页面并自动筛选该分类。

1.5 @Builder 组件复用

在 ArkTS 中,@Builder组件复用的核心机制。需要注意一个关键限制:@Builder 内不能声明变量

// ❌ 错误——@Builder 内不能有 const/interface@BuildercreateCategoryCard(name:string){consticons:Record<string,string>={...};// 编译报错!// ...}// ✅ 正确——将数据提取为普通方法getCatIcon(name:string):string{consticons:Record<string,string>={'唐诗三百':'📜','宋词精选':'🌸','元曲':'🎭','古诗十九首':'📖','乐府诗集':'🎵','诗经':'📗'};returnicons[name]||'📜';}@BuildercreateCategoryCard(name:string){Column(){Text(this.getCatIcon(name)).fontSize(28)Text(name).fontSize(12).fontColor($r('app.color.text_primary')).margin({top:8}).fontWeight(FontWeight.Medium)}// ...}

1.6 图片圆形容器

首页右上角的用户头像使用了Circle组件 +.overlay()的组合:

Circle().width(40).height(40).fill($r('app.color.accent_purple')).overlay(this.avatarText())

overlay是一个@Builder 方法

@BuilderavatarText(){Text('诗').fontColor(Color.White).fontSize(18).fontWeight(FontWeight.Bold)}

注意:在早期版本的 ArkTS 中,.overlay()不能直接接受Text()组件,必须通过@Builder方法包装。

二、诗词库页面开发(PoemListPage.ets)

2.1 交互功能概览

诗词库页面是用户浏览诗词的核心入口,包含三个维度:

交互维度实现方式数据来源
搜索TextInput组件用户输入,实时过滤
朝代筛选标签按钮 Row6 个选项(全部/先秦/唐/五代/宋/元)
类型筛选标签按钮 Row5 个选项(全部/五绝/七律/词/乐府)

2.2 数据过滤逻辑

之前我们使用了get filteredPoems()访问器,但在运行时发现其在模板中会返回undefined

// ❌ 不可行——get 访问器在模板返回 undefinedgetfilteredPoems():PoemItem[]{// ...过滤逻辑returnresult;// 运行时始终 undefined!}

正确做法:使用@State+@Watch组合:

@State@Watch('onFilterChange')searchText:string='';@State@Watch('onFilterChange')activeDynasty:string='all';@State@Watch('onFilterChange')activeType:string='all';@StatefilteredList:PoemItem[]=allPoems;// 存储过滤结果onFilterChange():void{letresult:PoemItem[]=allPoems;if(this.searchText.length>0){constkeyword:string=this.searchText.toLowerCase();result=result.filter((p:PoemItem)=>p.title.includes(keyword)||p.author.includes(keyword));}if(this.activeDynasty!=='all'){result=result.filter((p:PoemItem)=>p.dynasty===this.activeDynasty);}if(this.activeType!=='all'){result=result.filter((p:PoemItem)=>p.type===this.activeType);}this.filteredList=result;// 更新状态触发重新渲染}

工作原理:当searchTextactiveDynastyactiveType任一状态变化时,@Watch('onFilterChange')自动触发onFilterChange()方法,更新filteredList,UI 随之刷新。

2.3 搜索框实现

TextInput是鸿蒙中的文本输入组件:

Row(){Text('🔍').fontSize(16).margin({left:12})TextInput({placeholder:'搜索诗词名称或作者...',text:this.searchText}).layoutWeight(1).backgroundColor(Color.Transparent).fontSize(14).placeholderColor($r('app.color.text_secondary')).onChange((val:string)=>{this.searchText=val;})// 搜索框不为空时显示清除按钮if(this.searchText.length>0){Text('✕').fontSize(16).fontColor($r('app.color.text_secondary')).margin({right:12}).onClick(()=>{this.searchText='';})}}.width('100%').height(44).backgroundColor($r('app.color.bg_card')).borderRadius(22)// 圆角搜索框

2.4 筛选标签

筛选标签的样式逻辑:选中的标签用主题色填充,未选中的用白色:

Text(filter.label).fontSize(13).fontColor(filter.name===this.activeDynasty?Color.White:$r('app.color.text_secondary')).padding({left:14,right:14,top:6,bottom:6}).backgroundColor(filter.name===this.activeDynasty?$r('app.color.accent_purple'):$r('app.color.bg_card')).borderRadius(16).onClick(()=>{this.activeDynasty=filter.name;})

2.5 结果计数与空状态

// 结果计数Row(){Text('共 '+this.filteredList.length+' 首').fontSize(12).fontColor($r('app.color.text_secondary'))Blank()}// 空状态展示if(this.filteredList.length===0){Column(){Text('📖').fontSize(48)Text('没有找到相关诗词').fontSize(16).fontColor($r('app.color.text_secondary')).margin({top:12})}.width('100%').height(200).alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center)}

2.6 卡片列表

每条诗词卡片显示:序号、标题、类型标签、朝代·作者、诗文节选、点赞数:

@BuildercreatePoemCard(poem:PoemItem){Row(){// 序号Text(poem.id.toString()).fontSize(22).fontWeight(FontWeight.Bold).fontColor($r('app.color.accent_purple')).opacity(0.3)Column(){Row(){Text(poem.title).fontSize(17).fontWeight(FontWeight.Bold)Text(poem.type).fontSize(10).fontColor($r('app.color.accent_purple')).padding({left:6,right:6,top:2,bottom:2}).backgroundColor($r('app.color.accent_purple')+'15').borderRadius(4)}Text(poem.dynasty+' · '+poem.author).fontSize(13).fontColor($r('app.color.text_secondary'))// 诗文节选(最多两行)Text(poem.content[0]+(poem.content.length>1?','+poem.content[1]:'')).fontSize(14).fontColor($r('app.color.text_secondary')).maxLines(1).textOverflow({overflow:TextOverflow.Ellipsis})Text('❤ '+poem.likes.toString()).fontSize(12).fontColor($r('app.color.accent_red'))}}.width('100%').padding(14).backgroundColor($r('app.color.bg_card')).borderRadius(12).onClick(()=>{router.pushUrl({url:'pages/PoemDetailPage',params:{poemId:poem.id}});})}

三、跨页面参数传递

3.1 从作者页跳转到诗词库并搜索

AuthorPage点击诗人卡片后,会跳转到诗词库并自动填入作者名进行搜索:

// AuthorPage.ets.onClick(()=>{router.pushUrl({url:'pages/PoemListPage',params:{searchAuthor:author.name}});})// PoemListPage.ets — 接收参数aboutToAppear():void{constparams=router.getParams()asRecord<string,Object>;if(params&&params['searchAuthor']!==undefined){this.searchText=params['searchAuthor']asstring;// @Watch 会自动触发 onFilterChange,更新 filteredList}}

四、@Builder 中的 if 条件

在 ArkTS 中,if条件语句可以直接在build()@Builder中使用:

@BuildercreatePoemCard(poem:PoemItem){Row(){if(this.editMode){Circle()// 编辑模式下的选择框.width(22).height(22).stroke($r('app.color.accent_purple')).strokeWidth(2).fill(Color.Transparent)}// ... 其余内容}}

但需要注意:if条件内部只能包含 UI 组件语法,不能包含变量声明、函数调用赋值等。

小结

本章完成了首页和诗词库两个核心页面的开发,涵盖了:

  • 渐变背景卡片的设计
  • Grid 网格布局的使用
  • @Builder 组件复用技巧
  • 搜索 + 双维度筛选的实现
  • 跨页面参数传递
  • 数据过滤的最佳实践(@State + @Watch)

在下一章中,我们将继续开发诗词详情和作者天地两个页面,深入复杂数据展示和交互设计。


【系列目录】

  • (一)项目初始化与架构设计
  • (二)首页与诗词库页面开发 ← 本文
  • (三)诗词详情与作者天地页面开发
  • (四)收藏页面与底部导航实现
  • (五)编译调试与问题修复经验
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/8 15:35:43

MCX W72智能电源开关与VBAT管理实战:实现微安级深度睡眠与数据保持

1. 项目概述与核心价值 在电池供电的嵌入式设备开发中&#xff0c;我们常常面临一个核心矛盾&#xff1a;如何在需要时提供充沛的算力&#xff0c;而在空闲时又能将功耗降到极致&#xff0c;以延长续航。对于像NXP MCX W72这类面向物联网和便携式设备的高性能微控制器&#xff…

作者头像 李华
网站建设 2026/6/8 15:34:36

深度解析:OpCore-Simplify如何实现黑苹果EFI配置的智能自动化

深度解析&#xff1a;OpCore-Simplify如何实现黑苹果EFI配置的智能自动化 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify OpCore-Simplify是一款创新的…

作者头像 李华
网站建设 2026/6/8 15:32:32

终极MCprep指南:5分钟让Blender变成Minecraft动画神器

终极MCprep指南&#xff1a;5分钟让Blender变成Minecraft动画神器 【免费下载链接】MCprep Blender python addon to increase workflow for creating minecraft renders and animations 项目地址: https://gitcode.com/gh_mirrors/mc/MCprep 你是否曾为制作Minecraft动…

作者头像 李华
网站建设 2026/6/8 15:31:23

华硕笔记本性能瓶颈如何破解?G-Helper轻量级控制中心全攻略

华硕笔记本性能瓶颈如何破解&#xff1f;G-Helper轻量级控制中心全攻略 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenboo…

作者头像 李华
网站建设 2026/6/8 15:31:20

python-dotenv:从 .env 文件加载环境变量

文章目录python-dotenv&#xff1a;从 .env 文件加载环境变量python-dotenv&#xff1a;从 .env 文件加载环境变量 python-dotenv 是一个用于读取 .env 文件并将键值对设置为环境变量的 Python 库&#xff0c;目前获得了 8,779 个 Star。 该库的设计目标是为遵循 12-factor 原…

作者头像 李华
网站建设 2026/6/8 15:28:31

NVIDIA Profile Inspector完全指南:从新手到专家的显卡配置秘籍

NVIDIA Profile Inspector完全指南&#xff1a;从新手到专家的显卡配置秘籍 【免费下载链接】nvidiaProfileInspector 项目地址: https://gitcode.com/gh_mirrors/nv/nvidiaProfileInspector 还在为游戏卡顿、画面撕裂和性能瓶颈而烦恼吗&#xff1f;NVIDIA Profile In…

作者头像 李华