open harmony 项目实战:从 0 到 1 搭建一款语文学习 App

最近我用 OpenHarmony + ArkTS 做了一款语文学习类应用,名字叫“语文视界”。它不是一个单纯的 Demo,而是包含首页推荐、诗词鉴赏、阅读、字典、学习中心、收藏记录、个人中心等多个模块的小型完整项目。📚

这篇文章作为系列开篇,主要聊聊项目整体架构:一个 OpenHarmony 学习类 App 从功能规划到目录组织,再到页面流转,应该怎么搭起来。

一、项目定位

“语文视界”的核心目标是让用户可以在手机或平板上完成轻量语文学习:

  • 首页:展示今日推荐、快速入口、学习数据。
  • 诗词:支持年级、朝代筛选,进入详情页查看注释、译文、赏析。
  • 阅读:提供名著、散文、古文、诗词鉴赏等阅读内容。
  • 字典:支持汉字与成语查询。
  • 学习:提供每日打卡、诗词默写、诗词配对、朝代排序。
  • 我的:展示收藏数、阅读记录、学习天数和反馈入口。

这样的模块设计比较适合 OpenHarmony 入门进阶:既有页面 UI,也有状态管理、数据检索、交互反馈和响应式适配。

二、项目目录结构

项目核心代码集中在 entry/src/main/ets

entry/src/main/ets
├── common
│   ├── components
│   ├── constants
│   └── utils
├── data
├── entryability
├── entrybackupability
├── model
├── pages
│   ├── dictionary
│   ├── home
│   ├── learn
│   ├── my
│   ├── poetry
│   └── reading
└── viewmodel

我个人很喜欢这种分层方式:页面归页面,数据归数据,公共组件和工具类单独放,后续维护时不会乱成一团。

三、主入口页面的职责

项目的主入口是 Index.ets。它不是只展示首页,而是承担了“轻量路由容器”的角色。

核心状态有两个:

@State currentTabIndex: number = 0;
@State currentView: string = 'home';

currentTabIndex 控制底部导航选中项,currentView 控制当前展示哪个页面。比如进入诗词详情页时,会把当前页面记录为上一页,再写入目标页面状态:

private navToPoetryDetail(poetryId: number): void {
  AppStorage.setOrCreate('prev_view', this.currentView);
  AppStorage.setOrCreate('nav_poetry_id', poetryId);
  AppStorage.setOrCreate('current_view', 'poetry_detail');
  this.currentView = 'poetry_detail';
}

这样做不需要引入很复杂的路由系统,也能满足中小型 App 的页面跳转需求。

四、六大一级页面

底部导航包含 6 个一级入口:

this.buildTabItem(0, '首页', $r('app.media.ic_home_normal'), $r('app.media.ic_home_selected'));
this.buildTabItem(1, '诗词', $r('app.media.ic_poetry_normal'), $r('app.media.ic_poetry_selected'));
this.buildTabItem(2, '阅读', $r('app.media.ic_reading_normal'), $r('app.media.ic_reading_selected'));
this.buildTabItem(3, '字典', $r('app.media.ic_dict_normal'), $r('app.media.ic_dict_selected'));
this.buildTabItem(4, '学习', $r('app.media.ic_learn_normal'), $r('app.media.ic_learn_selected'));
this.buildTabItem(5, '我的', $r('app.media.ic_my_normal'), $r('app.media.ic_my_selected'));

这 6 个模块基本覆盖了学习类 App 的主要流程:发现内容、学习内容、检索内容、练习巩固、查看个人数据。

五、数据层设计

项目的数据文件放在 data 目录下:

  • poetry_data.ets:诗词数据。
  • reading_data.ets:阅读数据。
  • dictionary_data.ets:成语数据。
  • char_data.ets:汉字数据。
  • learn_quiz_data.ets:学习题库。

本地数据的好处是启动快、离线可用、功能稳定。对于学习类 App 来说,早期不一定非要先接后端,先把内容结构和体验跑通更重要。

六、ViewModel 负责业务逻辑

诗词模块使用了 PoetryViewModel 统一管理收藏、历史、筛选、推荐等逻辑。

export class PoetryViewModel {
  private favoriteIds: number[] = [];
  private readHistoryIds: number[] = [];
  private poetryCache: Map<number, Poetry> = new Map<number, Poetry>();

  constructor() {
    this.buildCache();
    this.loadFavorites();
    this.loadReadHistory();
  }
}

这样页面层不用关心数据怎么存、怎么查,只需要调用 ViewModel 方法即可。页面会更干净,也更容易继续扩展。

七、视觉风格

项目整体采用暖色背景、圆角卡片、柔和图标和轻量动效。对于语文学习应用来说,这种风格比冷冰冰的工具型界面更适合。

比如主题色集中在 ThemeColors.ets 中:

get backgroundColor(): string {
  return this.isDark ? '#1A1A2E' : '#FFF9F0';
}

get cardBackground(): string {
  return this.isDark ? '#2D2D44' : '#FFFFFF';
}

统一主题后,页面就不需要到处写颜色值,后期调整风格也方便。

八、适合放的截图

建议在 CSDN 文章里放这些图:

  • 首页截图:展示整体风格。
  • 诗词详情页截图:展示内容阅读体验。
  • 学习中心截图:展示打卡与学习模块。
  • 我的页面截图:展示数据看板。

图文结合后,读者会更容易理解这个项目不是简单页面拼接,而是一个完整学习 App。

总结

这个项目的搭建思路可以概括为:先确定学习场景,再拆模块,再用 Index.ets 做页面容器,用 AppStorage 做轻量状态流转,用 ViewModel 管业务逻辑,最后通过主题系统和动效提升完成度。

对于想学习 OpenHarmony 的同学来说,这类项目非常适合练手:不依赖复杂服务端,却能覆盖 UI、状态、数据、交互、适配等多个知识点。🚀

img

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