当前位置: 首页 > news >正文

OpenHarmony 英语学习 App 实战:自定义生词本、持久化存储与学习数据管理

OpenHarmony 英语学习 App 实战:自定义生词本、持久化存储与学习数据管理

摘要

英语学习 App 不能只提供固定词库。真实学习中,用户会从课本、阅读、听力、影视台词里遇到自己的生词,因此“自定义生词本”是非常重要的功能。本文以「英语视界 YingYu」项目为例,分享如何在 OpenHarmony/HarmonyOS 中实现自定义生词本、详情弹窗、添加表单、搜索过滤和本地持久化。📘

相关文件包括:

entry/src/main/ets/pages/CustomWordBook.ets entry/src/main/ets/utils/StorageService.ts entry/src/main/ets/model/DataModels.ts entry/src/main/ets/utils/YingYuPreferences.ts

一、自定义生词本要解决什么问题?

固定词库适合系统学习,但用户自己的生词更有价值:

  • 课外阅读遇到的词;
  • 老师补充的重点词;
  • 听力材料里的陌生词;
  • 错题中反复出现的词;
  • 考试作文常用表达。

所以自定义生词本需要具备:

  • 添加单词;
  • 保存音标、释义、例句、标签;
  • 查看详情;
  • 搜索过滤;
  • 参与复习系统;
  • 本地持久化保存。

二、数据模型:CustomWord

项目中使用CustomWord表示一个自定义单词:

export interface CustomWord {id:stringword:stringphonetic?:stringtranslation:stringexample?:stringtags:string[] createdAt:stringreviewCount:numbermastered:boolean}

字段设计比较完整:

  • id:唯一标识;
  • word:英文单词;
  • phonetic:可选音标;
  • translation:中文释义;
  • example:可选例句;
  • tags:标签;
  • createdAt:添加时间;
  • reviewCount:复习次数;
  • mastered:是否掌握。

这些字段不仅能展示单词详情,也能和复习系统、统计系统结合。

三、存储 Key 设计

StorageService.ts中集中管理存储 Key:

constSTORAGE_KEY_CUSTOM_WORDS ='yingyu_custom_words'constSTORAGE_KEY_REVIEW_RECORDS ='yingyu_review_records'constSTORAGE_KEY_DAILY_TASKS ='yingyu_daily_tasks'constSTORAGE_KEY_LEARNING_GOALS ='yingyu_learning_goals'

把 Key 放在统一服务里有两个好处:

  • 避免页面里到处写字符串;
  • 后续迁移数据结构更方便。

四、生成唯一 ID

添加单词时需要生成唯一 ID:

functiongenerateId():string{ returnDate.now().toString(36)+Math.random().toString(36).substring(2,9) }

这是一个轻量方案,适合本地数据。它结合时间戳和随机字符串,在单机使用场景下足够可靠。

五、读取自定义单词

读取逻辑封装在getCustomWords()中:

exportfunctiongetCustomWords():CustomWord[] {try{conststored =AppStorage.get<string>(STORAGE_KEY_CUSTOM_WORDS)if(stored) {returnJSON.parse(stored)asCustomWord[] } }catch(e) {console.error('Failed to load custom words:', e) }return[] }

这里有一个值得保留的习惯:读取失败时返回空数组,而不是让页面崩掉。学习类应用要优先保证可用性。

六、保存自定义单词

保存时把数组序列化成 JSON:

exportfunctionsaveCustomWords(words: CustomWord[]): void {try{AppStorage.setOrCreate(STORAGE_KEY_CUSTOM_WORDS, JSON.stringify(words)) } catch (e) { console.error('Failedtosave custom words:', e) } }

对于小规模本地生词本,JSON 数组足够简单。后续如果数据量上升,可以迁移到数据库或云端同步。

七、添加单词:补齐系统字段

页面提交的只是用户输入字段,真正保存前由服务层补齐 ID、创建时间、复习次数和掌握状态:

exportfunctionaddCustomWord(word: Omit<CustomWord,'id'|'createdAt'|'reviewCount'|'mastered'>):CustomWord{constnewWord:CustomWord= { ...word,id:generateId(),createdAt:newDate().toISOString(),reviewCount:0,mastered:false}constwords =getCustomWords() words.push(newWord)saveCustomWords(words)returnnewWord }

这样页面只关心用户输入,服务层负责数据完整性。

八、更新和删除

更新单词:

exportfunctionupdateCustomWord(id:string,updates: Partial<CustomWord>): boolean { const words = getCustomWords()const index = words.findIndex(w=>w.id===id)if(index !== -1) { words[index]= { ...words[index], ...updates } saveCustomWords(words)returntrue} returnfalse}

删除单词:

exportfunctiondeleteCustomWord(id:string):boolean{constwords =getCustomWords()constfiltered = words.filter(w=>w.id!== id)if(filtered.length!== words.length) {saveCustomWords(filtered)returntrue}returnfalse}

返回boolean可以让页面判断操作是否成功,并显示 Toast 或刷新列表。

九、搜索过滤

搜索逻辑同时支持英文、中文释义和标签:

exportfunctionsearchCustomWords(keyword:string): CustomWord[]{ const words = getCustomWords()const lower = keyword.toLowerCase()return words.filter(w => w.word.toLowerCase().includes(lower)||w.translation.toLowerCase().includes(lower)||w.tags.some(t => t.toLowerCase().includes(lower)) ) }

