news 2026/7/20 19:24:41

HarmonyOS ArkTS 工具网格与路由导航:从小工具百宝箱看卡片式布局与页面跳转的实战技巧

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HarmonyOS ArkTS 工具网格与路由导航:从小工具百宝箱看卡片式布局与页面跳转的实战技巧

引子:一个应用塞五个小工具

"工具箱"应用——把二维码生成、单位换算、随机决策、颜色提取、倒计时五个小工具集成到一个应用里。需求很简单:首页放五个卡片,点击跳转到对应工具页面。

看起来就是"画五个卡片,加个跳转",但做起来发现几个细节要处理:卡片的阴影和圆角怎么配合、网格布局怎么自适应、路由跳转怎么传参、渐变背景怎么和卡片颜色协调。

这个应用虽然功能不复杂,但涉及了 ArkUI 开发的多个实用知识点。今天就从 Index.ets 的代码出发,聊聊工具网格的设计和路由导航的实现。
完整效果

项目结构:多页面的应用架构

和星空运势应用不同,这个工具箱是多页面架构——每个工具一个独立页面:

entry/src/main/ets/ ├── pages/ │ ├── Index.ets # 首页(工具网格) │ ├── QRGenerator.ets # 二维码生成 │ ├── UnitConverter.ets # 单位换算 │ ├── RandomTool.ets # 随机决策 │ ├── ColorPicker.ets # 颜色提取 │ └── Countdown.ets # 倒计时 ├── entryability/ │ └── EntryAbility.ets └── resources/

为什么用多页面而不是 Swiper

星空运势应用用 Swiper 在三个页面间切换,因为三个功能是并列的,用户可能频繁切换。但工具箱的五个工具是独立的——用户通常只用一个工具,不需要在工具间切换。

用路由跳转(router.pushUrl)更合适:

  • 每个工具独立运行,不共享状态
  • 跳转到工具页面后,用户可以返回首页再选另一个工具
  • 页面栈管理更清晰(push 进去,pop 回来)

router 的引入

import{router}from'@kit.ArkUI';

router是 ArkUI 的页面路由模块,提供页面跳转、返回、传参等功能。@kit.ArkUI是鸿蒙系统的 UI 框架包,包含所有 UI 相关的 API。

ToolItem 接口:工具数据的建模

