读懂鸿蒙课程模板的数据结构:共享章节目录、视频映射与二次开发检查
给课程应用增加一节课,看起来像是在数组末尾补一个对象。阅读鸿蒙实践案例中心的 HarmonyOS-APPTMPL-Course 模板后,我发现,动手之前更值得确认的是三个问题:这份章节目录被哪些课程使用,用户点击的目录项怎样对应视频,以及插入章节后原来的位置索引是否仍然有效。
本文记录的是 2026 年 11 月 9 日对公开仓库的源码阅读。直接核对的重点是 commons/http/src/main/ets/mocks/Data/CourseData.ets,并结合仓库 README 的数据层和二次开发说明进行分析。此次没有构建 HAP,也没有在真机或模拟器播放视频;下文的设备检查项是后续验证计划。
一、先区分课程对象与章节对象
CourseData.ets 同时导出 COURSE_CATALOG 和 COURSE_DATA。前者是章节目录,后者是课程集合。直接看到的章节目录包含六个条目,ID 从 0001 到 0006。章节对象保存标题、简介、视频地址、封面、时间以及学习进度等字段。
课程对象则描述一门课:课程名称、分类、讲师、时长、学习人数和免费状态等。对于使用章节目录的课程,courseCatalog 把课程和具体章节关联起来。以“平台上的一门课程”和“这门课程中的一节视频”分别理解两层数据,后面修改时就不容易改错位置。
下面是从原文件摘出的短片段,只保留与目录引用有关的行;省略号表示中间字段未展示。
// CourseData.ets,节选
export const COURSE_CATALOG: CourseCatalog [] = [
{
id: '0001',
courseTitle: '01 HarmonyOS第一课第1节',
catalogTitle: '第1节',
// ...
learnProgress: 0,
},
// ...
];
export const COURSE_DATA: Course[] = [
{
id: '0007',
courseTitle: 'HarmonyOS简介',
// ...
videoUrl: '',
courseCatalog: COURSE_CATALOG,
isFree: true,
isPay: false,
},
// ...
];
这里有一个排查时很容易忽略的细节:课程对象的 videoUrl 可以是空字符串,而章节对象中保存了具体媒体地址。因此,仅看到课程层的这个字段为空,不能立即判定它没有可播放内容;还需要沿着 courseCatalog 查看选中的章节。最终页面如何处理这些数据,仍要结合播放入口和设备表现核对。
二、共享目录会扩大一次修改的影响范围
文件中的多门课程都写着 courseCatalog: COURSE_CATALOG。这是一份方便演示的共享数据:增加一个章节,所有引用该目录的课程都有可能出现这个新条目。它适合展示通用页面,却要求二次开发者先确认业务意图。
假设只想给“DevEco Studio的使用”增加一节课,如果直接向公共的 COURSE_CATALOG 追加条目,那么其他同样引用它的课程也会受到影响。我的处理顺序会是:先列出引用这份目录的课程,再决定是修改公共演示内容,还是给目标课程建立独立目录,最后回到每个受影响入口检查结果。
同样要留意两种复制的区别。给课程换一个数组,可以让它拥有独立的章节顺序;但仅做数组的浅复制,里面的章节对象仍可能被复用。如果后续代码会修改对象上的学习进度,是否需要独立对象,应该由实际状态存储和更新逻辑决定。这里不能仅凭数据定义就断言模板已经发生“进度串课”,因为此次没有完整追踪更新链路。
原文件还有一些课程使用 [COURSE_CATALOG[0]] 这样的写法。这表示显式选取公共目录某个位置的章节。调整公共数组顺序时,除了查看完整目录的使用者,也应检查这些按位置选择条目的地方;数组第一个元素发生变化,引用表达式本身并不会提醒你它已经指向另一节内容。
三、ID、索引与视频地址承担不同职责
仓库 README 的二次开发说明指出,ChapterDetail 按 catalogIndex 和章节 videoUrl 构造播放列表,并要求同一目录内的章节 ID 唯一。这部分映射关系来自仓库说明;本次没有把对应页面实现完整读到,因此不把文档描述当作已经通过设备验证的行为。
| 字段 | 阅读时的理解 | 修改时要检查什么 |
|---|---|---|
| 章节 id | 表示目录中的章节身份 | 同目录内唯一;不要因为移动位置就随意换 ID |
| catalogIndex | 表示当前目录中的位置 | 插入、删除或排序后,选中项和索引仍对应 |
| videoUrl | 提供章节的媒体地址 | 地址、标题与章节一致,资源可用且具备使用授权 |
“ID 不重复”和“点击后播放正确”是两项检查。比如在第二节前插入新条目,即使所有 ID 都唯一,原先按位置保存的选择也可能需要重新对应。是否会真正影响当前模板,要看它何时计算索引、页面如何恢复状态,以及播放列表何时刷新,不能只检查数组能否通过类型检查。
我更愿意把二次开发目标写成一条可观察的路径:课程入口 → 目录标题 → 选中章节 → 媒体内容。逐段核对,可以区分究竟是数据归属、选择位置还是视频资源出了问题。只有页面上的标题和实际媒体一致,才算完成了这条路径的验证。
四、把本地演示数据与真实服务分开核对
仓库 README 说明,Apis.ets 暴露课程、目录和观看记录等查询函数,RequestMock.ets 通过 AxiosMock 提供演示数据。此次访问 RequestMock.ets 的代码预览时,页面显示“文件内容审核中,请稍后重试”,因此这里明确引用 README 的描述,未逐行确认它的拦截实现。
这个边界会影响排查顺序:课程卡片和目录能显示,说明页面拿到了用于展示的数据;远程媒体能否打开,还取决于地址、网络、媒体格式与设备能力。两条链路应该分别记录结果。类似地,模板里的 isPay 等演示状态,也不能替代真实支付服务的确认。
若后续接入自己的课程接口,我会先保持现有数据字段与调用入口稳定,确认真实响应如何转换成页面需要的课程和章节,再逐步替换 mock。媒体地址、学习进度、账号权限等问题分别核对,能让每次改动的结果更容易解释。
五、新增一节课时,我会怎样验证
基于这次阅读,我把检查顺序整理成以下五步。它们是可执行的验收建议,本次没有运行这些设备测试。
- 确认目录归属。 找出目标课程及共享目录的其他引用者,写明新章节应当在哪些课程中出现。
- 核对数据对应。 检查章节 ID、展示标题、封面和视频地址。向中间插入或删除条目时,同时检查按数组下标取值的位置。
- 核对选中与播放。 在可用设备上依次点击首节、新增章节和末节,记录选中的标题、目录位置以及实际媒体结果;不能只看播放器区域是否出现。
- 核对返回与再次进入。 返回课程页后重新进入,再切换另一门共享目录的课程,检查课程标题、选中项与记录是否属于预期对象。
- 核对失败状态。 在测试配置中使用明确无效的媒体地址,观察错误反馈和返回路径;恢复有效地址后复验。只有失败后的页面仍可继续使用,改动才更适合交给真实用户。
这些检查项的价值在于让问题对应到具体层次:目录归属错误就先看数据引用,选中项错误就查索引传递,标题正确而播放失败再收集媒体和设备信息。这样可以减少还没确认原因就反复修改 UI 的情况。
六、这次阅读得到的结论
这份课程模板的数据结构比较直观,但“修改一节课”的影响取决于目录被如何共享。直接读到的源码表明,多门课程引用同一个章节数组,也存在按数组下标单独选取章节的写法。仓库说明进一步提示了目录索引和媒体地址之间的关系。
因此,二次开发时我会先画清课程、目录与章节的对应关系,再修改数据;完成后检查真实点击路径,而不是把“字段填齐”当作“播放正确”。这次没有形成设备运行结论,也没有验证视频资源当前可用性。源码中能确认的结构已经明确,下一步的设备检查也就有了具体目标。
参考资料与源码说明
- 鸿蒙实践案例:学习课程应用模板
- HarmonyOS-APPTMPL-Course 仓库及 README
- CourseData.ets 课程与章节数据
- RequestMock.ets 文件入口:本次预览受审核状态影响,相关架构说明引用 README。
文中短代码片段取自上述仓库的 CourseData.ets;原文件标注 Copyright (c) 2024 Huawei Device Co., Ltd.,采用 Apache License 2.0。片段为阅读说明而节选,省略部分不可作为完整可运行代码。其余分析和验证建议为本次阅读整理。
- 点赞
- 收藏
- 关注作者
评论(0)