【鸿蒙打卡第3天】从零构建音乐歌单:ArkTS 数组、对象与 List 列表渲染实战
本文总结了HarmonyOS开发中数组与对象数据结构的学习要点,并通过歌单界面实现展示了实战应用。重点包括:1) 数组和对象的定义、语法及应用场景;2) 歌单项目分层架构设计;3) 核心代码实现细节,包括数据模型定义、Mock数据构造和界面渲染优化;4) 运行效果展示及开发心得,强调类型安全、列表性能优化和时间格式化技巧。文章完整呈现了从理论学习到项目实践的完整链路,为HarmonyOS应用开发提
·
今日学习复盘:HarmonyOS 数据结构与歌单界面实战
1. 核心理论:数组与对象的深度理解
今日重点攻克了 ArkTS 中两种最基础也最重要的数据结构,它们是构建复杂应用界面的基石。
📦 数组 (Array):同类数据的集合
- 定义:用于存储类型相同的一组数据。
- 语法:
let 数组名: 类型[] = [数据1, 数据2, ...] - 应用场景:歌单列表、商品列表、消息流等需要批量渲染的场景。
- 关键点:在 ArkTS 中,强类型约束要求数组内的元素必须严格符合声明的类型,这有助于在编译期发现错误。
💡 示例:
let scores: number[] = [90, 85, 92];
🗂️ 对象 (Object):异构数据的模型
- 定义:用于描述一个实体,通过键值对 (Key-Value) 存储不同类型的属性。
- 语法:
let entity: EntityType = { key1: value1, // 属性名: 属性值 key2: value2 }; - 访问方式:使用点符号
对象名.属性名获取具体值。- ⚠️ 注意:直接打印对象(如
console.log(obj))在某些环境下可能只显示[object Object],无法直观看到内部数据。调试时建议打印具体属性或使用JSON.stringify()。
- ⚠️ 注意:直接打印对象(如
- 应用场景:定义用户信息、歌曲详情、商品属性等具有多个维度的数据模型。
2. 实战任务:静态歌单数据 Mock 与界面展示
✅ 任务目标:定义 SongItem 核心数据结构,完成静态数据 Mock,并渲染出美观的歌单列表。
📂 项目结构规划
为了保持代码的清晰与可维护性,采用了标准的分层目录结构:
entry-src-main-ets/
├── data/ # 存放模拟数据 (Mock Data)
│ └── Mockdata.ets
├── model/ # 存放数据模型接口 (Interfaces)
│ └── SongItem.ets
└── pages/ # 存放页面逻辑
└── Index.ets
💻 核心代码实现详解
① 数据模型定义 (model/SongItem.ets)
不仅定义了数据接口,还封装了通用的工具函数,体现了高内聚的设计思想。
// 定义歌曲数据接口,确保数据类型安全
export interface SongItem {
id: number; // 唯一标识
title: string; // 歌名
artist: string; // 歌手
album: string; // 专辑
duration: number; // 时长 (秒)
coverUrl: string; // 封面链接
audioUrl: string; // 音频链接
isLiked: boolean; // 是否收藏
}
/**
* 工具函数:将秒数格式化为 "分:秒" (例如 269 -> "4:29")
* 逻辑:Math.floor 取整分钟,% 运算取余秒,padStart 补零
*/
export function formatDuration(seconds: number): string {
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
// 确保秒数始终为两位数,如 5 -> "05"
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
}
② 模拟数据构造 (data/Mockdata.ets)
构建了包含 5 首歌曲的测试数据集,涵盖了中英文歌曲及不同的收藏状态,用于验证列表渲染的多样性。
import type { SongItem } from '../model/SongItem';
export const MOCK_SONG_LIST: SongItem[] = [
{
id: 1,
title: "晴天",
artist: "周杰伦",
album: "叶惠美",
duration: 269,
coverUrl: "https://picsum.photos/200/200?random=1", // 随机占位图
audioUrl: "",
isLiked: true
},
{
id: 2,
title: "起风了",
artist: "买辣椒也用券",
album: "起风了",
duration: 325,
coverUrl: "https://picsum.photos/200/200?random=2",
audioUrl: "",
isLiked: false
},
// ... (其他歌曲数据略,保持结构一致)
];
③ 界面渲染逻辑 (pages/Index.ets)
利用 ArkUI 的声明式语法,结合 List 和 ForEach 实现高效列表渲染。
✨ 亮点优化:
- 状态管理:使用
@State装饰songList,确保数据变化时视图自动刷新。 - 唯一 Key:
ForEach的第三个参数(item) => item.id.toString()至关重要,它帮助框架识别列表项的唯一性,提升渲染性能。 - 布局细节:
- 使用
layoutWeight(1)让歌曲信息列自动占据剩余空间,防止时长文本换行。 - 添加
borderRadius和backgroundColor提升卡片质感。 - 使用
ImageFit.Cover确保封面图片不变形填充。
- 使用
@Entry
@Component
struct Index {
// 绑定状态数据,初始值为 Mock 数据
@State songList: SongItem[] = MOCK_SONG_LIST;
build() {
Column() {
Text('我的歌单')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ top: 20, bottom: 10 })
List({ space: 10 }) {
ForEach(this.songList, (item: SongItem) => {
ListItem() {
Row() {
// 1. 封面图片
Image(item.coverUrl)
.width(60)
.height(60)
.borderRadius(8)
.objectFit(ImageFit.Cover)
// 2. 歌曲文本信息
Column({ space: 5 }) {
Text(item.title)
.fontSize(16)
.fontWeight(FontWeight.Medium)
Text(`${item.artist} - ${item.album}`)
.fontSize(12)
.fontColor('#666666')
}
.layoutWeight(1) // 关键:自适应宽度
.margin({ left: 10 })
// 3. 格式化后的时长
Text(formatDuration(item.duration))
.fontSize(12)
.fontColor('#999999')
}
.padding(10)
.backgroundColor('#FFFFFF')
.borderRadius(10)
}
}, (item: SongItem) => item.id.toString()) // 必须提供唯一 Key
}
.padding(10)
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5') // 整体背景色
}
}
3. 运行效果与反思
🖼️ 最终展示
成功在虚拟机中渲染出歌单界面,列表项整齐排列,图片加载正常,时长格式正确(如 4:29),UI 风格简洁现代。
💡 学习心得与注意事项
- 类型安全的重要性:通过
interface定义数据模型,使得在编写 UI 代码时能获得完整的智能提示,减少了拼写错误。 - 时间格式化逻辑:
padStart(2, '0')是一个非常实用的字符串方法,在处理时间、日期格式化时经常用到。 - 列表性能:在
ForEach中生成唯一的key是避免列表渲染错乱或性能低下的关键,切忌使用数组索引index作为 key(如果列表会发生增删操作)。 - 资源加载:目前使用的是网络随机图 (
picsum.photos),实际开发中应替换为本地资源$r('app.media.xxx')或真实的 CDN 链接,并注意处理图片加载失败的情况。
更多推荐


所有评论(0)