interfaceToolItem{name:string;// 工具名称desc:string;// 工具描述icon:string;// emoji 图标page:string;// 跳转页面路径color:string;// 卡片背景色}

为什么用 interface 而不是 class

工具数据是只读的,不需要实例化方法,用interfaceclass更轻量。interface编译后不会生成额外的 JavaScript 代码,包体积更小。

字段的设计考量

  • name:显示在卡片上的标题,简短有力
  • desc:显示在卡片上的描述,说明工具用途
  • icon:emoji 图标,比图片加载快,兼容性好
  • page:路由路径,点击卡片时跳转到对应页面
  • color:卡片背景色,每个工具有自己的主题色

为什么 color 不用枚举

颜色值用字符串而不是枚举,是因为:

  1. 灵活性:可以直接用 CSS 颜色值,不需要额外定义枚举
  2. 简洁性'#4F6EF7'Color.BLUE更直观
  3. 扩展性:如果以后要加更多颜色,不需要修改枚举定义

工具数据:五个工具的定义

tools:ToolItem[]=[{name:'二维码生成',desc:'输入文字或链接,即时生成二维码',icon:'📱',page:'pages/QRGenerator',color:'#4F6EF7'},{name:'单位换算',desc:'长度·重量·温度·面积·数据',icon:'📐',page:'pages/UnitConverter',color:'#34C759'},{name:'随机决策',desc:'抛硬币·掷骰子·随机数·抽签',icon:'🎲',page:'pages/RandomTool',color:'#FF6B35'},{name:'颜色提取',desc:'从图片取色,智能配色方案',icon:'🎨',page:'pages/ColorPicker',color:'#AF52DE'},{name:'倒计时',desc:'设定事件日,实时倒数动画',icon:'⏳',page:'pages/Countdown',color:'#FF2D55'},];

数据和 UI 的分离

工具数据定义在组件内部(tools数组),但和 UI 渲染逻辑分离。如果要加新工具,只需要在数组里加一个对象,不需要改 UI 代码。

颜色的选择

五个工具用了五种不同的颜色:

工具颜色色系
二维码生成#4F6EF7蓝色
单位换算#34C759绿色
随机决策#FF6B35橙色
颜色提取#AF52DE紫色
倒计时#FF2D55红色

五种颜色饱和度相近,在深色背景上都能看清,但又各有区分。用户可以通过颜色快速识别工具——“蓝色是二维码,绿色是换算”。

page 路径的格式

'pages/QRGenerator'是路由路径,格式是pages/页面名。不需要加.ets后缀,路由会自动查找对应的组件。

路由跳转:navTo 方法

navTo(page:string):void{router.pushUrl({url:page});}

router.pushUrl 的用法

router.pushUrl把目标页面压入页面栈,用户可以返回上一页。参数是一个对象,url是目标页面的路径。

为什么封装成 navTo

直接调用router.pushUrl({ url: item.page })也可以,但封装成navTo有两个好处:

  1. 语义化this.navTo(item.page)router.pushUrl({ url: item.page })更易读
  2. 可扩展:如果以后要加路由拦截(比如登录检查),只需要改navTo方法,不需要改所有 onClick

页面栈的管理

pushUrl会把目标页面压入栈顶,用户按返回键会 pop 回首页。这是鸿蒙系统的标准导航模式,不需要额外处理。

如果要替换当前页面(不保留首页在栈中),可以用router.replaceUrl。但工具箱需要保留首页,所以用pushUrl

页面布局:头部 + 网格

build(){Column(){// 头部Column(){Text('🧰 小工具百宝箱').fontSize(26).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')Text('精选实用小工具,一个应用全搞定').fontSize(13).fontColor('#888888').margin({top:6})}.width('100%').padding({left:20,right:20,top:60,bottom:24}).alignItems(HorizontalAlign.Start)// 工具卡片网格Scroll(){Grid(){...}}.layoutWeight(1).scrollBar(BarState.Off)}.width('100%').height('100%').linearGradient({direction:GradientDirection.Bottom,colors:[['#1A1A2E',0.0],['#16213E',0.5],['#0F3460',1.0]]})}

头部区域

头部用 Column 居左对齐(alignItems(HorizontalAlign.Start)),包含标题和副标题:

  • 标题:26px 粗体白色,醒目
  • 副标题:13px 灰色,说明用途
  • padding:top 60px 留出状态栏空间,bottom 24px 和网格隔开

网格区域

网格用Scroll+Grid实现:

  • Scroll:让网格可以滚动(工具数量多时)
  • layoutWeight(1):占据剩余空间
  • scrollBar(BarState.Off):隐藏滚动条

渐变背景

.linearGradient({direction:GradientDirection.Bottom,colors:[['#1A1A2E',0.0],['#16213E',0.5],['#0F3460',1.0]]})

背景是从深蓝到更深蓝的渐变:

  • 顶部#1A1A2E:最浅的深蓝色
  • 中间#16213E:中等深度
  • 底部#0F3460:最深的蓝色

这种渐变让页面有"深度感",比纯色背景更高级。

Grid 布局:2 列自适应

Grid(){ForEach(this.tools,(item:ToolItem,idx:number)=>{GridItem(){Column(){Text(item.icon).fontSize(42).margin({bottom:14})Text(item.name).fontSize(17).fontWeight(FontWeight.Bold).fontColor('#FFFFFF').margin({bottom:6})Text(item.desc).fontSize(11).fontColor('#AAFFFFFF').maxLines(2).textAlign(TextAlign.Center)}.width('100%').height(160).borderRadius(18).backgroundColor(item.color).justifyContent(FlexAlign.Center).shadow({radius:8,color:item.color+'44',offsetY:4}).onClick(()=>this.navTo(item.page))}})}.columnsTemplate('1fr 1fr').columnsGap(14).rowsGap(14).padding({left:20,right:20,top:8,bottom:80}).width('100%')

columnsTemplate 的用法

.columnsTemplate('1fr 1fr')定义了两列等宽布局。1fr表示占剩余空间的比例,两个1fr就是两列各占一半。

如果要三列,改成'1fr 1fr 1fr'。如果要不等宽,可以用'2fr 1fr'(第一列是第二列的两倍宽)。

间距的控制

  • columnsGap(14):列间距 14px
  • rowsGap(14):行间距 14px
  • padding({left:20,right:20,top:8,bottom:80}):左右留 20px 边距,底部留 80px(避免被系统导航栏遮挡)

卡片的尺寸

每个卡片width('100%').height(160),宽度自适应列宽,高度固定 160px。固定高度保证所有卡片高度一致,视觉上整齐。

卡片样式:圆角、阴影、背景色

圆角

.borderRadius(18)给卡片 18px 的圆角。大圆角让卡片看起来更柔和,符合现代 UI 设计趋势。

阴影

.shadow({radius:8,color:item.color+'44',offsetY:4})

阴影有三个参数:

  • radius: 8:阴影模糊半径,越大越模糊
  • color: item.color+'44':阴影颜色,用卡片颜色加 44(26% 透明度)
  • offsetY: 4:阴影垂直偏移,让阴影在卡片下方

为什么阴影颜色用卡片颜色?

用灰色阴影(#00000044)也可以,但用卡片颜色的半透明版本更有"发光感"——蓝色卡片的阴影是蓝色的,绿色卡片的阴影是绿色的。

背景色

.backgroundColor(item.color)用工具数据中的颜色作为卡片背景。每个工具有自己的主题色,用户可以通过颜色快速识别。

内容居中

.justifyContent(FlexAlign.Center)让卡片内容垂直居中。图标、名称、描述三个元素在卡片中间排列,不会偏上或偏下。

卡片内容:图标、名称、描述

Column(){Text(item.icon).fontSize(42).margin({bottom:14})Text(item.name).fontSize(17).fontWeight(FontWeight.Bold).fontColor('#FFFFFF').margin({bottom:6})Text(item.desc).fontSize(11).fontColor('#AAFFFFFF').maxLines(2).textAlign(TextAlign.Center)}

三个元素的层次

元素字体大小颜色作用
图标42px默认视觉焦点
名称17px 粗体白色工具名称
描述11px半透明白色工具用途

图标最大,吸引注意力;名称粗体,告诉用户这是什么;描述最小,补充说明。

描述的截断

.maxLines(2)限制描述最多显示两行,超过两行显示省略号。这样可以保证卡片高度一致,不会因为描述太长导致卡片参差不齐。

文字颜色

  • 标题:纯白色#FFFFFF,最醒目
  • 描述:半透明白色#AAFFFFFF,比标题弱化但比背景突出

踩坑记录

坑 1:Grid 的高度计算

Grid 的高度是自动计算的,但如果子组件高度不一致,可能导致布局错乱。代码中给每个 GridItem 设了固定高度(160),避免了这个问题。

坑 2:Scroll 的 scrollBar

默认情况下 Scroll 会显示滚动条,影响美观。.scrollBar(BarState.Off)隐藏滚动条。

坑 3:router 的路径格式

路由路径不需要加.ets后缀。写'pages/QRGenerator'而不是'pages/QRGenerator.ets'

坑 4:底部 padding

网格底部留了 80px 的 padding,是为了避免被系统导航栏遮挡。如果底部工具卡片被导航栏挡住,可以增大这个值。

坑 5:渐变背景的方向

GradientDirection.Bottom表示从上到下渐变。如果要从下到上,用GradientDirection.Top

代码改进建议

1. 工具数据外部化

当前工具数据写在组件内部。如果以后要加更多工具,建议移到独立文件:

// data/Tools.tsexportconstTOOLS:ToolItem[]=[...];

2. 卡片点击动画

当前卡片点击没有反馈。可以加缩放动画:

.scale({x:this.scaleVal,y:this.scaleVal}).animation({duration:150}).onClick(()=>{this.scaleVal=0.95;setTimeout(()=>{this.scaleVal=1;},150);this.navTo(item.page);})

3. 路由传参

如果要给工具页面传参(比如从首页传入初始值),可以用router.pushUrlparams

router.pushUrl({url:page,params:{initialValue:'xxx'}});

然后在目标页面用router.getParams()获取。

4. 页面栈管理

如果用户从工具页面返回首页后想清空页面栈(避免多次返回),可以用router.clear()

5. 搜索功能

如果工具数量增多,可以加搜索功能。用TextInput组件接收搜索关键词,过滤tools数组。

总结

小工具百宝箱的首页核心是"数据驱动网格"——把工具数据用 Grid 渲染成卡片,点击通过 router 跳转到对应页面。卡片的圆角、阴影、背景色配合渐变背景,视觉效果干净整洁。

适用边界:这个部分适合用作 ArkUI 工具网格和路由导航的学习案例,涵盖了 ToolItem 接口设计、Grid 布局、router.pushUrl、卡片样式、渐变背景等核心知识点。但如果要上架应用商店,还需要补充搜索功能、工具分类、最近使用、收藏功能、路由传参等内容。建议在此基础上逐步扩展,而不是一次性做完所有功能。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/20 19:24:36

下水道管道更换公司怎么选才靠谱?

家里的下水道管道老化、破损,甚至出现严重渗漏、堵塞,更换管道就成了当务之急。可面对市面上五花八门的维修公司,不少业主最头疼的问题就是:下水道管道更换公司怎么选才靠谱? 从价格虚高、技术参差不齐,到中…

作者头像 李华
网站建设 2026/7/20 19:21:14

TikTok 评论分析实战:一分钟整理上千条评论思路

以前做评论分析,一般流程是:打开视频↓不断加载评论↓复制↓粘贴Excel↓删除重复↓人工统计整个过程非常耗时间。现在很多运营团队已经改成:第一步:导出评论。第二步:交给AI分析。例如统计:高频问题用户情绪…

作者头像 李华
网站建设 2026/7/20 19:18:44

FlyEnv

FlyEnv 是一款一体化的 PHP 开发环境软件, 包含了PHP开发中所需要的一切。FlyEnv 支持网络开发所必需的各种技术。包括 PHP、MySQL、Caddy、Nginx、Apache、MariaDB、MongoDB、PostgreSQL、Memcached、Redis 和 Pure-FTP,确保与大多数网络应用程序和框架兼容。 简单…

作者头像 李华