【OpenHarmony/HarmonyOs 】ArkTS 实现本地化学习 App:元素周期表、方程式与知识库设计
【OpenHarmony/HarmonyOs 】ArkTS 实现本地化学习 App:元素周期表、方程式与知识库设计
这篇文章基于我的 HarmonyOS 化学学习项目「化学视界」整理。项目的定位很明确:做一款离线可用、打开即学、适合中学生和化学爱好者使用的学习工具。它包含元素周期表、化学方程式、化学知识库、挑战练习、收藏、错题、成就和学习统计等功能。📚
一、我为什么选择“本地化学习 App”这个方向?
一开始做这个项目时,我没有先考虑复杂的账号体系、云同步或推荐系统,而是先问了一个更基础的问题:一个化学学习工具最核心的价值是什么?
我的答案是:查得快、看得懂、练得起来。
所以项目最早的设计重点放在三类内容:
- ⚛️ 元素周期表:承载 118 个元素的信息查询。
- ⚗️ 化学方程式:承载常见反应、条件、现象和说明。
- 📚 化学知识库:承载概念、定律、实验、周期律、有机化学等内容。
这些内容本身非常适合本地化。用户打开 App 后,不需要等网络请求,不需要登录,也不需要担心学习资料突然加载失败。
二、项目整体功能拆分
我在开发时没有把所有逻辑都堆到首页,而是按学习场景拆成多个页面:
Index.ets:底部导航主框架。PeriodicTable.ets:元素周期表。ElementDetail.ets:元素详情。Equations.ets:方程式列表。EquationDetail.ets:方程式详情。Knowledge.ets:知识库列表。KnowledgeDetail.ets:知识详情。Quiz.ets:挑战练习。Favorites.ets:收藏夹。Achievement.ets:成就系统。Settings.ets:我的页面和数据管理。
这样的拆法有一个好处:每个页面都围绕一个学习动作展开。查元素就是查元素,刷题就是刷题,收藏就是收藏,后续维护时也不容易混乱。
三、数据层:先把模型设计清楚
本地化 App 最重要的是数据结构。比如元素模型就不是只存一个名字,而是要覆盖学习时真正会查的信息:
export interface ChemicalElement {
number: number;
symbol: string;
name: string;
nameEn: string;
atomicMass: string;
category: ElementCategory;
electronConfig: string;
electronegativity: number;
density: string;
meltingPoint: string;
boilingPoint: string;
discoveryYear: string;
discoverer: string;
description: string;
row: number;
col: number;
}
我开发时的思路是:列表页需要展示“轻信息”,详情页需要展示“完整信息”。所以模型字段要一次设计完整,页面再按需要取用。
类似地,方程式数据也包含名称、反应式、类型、条件、现象和说明:
export interface ChemicalEquation {
id: number;
name: string;
equation: string;
type: EquationType;
conditions: string;
现象: string;
description: string;
level: string;
}
这样做之后,页面就不会被迫把展示文案写死在组件里,后续增加内容也只需要维护数据文件。
四、主框架:底部导航承载高频入口
项目主框架使用 Tabs 承载多个一级入口:
Tabs({ controller: this.tabController, index: this.currentIndex }) {
TabContent() {
EquationsView()
}
.tabBar(this.tabBarBuilder(0, '方程式',
$r('app.media.icon_equation_selected'),
$r('app.media.icon_equation_normal')))
TabContent() {
PeriodicTableView()
}
.tabBar(this.tabBarBuilder(2, '周期表',
$r('app.media.icon_periodic_selected'),
$r('app.media.icon_periodic_normal')))
}
.barPosition(BarPosition.End)
.barMode(BarMode.Fixed)
我没有做一个很重的首页,因为这个 App 是工具型学习产品。用户打开后大概率是要查资料或练习,而不是看欢迎页。
底部导航的顺序也是按使用场景安排的:
- 方程式:学习化学时经常查。
- 成就:提供学习激励。
- 周期表:核心查询工具。
- 知识:系统学习内容。
- 挑战:练习与巩固。
- 收藏:复习入口。
- 我的:统计和设置。
五、列表页:搜索和筛选是核心能力
方程式和知识库页面都做了搜索与分类筛选。以知识库为例:
Search({ placeholder: '搜索知识点(标题、内容、标签)' })
.onChange((value: string) => {
this.searchText = value;
if (value.length > 0) {
this.displayedKnowledge = searchKnowledge(value);
this.isSearchMode = true;
} else {
this.updateDisplayedKnowledge();
this.isSearchMode = false;
}
})
开发时我把搜索状态单独抽出来:
searchText:当前输入内容。isSearchMode:是否处于搜索模式。displayedKnowledge:最终显示的数据。selectedCategory:当前筛选分类。
这样 UI 层只关心 displayedKnowledge,不需要每次渲染都临时计算。
六、详情页:用参数路由连接列表和内容
元素详情页通过路由参数加载具体元素:
let params = router.getParams() as Record<string, number>;
if (params && params.elementNumber) {
let el = getElementByNumber(params.elementNumber);
if (el) {
this.element = el;
this.elementLocal = el;
}
}
我的开发思路是:列表只负责展示摘要和入口,详情页负责完整阅读。这样不会让列表卡片变得臃肿,也能让用户快速扫视。
方程式详情和知识详情也是同样思路:
- 列表页传
id。 - 详情页根据
id查本地数据。 - 找不到数据时展示空状态。
这种方式很适合离线 App,因为数据都在本地,跳转和加载都很快。
七、视觉体验:不同内容使用不同颜色语言
化学内容天然有分类感,比如元素类别、反应类型、知识类型都可以用颜色辅助识别。
方程式页面中,不同反应类型对应不同颜色:
getTypeColor(type: EquationType): string {
const colorMap: Record<string, string> = {
'combination': '#E3F2FD',
'decomposition': '#E8F5E9',
'replacement': '#FFF3E0',
'exchange': '#F3E5F5',
'combustion': '#FFEBEE'
};
return colorMap[type] || '#F5F5F5';
}
这种设计不是单纯为了好看,而是为了让学生在视觉上建立关联:看到颜色就能大致判断内容类别。
八、我开发这个项目时的几个取舍
1. 先做离线,再考虑扩展
我没有一开始就做复杂服务端,因为化学资料查询本身就很适合本地化。先把核心学习体验做好,比先做一堆账号和网络能力更重要。
2. 先做可读性,再做复杂动效
元素、方程式和知识库都是内容型页面,动效只做点击反馈、页面进入和弹窗过渡,不让动画抢走阅读注意力。
3. 先统一数据结构,再做页面
如果数据模型混乱,后面做搜索、收藏、详情跳转都会很难。所以我先把元素、方程式、知识点这些模型定好,再开发页面。
九、可以继续优化的方向
后续这个本地化架构还可以继续升级:
- 增加学习路线,比如“初中基础路线”“高中提升路线”。
- 给知识点和题目建立关联。
- 方程式详情中加入反应类型图解。
- 周期表支持更多筛选条件。
- 收藏夹支持自定义分组。
- 本地学习报告增加趋势图。
十、总结
这个项目的核心开发思路可以概括为:
- 📦 内容本地化,保证打开即用。
- 🧱 页面模块化,降低维护成本。
- 🔍 搜索筛选优先,提升查询效率。
- 📖 列表和详情分离,保证阅读体验。
- 🎨 用颜色表达分类,帮助用户理解。
对于学习类 App 来说,技术实现不只是把页面写出来,更重要的是把“用户怎么学”变成清晰的信息架构。「化学视界」正是围绕这个目标一步步搭起来的。✨

更多推荐


所有评论(0)