这种搜索方式对用户很友好:

  • 输入英文可以找到单词;
  • 输入中文可以找到释义;
  • 输入标签可以找到专题词。

十、添加单词表单

CustomWordBook.ets中定义了AddWordSheet子组件,用于处理添加表单。

@Componentstruct AddWordSheet {@Linkvisible: booleanonWordAdded: () => void = () => {}@StatewordText: string =''@Statephonetic: string =''@Statetranslation: string =''@Stateexample: string =''@StatetagsInput: string =''}

这里把表单做成独立子组件,而不是直接放在页面里,可以减少整页重建,也更利于维护。

提交时处理标签:

const tags = this.tagsInput.split(',').map(t => t.trim()).filter(t => t.length>0)

标签支持逗号分隔,适合用户输入“考试, 写作, 高频词”这样的内容。

十一、详情弹窗:WordDetailSheet

项目还实现了单词详情弹窗:

@Componentstruct WordDetailSheet {@Linkvisible: boolean@Propword: CustomWord = { id: '', word: '', translation: '', tags: [], createdAt: '', reviewCount: 0, mastered: false } }

弹窗进入时有缩放和透明度动画:

aboutToAppear() {this.dialogScale =0.88this.dialogOpacity =0animateTo({ duration:260, curve: Curve.EaseOut }, () => {this.dialogScale =1this.dialogOpacity =1}) }

展示内容包括:

  • 单词;
  • 音标;
  • 中文释义;
  • 例句;
  • 标签;
  • 添加时间;
  • 复习次数或掌握状态。

十二、本地持久化的另一层:Preferences 封装

项目中还有YingYuPreferences.ts,用于 Preferences 和 AppStorage 的兜底封装。

exportfunctioninitYingYuUserData(context: common.UIAbilityContext):void{if(pref) {return}try{ pref = preferences.getPreferencesSync(context, {name:'yingyu_user_data_v1'}) }catch(e) {console.error('initYingYuUserData failed:',JSON.stringify(e)) } }

读取时优先 Preferences,失败则回退 AppStorage:

exportfunctionyingyuPrefGet(key:string):string|undefined{if(pref) {constv = pref.getSync(key,'')asstringreturnv.length>0? v :undefined}constfallback =AppStorage.get<string>(key)if(fallback !==undefined&& fallback.length>0) {returnfallback }returnundefined}

这种封装让数据层更稳,也便于后续统一替换存储方案。

十三、小结

本文结合「英语视界 YingYu」项目,拆解了自定义生词本的完整实现:

  • 使用CustomWord描述用户单词;
  • 使用StorageService封装增删改查;
  • 使用 JSON + AppStorage 保存轻量数据;
  • 使用searchCustomWords()支持英文、中文、标签搜索;
  • 使用AddWordSheet管理添加表单;
  • 使用WordDetailSheet展示单词详情;
  • 使用 Preferences 封装增强持久化可靠性。

自定义生词本让学习 App 从“固定内容工具”变成“用户自己的学习资料库”。这类功能虽然不 flashy,但非常能提升长期使用价值。📖

http://www.cnnetsun.cn/news/3093639.html

相关文章:

  • yarn 的单作业运行模式
  • 在以往的项目开发中,在很多地方用到了多线程。
  • HBM吸走产能,东芯股份的SLC NAND开始涨价
  • RAII 有什么作用
  • 后台状态巡检低效怎么排查:状态字段、截图证据和任务日志设计
  • 电子自旋的诡异之谜破解 —— 原创电子结构理
  • 死磕信号量实现读者-写者:我被自己写的代码坑惨了
  • 出口工控硬件选型干货:工业 DC-DC/AC-DC 模块电源三点筛选标准丨国产化丨直流电源模块
  • 哈佛等联合研究团队揭开视频生成模型的致命盲区
  • 《Windows Go gRPC 端口占用 bind 报错完整解决方案|Kratos 微服务优雅停机保姆级教程》
  • 3分钟从B站视频到文字稿:bili2text终极指南
  • iSpaRo 2025|月球基地布线,机器人“胳膊不够长”怎么办?
  • 《传世无双》2026年7月最新官网下载:九大元神组合与实战攻略
  • 【JAVA毕设源码分享】基于springboot基于协同过滤课程推荐的线上安全教育平台的设计与实现(程序+文档+代码讲解+一条龙定制)
  • 使用74HC165与ARM Cortex-M4实现高效并行转串行输入设计
  • 后端资源池化:何时用?怎么用?
  • 基于单片机的工件位置控制系统设计
  • AI账号管理与数据备份的实战解决方案
  • 安装登录5分钟
  • go: Handshaking Pattern
  • 看见旋律 - WinUI3 实现音乐监听:47 种漂亮的数学线条形态
  • 实战指南:如何用changedetection.io构建企业级网站变更监控系统
  • 遗传算法实操调参与收敛性诊断实战指南
  • AI 辅助:后端架构选型取舍:没有银弹,只有约束条件
  • 系统调用全路径拆解:从用户态 read(fd) 到内核驱动的上下文切换代价与字符设备实战
  • 3D渲染新范式:从画面像素到全域实景空间 像素流实时建模 新一代视频孪生图形架构
  • AI 辅助:Service Mesh 落地经验:流量治理不是先把边车塞满
  • GitOps 发布实践:声明式配置也需要回滚纪律
  • AI浪潮下普通人焦虑何解?花叔、“五道口纳什”等UP主分享学习路径
  • 企业级检索增强 后端集成:Java 服务如何管理知识库版本