【细胞工坊|08】HarmonyOS ArkTS 知识点列表实战:实现细胞、遗传与病毒知识分类
部分内容由AI辅助生成。本文面向 HarmonyOS 5.0 及以上版本基于 细胞工坊 项目真实源码展开源码根目录为D:\huawei\one14-9。本文重点复核entry/src/main/ets/pages/LearningPage.ets、entry/src/main/ets/views/learning/KnowledgeListPage.ets、entry/src/main/ets/views/learning/KnowledgeDetailPage.ets与entry/src/main/ets/model/KnowledgePoint.ets。文章只讨论源码已经实现的分类入口、知识点过滤、颜色图标映射、列表卡片、详情页参数传递和安全区适配不虚构搜索、收藏、学习进度同步、远程知识库或 AI 推荐。知识型页面最容易写成“静态内容堆叠”首页给几个入口点进去列一堆标题再点开看正文。短期看能交付但分类、详情、图标、颜色和路由参数如果没有边界后面增加细胞、遗传、病毒、DNA、培养等主题时页面会迅速变得难维护。细胞工坊的实现采用了一个比较稳的链路学习中心通过分类卡片传入category知识点列表根据分类过滤本地数组列表项按知识点 ID 映射图标点击后把知识点字段传给详情页。这篇文章的重点不是讲生命科学知识本身而是拆解 HarmonyOS ArkTS 页面如何把知识分类做成可复核、可扩展的本地信息架构。当前源码中的知识点来自getAllKnowledgePoints()静态数组分类信息来自getKnowledgeCategories()没有网络请求也没有后台内容管理。这个边界对 AppGallery 审核和离线教学定位都很重要。一、先看入口学习中心负责分类网格不负责列表过滤LearningPage是学习中心它读取知识分类和学习工具Component export struct LearningPage { State categories: KnowledgeCategory[] getKnowledgeCategories() State tools: LearningTool[] getLearningTools() State screenWidth: number 360 }分类入口不是硬编码在 UI 里而是由KnowledgePoint.ets提供export interface KnowledgeCategory { name: string count: number icon: Resource color: string }点击分类卡片时学习中心只做一件事跳转到知识点列表页并传入分类名。router.pushUrl({ url: views/learning/KnowledgeListPage, params: { category: cat.name } })这个边界比较清楚。学习中心不需要知道该分类下有哪些知识点也不负责筛选数组。它只负责展示分类入口。真正的过滤逻辑留给KnowledgeListPage这样入口页不会被列表规则污染。二、分类网格做了响应式列数适合手机和平板学习中心的分类网格不是固定两列而是根据屏幕宽度返回不同列模板private gridCols(): string { if (this.screenWidth 840) return 1fr 1fr 1fr 1fr if (this.screenWidth 600) return 1fr 1fr 1fr return 1fr 1fr }根容器通过onAreaChange更新宽度.onAreaChange((_o, n) { this.screenWidth n.width as number })Grid 使用这个模板Grid() { ForEach(this.categories, (cat: KnowledgeCategory) { GridItem() { Column() { Image(cat.icon) Text(cat.name) Text(${cat.count}个知识点) } } }) } .columnsTemplate(this.gridCols()) .columnsGap(10) .rowsGap(10)对 HarmonyOS 多设备应用来说这种做法比写死两列更稳。手机上两列可读平板或 2in1 窗口变宽后可以扩展到三列或四列分类卡片不会被拉得过宽。三、知识点模型只存可展示字段知识点数据结构很轻export interface KnowledgePoint { id: string title: string category: string summary: string content: string }它没有收藏状态、学习进度、远程 ID、版本号或富媒体 URL。当前源码定位就是一个本地静态知识库。列表页和详情页都围绕这五个字段展开。分类统计则由KnowledgeCategory提供export function getKnowledgeCategories(): KnowledgeCategory[] { return [ { name: 基础, count: 12, icon: $r(app.media.ic_bio_microscope), color: #00D9FF }, { name: 培养, count: 10, icon: $r(app.media.ic_bio_petri), color: #00FFB2 }, { name: DNA, count: 9, icon: $r(app.media.ic_bio_dna), color: #7C4DFF }, { name: 病毒, count: 8, icon: $r(app.media.ic_bio_virus), color: #FF4D4F }, { name: 遗传, count: 8, icon: $r(app.media.ic_bio_genetics), color: #7C4DFF }, { name: 细胞, count: 10, icon: $r(app.media.ic_bio_mitosis), color: #00FFB2 } ] }命令行读取KnowledgePoint.ets时部分中文可能显示为乱码但分类结构、字段和数量可以从源码函数复核。文章只基于这些可验证字段描述分类能力。四、列表页从路由参数读取分类KnowledgeListPage定义了路由参数接口interface KnowledgeListParams { category?: string }页面初始化时读取参数aboutToAppear(): void { const params router.getParams() as KnowledgeListParams | undefined if (params?.category) { this.category params.category } this.reloadPoints() }这段代码有两个工程点逻辑作用风险控制params?.category支持从学习中心传入分类参数不存在时保留默认分类reloadPoints()统一刷新列表数据避免 UI 树里写过滤逻辑默认分类是基础State category: string 基础因此即使页面不是从分类网格进入而是从首页快捷入口进入也能展示基础知识点列表不会出现空白页。五、过滤逻辑带基础兜底避免未知分类导致空列表知识点过滤函数很短但有明确兜底private reloadPoints(): void { const filtered this.allPoints.filter((item: KnowledgePoint) item.category this.category) this.points filtered.length 0 ? filtered : this.allPoints.filter((item: KnowledgePoint) item.category 基础) }如果传入的分类存在就展示该分类如果传入分类无匹配结果就退回基础分类。这样做可以防止路由参数拼错、旧版本入口残留或外部快捷入口传入未知分类时页面空白。这里有一个边界页面标题仍显示this.category · 知识点如果传入未知分类列表显示基础内容但标题可能仍是未知分类。后续如果要更严谨可以在兜底时同步修正categoryif (filtered.length 0) { this.points filtered } else { this.category 基础 this.points this.allPoints.filter((item: KnowledgePoint) item.category 基础) }这只是可改进方向当前源码的真实实现是“列表数据兜底到基础标题不主动重置”。六、分类颜色用函数集中映射列表页根据当前分类返回主色private getCategoryColor(): string { const cat this.category if (cat 基础) return #00D9FF if (cat 培养) return #00FFB2 if (cat DNA) return #7C4DFF if (cat 病毒) return #FF4D4F if (cat 遗传) return #7C4DFF if (cat 细胞) return #00FFB2 return #00D9FF }这个函数让列表项图标、数字标牌和分类视觉保持一致。比在每个组件里手写颜色更容易维护。但这里也有一个可维护性问题颜色在getKnowledgeCategories()和getCategoryColor()中各写了一份。后续如果分类色调整可能出现入口页和列表页颜色不一致。更稳的方式是把分类颜色统一放在一个配置表里然后学习中心和列表页都读取同一份数据。七、知识点图标按 ID 映射不只按分类粗略映射getPointIcon()是当前页面较长的一段逻辑。它不是简单按分类给同一个图标而是按知识点 ID 映射更具体的资源private getPointIcon(kp: KnowledgePoint): Resource { const id kp.id if (id basic_1) return $r(app.media.ic_bio_microscope) if (id basic_2) return $r(app.media.ic_bio_cell) if (id basic_3) return $r(app.media.ic_bio_protocol) if (id basic_4) return $r(app.media.ic_bio_pipette) if (id basic_5) return $r(app.media.ic_bio_shield) if (id culture_1 || id culture_6 || id culture_7) { return $r(app.media.ic_bio_petri) } if (id dna_3 || id dna_4 || id dna_5) { return $r(app.media.ic_bio_dna) } return $r(app.media.ic_bio_cell) }这能让知识点列表更像知识库而不是同一分类下所有条目都长一样。比如 DNA 提取、PCR、突变、离心分层可以显示不同图标用户扫列表时更容易区分主题。代价是函数会越来越长。当前数据规模大约几十条手写映射还能接受如果知识点继续增长建议把图标名放进KnowledgePoint数据结构或者建立Recordstring, Resource映射表。八、列表卡片做了长文本保护知识点列表使用List和ForEach渲染List({ space: 8 }) { ForEach(this.points, (kp: KnowledgePoint, index: number) { ListItem() { Row() { // icon text arrow } } }) } .width(100%) .layoutWeight(1)标题和摘要都限制了行数Text(kp.title) .fontSize(AppFonts.BODY_SIZE) .fontWeight(AppFonts.WEIGHT_MEDIUM) .fontColor(AppColors.TEXT_PRIMARY) .maxLines(1) .textOverflow({ overflow: TextOverflow.Ellipsis }) Text(kp.summary) .fontSize(AppFonts.CAPTION_SIZE) .fontColor(AppColors.TEXT_SECONDARY) .margin({ top: 4 }) .maxLines(2) .textOverflow({ overflow: TextOverflow.Ellipsis })这对知识内容页很重要。知识点摘要天然会比功能按钮文案长如果不做截断小屏设备上列表高度会失控右侧箭头也可能被挤出可视区域。九、数字标牌提供当前分类内的阅读顺序列表项左侧使用Stack组合背景圆、图标和数字Stack({ alignContent: Alignment.BottomEnd }) { Column() {} .width(42) .height(42) .borderRadius(21) .backgroundColor(this.getCategoryColor()) .opacity(0.12) Image(this.getPointIcon(kp)) .width(22) .height(22) .fillColor(this.getCategoryColor()) .alignSelf(ItemAlign.Center) Text(${index 1}) .fontSize(8) .fontWeight(AppFonts.WEIGHT_BOLD) .fontColor(AppColors.TEXT_WHITE) .backgroundColor(this.getCategoryColor()) .width(15) .height(15) .borderRadius(7.5) .textAlign(TextAlign.Center) }这个结构把“主题”和“序号”放在同一视觉区域。序号是当前分类内的顺序不是全局知识 ID。用户从基础、DNA、病毒切换时序号会重新从 1 开始这和ForEach(this.points, ..., index)的实现一致。十、点击列表项把详情所需字段一次性传过去列表项点击后跳转详情页router.pushUrl({ url: views/learning/KnowledgeDetailPage, params: { id: kp.id, title: kp.title, category: kp.category, summary: kp.summary, content: kp.content } })当前实现直接把详情页需要的字段作为路由参数传递。这样详情页不需要再从全量知识数组里查一次页面打开逻辑简单。代价是路由参数变长。当前内容是本地短文本还能接受如果未来知识正文变成长文章、富文本或图片组合更稳的方式是只传id详情页根据id查询本地模型或仓储服务。当前源码尚未抽服务层文章不把它写成已实现能力。十一、详情页做参数兜底和文本渲染KnowledgeDetailPage读取列表页传入的参数aboutToAppear(): void { const params router.getParams() as KnowledgeDetailParams | undefined if (params?.id) this.kpId params.id if (params?.title) this.title this.normalizeDisplayText(params.title, 知识点) if (params?.category) this.category this.normalizeDisplayText(params.category, 基础) if (params?.summary) this.summary this.normalizeDisplayText(params.summary, this.summary) if (params?.content) this.content this.normalizeDisplayText(params.content, this.content) }默认状态也给了兜底State title: string 知识点 State category: string 基础 State summary: string 通过分类知识点快速理解对应生命科学概念。 State content: string 结合实验现象、可视化反馈和生活实例进行理解可以让知识点更容易记住。这意味着即使路由参数缺失详情页也不会空白。它会显示默认知识点文案。对教学类应用来说这种兜底比直接崩溃更符合用户预期。十二、详情页还根据知识点映射相关实验详情页源码里有getRelatedExperiment()会根据kpId和category选择相关实验private getRelatedExperiment(): RelatedExp { const id this.kpId const cat this.category let resId microscope_observation let resName 显微镜观察洋葱表皮 if (cat 培养) { if (id culture_2 || id culture_4 || id culture_7 || id culture_10) { resId sterile_operation resName 无菌操作挑战 } else { resId bacteria_culture resName 培养细菌菌落 } } return { id: resId, name: resName } }这说明知识点详情不只是静态文本它已经准备了“知识点 - 相关实验”的映射逻辑。需要注意的是文章本文聚焦列表页相关实验入口是否已经完整出现在详情 UI 中需要按详情页后续源码继续复核不能只凭这个函数声称全链路已经打通。十三、安全区和页面滚动处理方式一致知识点列表页读取顶部和底部安全区StorageProp(statusBarHeight) statusBarHeight: number 36 StorageProp(bottomBarHeight) bottomBarHeight: number 0根容器统一避让.width(100%) .height(100%) .backgroundColor(AppColors.PAGE_BG) .padding({ top: this.statusBarHeight, bottom: this.bottomBarHeight })列表区域使用layoutWeight(1)这样顶部导航固定列表内容占剩余空间。知识点数量较多时列表滚动不会把顶部导航挤走也不会让底部内容直接贴住系统栏。十四、当前没有实现搜索、收藏和远程更新从KnowledgeListPage源码看当前知识点列表只做分类过滤和跳转详情。没有搜索框没有收藏状态没有请求接口也没有分页加载。这个边界必须写清楚。能力当前源码是否支持证据分类入口支持LearningPage分类 Grid按分类过滤支持reloadPoints()基础兜底支持无匹配时回到基础图标映射支持getPointIcon()详情跳转支持router.pushUrl()搜索未实现本页无 SearchBar收藏未实现KnowledgePoint无收藏字段远程更新未实现数据来自静态数组学习进度同步未实现本页无 DataStore 写入这张表能帮助读者判断源码真实能力。技术文章不是功能宣传页不能把后续想做的东西写成已经完成。十五、验证清单从分类入口到详情页复核知识点列表时可以按下面顺序步骤操作预期学习中心打开学习页分类网格显示基础、培养、DNA、病毒、遗传、细胞响应式列数改变窗口宽度600、840 宽度阈值后列数变化分类跳转点击 DNA 分类进入列表页并带category: DNA列表过滤查看列表标题和内容显示 DNA 知识点未知分类传入不存在分类列表数据兜底基础分类列表长文本查看摘要标题一行、摘要两行省略详情跳转点击任意知识点打开详情页并带 id/title/category/summary/content返回点击顶部返回调用router.back()如果未来加入搜索或收藏需要额外验证搜索关键字空态、收藏状态持久化、返回后状态恢复等场景。当前源码还不涉及这些能力。十六、常见问题与处理方式问题常见原因处理建议分类入口数量和列表实际数量不一致getKnowledgeCategories()的 count 手写后未同步从getAllKnowledgePoints()统计生成减少手工维护传入未知分类标题异常列表数据兜底但category未重置兜底时同步设置this.category 基础图标映射函数过长所有 ID 判断集中在页面方法抽成映射表或把 icon 放进模型详情参数过长直接把 content 放入路由参数只传 id详情页按 id 查询文本在小屏溢出标题或摘要没限制行数保留maxLines和textOverflow误以为支持搜索项目有通用 SearchBar 组件但本页没使用不在列表页声明搜索能力除非实际接入这些问题都来自源码的真实结构。当前实现已经适合本地静态知识库但如果内容规模继续扩大就需要把分类配置、知识点索引、图标映射和详情查询进一步服务化。十七、小结知识列表页的稳定来自三段式链路细胞工坊的知识点列表链路可以概括为三段学习中心只负责分类入口列表页只负责分类过滤和列表导航详情页负责接收参数并展示内容。KnowledgePoint提供本地静态知识数组KnowledgeCategory提供入口统计和图标颜色KnowledgeListPage用category参数过滤点击后把知识点字段传给详情页。这套实现没有伪装成远程知识库也没有把搜索、收藏、学习进度同步写成已完成能力。它的价值在于清晰、可复核、离线可用。对 HarmonyOS 教学应用来说先把分类入口、过滤兜底、图标映射、长文本保护和详情跳转做稳定再扩展搜索、收藏和进度记录会比一开始堆复杂能力更可靠。

相关新闻

Flutter应用移植OpenHarmony的逆向思维实践

Flutter应用移植OpenHarmony的逆向思维实践

1. 项目背景与核心思路作为一名同时接触Flutter和OpenHarmony的开发者,我发现将Flutter应用移植到OpenHarmony平台是个极具挑战性但又有趣的方向。这个项目源于一个逆向思维训练的需求——我们通常考虑如何将OpenHarmony应用迁移到其他平台,但反过来思考…

2026/8/8 17:56:23 阅读更多 →
STM32 USB Host读写U盘实战:从硬件选型到稳定性调优

STM32 USB Host读写U盘实战:从硬件选型到稳定性调优

1. 项目缘起:为什么要在STM32上读写U盘? 几年前,我接手一个工业数据采集终端的项目,客户要求设备能定期将采集到的传感器数据导出,并且操作要足够“傻瓜”——他们希望现场工人能像在电脑上一样,直接拔插U盘…

2026/8/8 18:11:17 阅读更多 →
Unity VR医疗培训项目实战:从场景搭建到性能优化的全流程解析

Unity VR医疗培训项目实战:从场景搭建到性能优化的全流程解析

1. 项目概述:从“HosptialDemo”看VR医疗培训的实战价值最近在整理过往项目时,翻到了一个名为“HosptialDemo”的Unity VR医院演示项目。这虽然只是一个演示,但麻雀虽小五脏俱全,它完整地串联起了从场景搭建、交互设计到流程模拟的…

2026/8/8 18:20:25 阅读更多 →

最新新闻

SpringBoot2+Vue3医院信息管理系统技术解析

SpringBoot2+Vue3医院信息管理系统技术解析

1. 项目概述:医院信息管理系统的技术栈解析这个基于SpringBoot2Vue3MyBatis-PlusMySQL8.0的医院信息管理系统,是当前医疗信息化领域的主流技术方案。我在实际医疗IT项目实施中发现,这类系统通常需要处理日均上万条的门诊记录、药品库存和医患…

2026/8/9 11:28:16 阅读更多 →
MinIO最新稳定版功能解析与部署实践

MinIO最新稳定版功能解析与部署实践

1. MinIO最新稳定版本概述 MinIO作为一款高性能的对象存储解决方案,其版本迭代一直备受开发者关注。当前(2023年Q3)官方最新稳定版本为RELEASE.2023-07-21T21-12-44Z,该版本在数据一致性、安全性和性能方面均有显著提升。与社区版…

2026/8/9 11:28:16 阅读更多 →
基于MaxCompute Delta Table与Time Travel的SCD Type 2自动化实现方案

基于MaxCompute Delta Table与Time Travel的SCD Type 2自动化实现方案

1. 项目概述:当数据仓库的维度表需要“记忆”在数据仓库和数据分析的日常工作中,我们经常需要处理一种特殊的表:维度表。它描述的是业务实体,比如客户、产品、供应商。一个看似简单但极其棘手的问题是:当客户的地址从“…

2026/8/9 11:28:16 阅读更多 →
RAR/ZIP/7Z压缩格式核心技术对比与应用指南

RAR/ZIP/7Z压缩格式核心技术对比与应用指南

1. 压缩格式江湖:RAR/ZIP/7Z的前世今生 第一次接触文件压缩是在2005年,当时要从学校机房拷贝一套AutoCAD教学视频,3.5英寸软盘根本装不下。机房管理员老张神秘地掏出WinRAR,眨眼间就把800MB的视频压成了十几张软盘能装下的体积——…

2026/8/9 11:28:16 阅读更多 →
3步搞定SPT-AKI存档编辑:让《逃离塔科夫》离线模式更自由

3步搞定SPT-AKI存档编辑:让《逃离塔科夫》离线模式更自由

3步搞定SPT-AKI存档编辑:让《逃离塔科夫》离线模式更自由 【免费下载链接】SPT-AKI-Profile-Editor Программа для редактирования профиля игрока на сервере SPT-AKI 项目地址: https://gitcode.com/gh_mirror…

2026/8/9 11:28:16 阅读更多 →
R语言核心语法与高效数据处理技巧详解

R语言核心语法与高效数据处理技巧详解

1. R语言基础语法精要解析 作为统计计算领域的瑞士军刀,R语言凭借其强大的数据处理能力和丰富的扩展包生态,已成为数据科学家的标配工具。今天我将结合多年实战经验,系统梳理R语言的核心语法要点,特别是那些官方文档不会明说但实际…

2026/8/9 11:27:15 阅读更多 →

日新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/9 0:01:47 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/9 0:01:47 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/9 0:03:48 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/9 0:01:47 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/9 0:01:47 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/9 0:03:48 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/8 17:02:44 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/9 0:45:04 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/8 17:02:44 阅读更多 →