OpenHarmony 英语学习 App 实战:ArkTS 项目结构、页面路由与模块化拆分
OpenHarmony 英语学习 App 实战:ArkTS 项目结构、页面路由与模块化拆分
摘要
当一个 ArkUI 项目从几个页面增长到二十多个页面时,最容易出现的问题不是某个功能不会写,而是结构开始混乱:页面之间互相依赖、工具函数散落、数据模型重复定义、路由路径难以维护。本文以「英语视界 YingYu」项目为例,分享 OpenHarmony/HarmonyOS ArkTS 项目如何做页面路由和模块化拆分。🧩
本文重点包括:
- 目录分层;
- 页面注册;
- 路由跳转;
- 数据模型集中管理;
- 工具模块拆分;
- 页面组件拆分;
- 后续可维护性建议。
一、项目结构总览
项目核心 ArkTS 代码位于:
entry/src/main/ets/
├── MainTabs.ets
├── entryability/
│ └── EntryAbility.ets
├── pages/
├── components/
├── data/
├── model/
├── styles/
└── utils/
这是一种比较清晰的中型应用结构:
entryability:应用生命周期;pages:页面;components:复用 UI 组件;data:静态学习内容;model:类型定义;utils:业务工具;styles:主题和设计 token。
二、EntryAbility:只做应用级初始化
EntryAbility.ets 负责:
- 设置颜色模式;
- 初始化用户数据;
- 初始化分布式同步;
- 加载主页面;
- 处理前后台生命周期;
- 处理跨设备续接。
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET)
initYingYuUserData(this.context)
initDistributedStore(this.context)
}
窗口创建时加载页面:
onWindowStageCreate(windowStage: window.WindowStage): void {
windowStage.loadContent('pages/MainTabsV2', (err) => {
if (err.code) {
windowStage.loadContent('pages/MainTabs', () => {})
}
})
}
入口 Ability 不应该写具体业务 UI,这样应用启动逻辑才清爽。
三、页面注册:main_pages.json
所有可路由页面都在 main_pages.json 中注册:
{
"src": [
"pages/Index",
"pages/Home",
"MainTabs",
"pages/MainTabsV2",
"pages/Vocabulary",
"pages/VocabularyDetail",
"pages/DailySentence",
"pages/Listening",
"pages/FunEnglish",
"pages/FunEnglishDetail",
"pages/Settings",
"pages/CustomWordBook",
"pages/ReviewCenter",
"pages/DailyTask",
"pages/LearningCalendar",
"pages/LearningGoals",
"pages/Grammar",
"pages/PhraseStudy",
"pages/ShareCenter"
]
}
页面注册的好处是路由清晰,但也要求团队对路径命名保持一致。
四、路由跳转
页面间跳转使用 @ohos.router:
import router from '@ohos.router'
首页快捷入口中有大量路由跳转:
this.QuickAccessTile(
'复习中心',
'艾宾浩斯',
$r('sys.symbol.arrow_2_circlepath'),
$r('app.color.icon_tag_grade'),
() => router.pushUrl({ url: 'pages/ReviewCenter' })
)
返回上一页:
SymbolGlyph($r('sys.symbol.chevron_left'))
.onClick(() => router.back())
路由建议:
- 页面路径统一放在常量文件中;
- 高频页面入口集中管理;
- 避免字符串路径散落在过多页面中。
五、Tabs 作为主导航
项目使用 Tabs 做主导航,再用自定义底部导航控制切换:
Tabs({
index: this.currentIndex,
controller: this.tabsController
}) {
TabContent() {
this.HomeTab()
}
TabContent() {
this.StudyTab()
}
TabContent() {
this.PracticeTab()
}
TabContent() {
this.ProfileTab()
}
}
.barPosition(BarPosition.End)
切换时:
this.tabsController.changeIndex(index)
这种方式把主页面分成首页、学习、练习、我的四大区域,符合学习类 App 的信息架构。
六、数据模型集中管理
项目中的模型集中在 DataModels.ts:
export interface Word {
id: number
word: string
phonetic: string
translation: string
example: string
exampleTranslation: string
grade: number
}
复习记录:
export interface ReviewRecord {
wordId: string
wordType: 'vocabulary' | 'custom' | 'funEnglish' | 'grammar'
learningDate: string
reviewDates: string[]
nextReviewDate: string
easeFactor: number
interval: number
repetitions: number
}
集中管理模型的好处:
- 页面和工具函数共享类型;
- 减少重复定义;
- 后续接口对接更容易;
- 编译期能发现字段错误。
七、data 目录:内置学习内容
项目把静态学习内容放在 data 目录:
data/
├── VocabularyData.ts
├── DailySentenceData.ts
├── ListeningData.ts
├── FunEnglishData.ts
├── GrammarData.ts
└── PhraseData.ts
这种结构适合当前阶段:
- 词库体量不大;
- 听力和语法内容可内置;
- 离线也可学习;
- 页面加载速度快。
后续如果内容量增长,可以逐步迁移到服务端或按需下载。
八、utils 目录:业务能力模块化
utils 目录承担项目的业务能力:
utils/
├── UserDataManager.ts
├── StorageService.ts
├── SpacedRepetition.ts
├── ShareService.ts
├── DistributedSync.ets
├── ListeningTtsHelper.ets
├── YingYuPreferences.ts
├── DeviceUtils.ets
└── AdaptiveDimensions.ets
每个工具文件对应一个能力:
- 用户数据;
- 存储服务;
- 复习算法;
- 分享能力;
- 分布式同步;
- TTS;
- 持久化;
- 设备判断;
- 响应式尺寸。
这比把所有函数写进页面文件要清晰得多。
九、组件拆分:页面内也可以拆子组件
在 CustomWordBook.ets 中,添加单词和详情弹窗被拆成独立组件:
@Component
struct AddWordSheet {
@Link visible: boolean
onWordAdded: () => void = () => {}
}
详情弹窗:
@Component
struct WordDetailSheet {
@Link visible: boolean
@Prop word: CustomWord = {
id: '',
word: '',
translation: '',
tags: [],
createdAt: '',
reviewCount: 0,
mastered: false
}
}
这种拆分能减少主页面复杂度,也避免输入框状态变化导致整页频繁重建。
十、存储层封装
底层 Preferences 封装在 YingYuPreferences.ts:
export function yingyuPrefSet(key: string, value: string): void {
if (!pref) {
AppStorage.setOrCreate(key, value)
return
}
pref.putSync(key, value)
void pref.flush()
}
业务层再通过 UserDataManager.ts 和 StorageService.ts 读写学习数据。这样的层次是:
页面
-> UserDataManager / StorageService
-> YingYuPreferences / AppStorage
-> Preferences
页面不直接接触底层存储细节,后续迁移更容易。
十一、模块化建议
继续扩展项目时,可以进一步优化:
- 抽出
Routes.ts统一管理页面路径; - 把首页大文件拆成多个组件文件;
- 把成就规则拆成独立
AchievementService; - 把复习算法和 UI 更新逻辑完全统一;
- 给
StorageService加数据版本号; - 给静态数据增加按年级索引;
- 把 AI 接口模型同步到移动端类型定义。
这些优化不是一开始必须做,但项目继续变大时会很有价值。
十二、小结
本文结合「英语视界 YingYu」项目,梳理了 OpenHarmony ArkTS 项目的模块化拆分:
EntryAbility负责应用级初始化;main_pages.json管理页面注册;router.pushUrl()负责页面跳转;Tabs构建主导航;DataModels.ts集中定义类型;data目录放内置学习内容;utils目录封装业务能力;- 页面内复杂弹窗可拆成子组件;
- 存储层通过服务封装,避免页面直接操作底层。
项目越大,结构越重要。好的模块化不是为了“看起来高级”,而是为了让下一次加功能时不痛苦。🧱


更多推荐



所有评论(0)