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

02数据模型与单词仓库-鸿蒙PC端Electron开发

欢迎加入开源鸿蒙PC社区https://harmonypc.csdn.net/源码仓库https://atomgit.com/qq_33247427/englishProject.git效果截图第2篇数据模型与单词仓库系列教程导航篇号标题状态01环境搭建与项目创建✅ 已完成02数据模型与单词仓库本篇03主入口页面与导航结构下一篇04极速划词页面实现05手写画布实现06百度 OCR 手写识别接入07答案比对与反馈 UI08单词切换与底部导航09词根分解与水印展示10项目总结与优化方向一、为什么要先设计数据模型在动手写 UI 之前先把数据结构想清楚有几个好处UI 和数据解耦— 页面只关心拿到什么数据不关心数据从哪来方便后续扩展— 今天用硬编码数据明天换数据库或网络接口UI 层不用改团队协作— 前端和后端可以基于同一份接口定义并行开发类型安全— ArkTS 是强类型语言定义好接口后编译器帮你检查我们的单词学习 App 需要管理以下信息单词本身英文、释义、音标词根词缀分解帮助记忆学习分组按日期唯一标识列表渲染需要二、定义 VocabularyWord 数据模型2.1 创建模型文件在electron/src/main/ets/models/目录下创建VocabularyWord.ets/** * 词根/词缀分解项 * 用于展示单词的构词法帮助用户理解和记忆 */ export interface WordPart { /** 词根/词缀文本如 electr */ text: string; /** 含义如 电 */ meaning: string; /** 类型prefix前缀| root词根| suffix后缀 */ type: string; } /** * 单词详情信息 * 包含词根分解等扩展信息 */ export interface WordDetail { /** 词根词缀分解列表 */ parts: WordPart[]; } /** * 单词数据模型 * 这是整个应用最核心的数据结构 */ export interface VocabularyWord { /** 唯一标识符用于列表渲染的 key */ id: string; /** 英文单词 */ english: string; /** 中文释义 */ meaning: string; /** 音标如 /ɪˈlektrɪkl/ */ phonetic: string; /** 音译可选如 伊莱克特瑞克 */ transliteration?: string; /** 词根分解详情可选 */ detail?: WordDetail; /** 所属日期分组如 3/12 */ date?: string; }2.2 设计思路详解为什么id用 string 而不是 numberArkUI 的ForEach和LazyForEach需要一个唯一的 key 来标识列表项。用 string 类型更灵活可以是数据库主键、UUID、或者简单的序号字符串。为什么detail和transliteration是可选的不是所有单词都有词根分解信息也不是所有单词都需要音译。用?标记为可选字段避免强制填充无意义的空值。为什么type用 string 而不是 enumArkTS 对 enum 的支持有一些限制特别是在 UI 描述中使用时。用 string 字面量prefix | root | suffix更简单直接也方便从 JSON 数据源加载。2.3 WordPart 的颜色编码设计在后续的 UI 中不同类型的词根词缀会用不同颜色展示type 值含义背景色文字色示例prefix前缀#FFEBEE浅红#E57373trans-跨越root词根#EEF1E4浅绿#8B9D6B-form形式suffix后缀#DBEAFE浅蓝#64B5F6-tion名词后缀这种颜色编码让用户一眼就能区分词根词缀的类型提升学习效率。三、创建单词数据仓库3.1 Repository 模式介绍Repository仓库模式是一种常见的数据层设计模式┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ UI 页面 │ ──→ │ Repository │ ──→ │ 数据源 │ │ (只管展示) │ │ (统一接口) │ │ (本地/网络) │ └──────────────┘ └──────────────┘ └──────────────┘好处UI 层不需要知道数据来自哪里切换数据源本地 → 网络只需修改 Repository 内部实现方便做缓存、数据转换等中间处理3.2 创建 SpeedWordRepository在electron/src/main/ets/data/目录下创建SpeedWordRepository.etsimport { VocabularyWord } from ../models/VocabularyWord; /** * 极速划词 默写单词的数据仓库 * 当前使用硬编码数据后续可替换为数据库或网络接口 */ export class SpeedWordRepository { private words: VocabularyWord[] [ { id: 1, english: electrical, meaning: adj. 电的与电有关的, phonetic: /ɪˈlektrɪkl/, date: 3/12, detail: { parts: [ { text: electr, meaning: 电, type: root }, { text: ical, meaning: 形容词后缀, type: suffix } ] } }, { id: 2, english: transform, meaning: v. 使转变使改观, phonetic: /trænsˈfɔːrm/, date: 3/12, detail: { parts: [ { text: trans, meaning: 跨越、转变, type: prefix }, { text: form, meaning: 形式、形状, type: root } ] } }, { id: 3, english: international, meaning: adj. 国际的, phonetic: /ˌɪntərˈnæʃənl/, date: 3/12, detail: { parts: [ { text: inter, meaning: 在…之间, type: prefix }, { text: nation, meaning: 国家, type: root }, { text: al, meaning: 形容词后缀, type: suffix } ] } }, { id: 4, english: uncomfortable, meaning: adj. 不舒服的不自在的, phonetic: /ʌnˈkʌmftəbl/, date: 3/12, detail: { parts: [ { text: un, meaning: 不、否定, type: prefix }, { text: comfort, meaning: 舒适, type: root }, { text: able, meaning: 能…的, type: suffix } ] } }, { id: 5, english: transportation, meaning: n. 运输交通工具, phonetic: /ˌtrænspɔːrˈteɪʃn/, date: 3/12, detail: { parts: [ { text: trans, meaning: 跨越, type: prefix }, { text: port, meaning: 搬运, type: root }, { text: ation, meaning: 名词后缀, type: suffix } ] } }, { id: 6, english: environment, meaning: n. 环境周围的事物, phonetic: /ɪnˈvaɪrənmənt/, date: 3/11, detail: { parts: [ { text: en, meaning: 使…, type: prefix }, { text: viron, meaning: 周围, type: root }, { text: ment, meaning: 名词后缀, type: suffix } ] } }, { id: 7, english: independent, meaning: adj. 独立的自主的, phonetic: /ˌɪndɪˈpendənt/, date: 3/11, detail: { parts: [ { text: in, meaning: 不、否定, type: prefix }, { text: depend, meaning: 依赖, type: root }, { text: ent, meaning: 形容词后缀, type: suffix } ] } }, // ... 更多单词数据 ]; /** * 按日期获取单词列表 * param date 日期字符串如 3/12 * returns 该日期下的所有单词 */ getWordsByDate(date: string): VocabularyWord[] { return this.words.filter((w: VocabularyWord) w.date date); } /** * 获取所有单词 * returns 完整单词列表 */ getAllWords(): VocabularyWord[] { return this.words; } /** * 根据 ID 获取单个单词 * param id 单词唯一标识 * returns 匹配的单词未找到返回 undefined */ getWordById(id: string): VocabularyWord | undefined { return this.words.find((w: VocabularyWord) w.id id); } /** * 获取所有可用的日期分组 * returns 去重后的日期列表 */ getAvailableDates(): string[] { const dateSet new Setstring(); for (const word of this.words) { if (word.date) { dateSet.add(word.date); } } return Array.from(dateSet).sort(); } }3.3 方法设计说明方法用途使用场景getWordsByDate(date)按日期筛选极速划词页面按天显示getAllWords()获取全部搜索功能、统计getWordById(id)精确查找跳转到单词详情getAvailableDates()获取日期列表日期选择器四、创建 HandwritingWordRepository除了极速划词的数据源手写练习页面也需要一个独立的数据仓库。创建electron/src/main/ets/data/HandwritingWordRepository.etsimport { VocabularyWord } from ../models/VocabularyWord; /** * 手写练习专用数据仓库 * 提供随机顺序的单词适合默写测试场景 */ export class HandwritingWordRepository { private words: VocabularyWord[] [ { id: hw-1, english: appreciate, meaning: v. 欣赏感激理解, phonetic: /əˈpriːʃieɪt/, transliteration: 阿普瑞希艾特 }, { id: hw-2, english: communicate, meaning: v. 交流传达, phonetic: /kəˈmjuːnɪkeɪt/, transliteration: 克缪尼凯特 }, { id: hw-3, english: demonstrate, meaning: v. 证明演示示威, phonetic: /ˈdemənstreɪt/, transliteration: 戴蒙斯特瑞特 }, // ... 更多单词 ]; /** * 获取所有手写练习单词 */ getAllWords(): VocabularyWord[] { return this.words; } /** * 获取单词总数 */ getWordCount(): number { return this.words.length; } }4.1 两个 Repository 的区别对比项SpeedWordRepositoryHandwritingWordRepository用途极速划词 默写独立手写练习分组方式按日期无分组词根分解有可选音译无有数据量每天 15-20 个全量词库五、在页面中使用数据仓库5.1 基本用法import { SpeedWordRepository } from ../data/SpeedWordRepository; import { VocabularyWord } from ../models/VocabularyWord; Entry Component struct MyPage { // 创建仓库实例私有不需要响应式 private repository: SpeedWordRepository new SpeedWordRepository(); // 状态变量UI 会响应变化 State words: VocabularyWord[] []; State selectedDate: string 3/12; aboutToAppear() { // 页面创建时加载数据 this.words this.repository.getWordsByDate(this.selectedDate); } build() { Column() { // 使用 ForEach 渲染列表 ForEach(this.words, (word: VocabularyWord) { Row() { Text(word.english) .fontSize(16) .fontWeight(FontWeight.Medium) Text(word.meaning) .fontSize(14) .fontColor(#6B7280) } .width(100%) .padding(12) }, (word: VocabularyWord) word.id) // key 函数 } } }5.2 关键点解析privatevsState// ❌ 不需要 State仓库实例不会变化 State repository: SpeedWordRepository new SpeedWordRepository(); // ✅ 正确仓库是私有的不触发 UI 刷新 private repository: SpeedWordRepository new SpeedWordRepository(); // ✅ 正确单词列表需要 State因为切换日期时会变化 State words: VocabularyWord[] [];ForEach 的 key 函数// ForEach 第三个参数是 key 生成函数 // 用于标识每个列表项帮助框架做最小化 DOM diff ForEach(this.words, (word: VocabularyWord) { // 渲染逻辑 }, (word: VocabularyWord) word.id) // ← 用 id 作为 key如果不提供 key 函数ArkUI 会用数组索引作为 key在数据变化时可能导致不必要的重渲染。5.3 切换日期加载数据selectDate(date: string) { this.selectedDate date; // 重新从仓库获取数据赋值给 State 变量触发 UI 刷新 this.words this.repository.getWordsByDate(date); }六、ArkTS 中数组状态的注意事项6.1 数组变更必须创建新引用ArkTS 的State检测的是引用变化不是内容变化// ❌ 错误push 不会触发 UI 刷新引用没变 this.words.push(newWord); // ✅ 正确创建新数组 this.words [...this.words, newWord]; // ❌ 错误splice 不会触发 UI 刷新 this.words.splice(index, 1); // ✅ 正确filter 返回新数组 this.words this.words.filter((w: VocabularyWord) w.id ! targetId);6.2 对象属性变更如果State是一个对象修改其属性也需要创建新对象State currentWord: VocabularyWord | null null; // ❌ 不会触发刷新 this.currentWord.meaning 新释义; // ✅ 创建新对象 this.currentWord { ...this.currentWord, meaning: 新释义 };七、数据层的后续扩展方向当前我们使用硬编码数据这在开发初期是最简单高效的方式。后续可以按需升级7.1 从 JSON 文件加载将单词数据放在resources/rawfile/words.json中import { resourceManager } from kit.LocalizationKit; async loadWordsFromFile(): PromiseVocabularyWord[] { const context getContext(this); const mgr context.resourceManager; const data await mgr.getRawFileContent(words.json); const text new TextDecoder().decode(data); return JSON.parse(text) as VocabularyWord[]; }7.2 使用 Preferences 持久化学习记录import { preferences } from kit.ArkData; // 保存已学习的单词 ID async saveLearnedWords(wordIds: string[]) { const store await preferences.getPreferences(getContext(this), learning); await store.put(learnedIds, JSON.stringify(wordIds)); await store.flush(); }7.3 接入网络 APIimport { http } from kit.NetworkKit; async fetchWordsFromServer(): PromiseVocabularyWord[] { const req http.createHttp(); try { const resp await req.request(https://api.example.com/words, { method: http.RequestMethod.GET }); return JSON.parse(resp.result as string) as VocabularyWord[]; } finally { req.destroy(); } }这些扩展都不需要修改 UI 层代码只需要修改 Repository 内部实现。八、本篇完整文件清单本篇新增的文件electron/src/main/ets/ ├── models/ │ └── VocabularyWord.ets ← 新增数据模型定义 └── data/ ├── SpeedWordRepository.ets ← 新增极速划词数据仓库 └── HandwritingWordRepository.ets ← 新增手写练习数据仓库九、本篇小结通过本篇教程我们完成了设计了VocabularyWord核心数据模型含词根分解理解了 Repository 模式的优势创建了SpeedWordRepository按日期分组创建了HandwritingWordRepository手写练习专用掌握了在页面中使用数据仓库的方法了解了 ArkTS 数组状态变更的注意事项规划了数据层的后续扩展方向下一篇预告第 3 篇主入口页面与导航结构— 我们将创建应用的主入口列表页NativeListPage实现功能入口卡片和页面路由跳转让用户能够进入极速划词和默写单词功能。

相关文章:

02数据模型与单词仓库-鸿蒙PC端Electron开发

欢迎加入开源鸿蒙PC社区 https://harmonypc.csdn.net/ 源码仓库 https://atomgit.com/qq_33247427/englishProject.git 效果截图 第2篇:数据模型与单词仓库 系列教程导航 篇号 标题 状态 01 环境搭建与项目创建 ✅ 已完成 02 数据模型与单词仓库 本篇 …...

Serverless平台为何总让人“又爱又恨”?揭秘Lovable设计的3层情感化架构(开发者体验×运维韧性×业务敏捷)

更多请点击: https://intelliparadigm.com 第一章:Serverless平台为何总让人“又爱又恨”? Serverless 架构在现代云原生开发中已成为主流选择,它承诺“无需管理服务器”,让开发者专注业务逻辑。然而,在真…...

面试记录 (2026/5/12)

问题一:java并发包下的AQS,了解多少? 这个真是没看过源码,就不班门弄斧了 直接学习下 大佬的经验 https://blog.csdn.net/qq_45772447/article/details/149126295?fromshareblogdetail&sharetypeblogdetail&sharerId149126295&…...

Sora 2国内可用性深度测评(2024Q2最新版):API调用失败率<0.8%的私有化部署方案首次公开

更多请点击: https://intelliparadigm.com 第一章:ChatGPT Sora 2视频生成怎么用 Sora 2 并非 OpenAI 官方发布的模型——截至目前(2024年中),OpenAI 仅公开了 Sora(初代)的演示能力&#xff0…...

Deep Lake:统一多模态AI数据存储与向量检索的实践指南

1. 项目概述:Deep Lake,一个为AI而生的数据湖 如果你正在构建一个需要处理图像、文本、音频、PDF,甚至医学影像DICOM文件的大模型应用,或者你在训练一个需要高效加载海量数据的深度学习模型,那么你很可能正被数据管理…...

OpenClaw智能体引导基准测试:本地LLM多步骤任务执行能力评估

1. 项目概述:一个专为LLM智能体设计的“开箱即用”能力基准测试 如果你最近在关注本地大语言模型(LLM)和智能体(Agent)的进展,可能会发现一个现象:很多模型在标准问答或代码生成任务上表现不错…...

【Google全家桶AI功能2026终极前瞻】:20位谷歌AI Lab核心工程师闭门透露的7大颠覆性升级路径

更多请点击: https://intelliparadigm.com 第一章:Google全家桶AI功能2026升级全景图谱 2026年,Google正式将Gemini 3.5 Ultra深度集成至全系生产力产品中,实现跨端、实时、上下文感知的AI协同。核心升级聚焦于“意图理解前置化”…...

Claude API开发实战:从模型选型到工具调用,一站式资源与代码详解

1. 项目概述与核心价值最近在折腾AI应用开发的朋友,估计没少为Claude API的调用和管理头疼。官方文档虽然详尽,但当你需要快速查找某个特定端点、对比不同模型参数,或者只是想找个现成的代码片段时,那种在多个页面间跳转、反复搜索…...

智慧工地起重机吊钩检测数据集VOC+YOLO格式1138张1类别

数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件)图片数量(jpg文件个数):1138标注数量(xml文件个数):1138标注数量(txt文件个数):1138标注类别…...

LLM与图数据库融合:自然语言驱动知识图谱查询实战

1. 项目概述:当LLM遇见图数据库,知识推理的新范式最近在探索如何让大语言模型(LLM)更好地处理复杂、结构化的知识时,我遇到了一个非常有意思的项目:dylanhogg/llmgraph。这个项目本质上是一个桥梁&#xff…...

IV测试仪选购避坑指南,这几点一定要提前了解

在光伏产业链中,IV测试仪应用广泛,覆盖组件分选、实验室检定、电站验收、运维排查等场景。市面上仪器品类繁杂,包含台式实验室款、生产线分选款、户外检测款,价格差距悬殊。不少采购人员不懂场景适配,盲目比价、堆砌参…...

只做中外合作办学,并且把它做深、做精

在中外合作办学领域,信息的透明与路径的可靠始终是学生与家长最核心的诉求。当越来越多项目涌现,如何甄别真正具备专业沉淀与行业敬畏心的服务者,成为选择前的第一道课题。这就是简申品牌存在的意义,而它背后的力量,来…...

如何快速集成Draw.io Mermaid插件:提升图表绘制效率的终极指南

如何快速集成Draw.io Mermaid插件:提升图表绘制效率的终极指南 【免费下载链接】drawio_mermaid_plugin Mermaid plugin for drawio desktop 项目地址: https://gitcode.com/gh_mirrors/dr/drawio_mermaid_plugin 还在为绘制复杂的流程图、时序图而烦恼吗&am…...

从RNN的“失忆症”到LSTM的“记忆宫殿”:图解三个门控单元如何拯救梯度消失

从RNN的"失忆症"到LSTM的"记忆宫殿":图解三个门控单元如何拯救梯度消失 想象一下,你正在阅读一本精彩的小说,但每翻过一页就会忘记前一页的大部分内容——这就是标准RNN神经网络面临的困境。在自然语言处理和时间序列分析…...

OpenAI面向欧洲部分用户开放网络安全专用模型GPT-5.5-Cyber,应对AI网络威胁

OpenAI推出欧洲专属网络安全模型 5月12日消息,据eWeek报道,OpenAI正式面向欧洲地区的部分用户开放了网络安全专用模型GPT-5.5-Cyber。该模型基于GPT-5.5架构开发,专为经过OpenAI验证的网络安全防御人员打造。 满足网络安全关键任务需求 GPT-5…...

Arm Forge工具链在HPC中的调试与性能优化实践

1. Arm Forge工具链概述高性能计算(HPC)领域的开发者经常面临并行程序调试和性能优化的挑战。Arm Forge作为一套集成化工具平台,包含了三个核心组件:DDT并行调试器、MAP性能分析器和Performance Reports报告生成工具。这套工具链特别适合处理MPI、OpenMP…...

NodeMCU固件烧录终极指南:告别命令行,5分钟搞定ESP8266刷机!

NodeMCU固件烧录终极指南:告别命令行,5分钟搞定ESP8266刷机! 【免费下载链接】nodemcu-pyflasher Self-contained NodeMCU flasher with GUI based on esptool.py and wxPython. 项目地址: https://gitcode.com/gh_mirrors/no/nodemcu-pyfl…...

Docker镜像标准化机器人开发环境:OpenClaw项目协作实践

1. 项目概述:一个面向协作开发的OpenClaw项目镜像最近在开源社区里,一个名为laolin5564/openclaw-collab-dev的Docker镜像引起了我的注意。这个镜像的名字本身就很有意思,它明确指向了“OpenClaw”和“协作开发”这两个核心概念。对于从事机器…...

基于 DWT 的盲数字水印实现(嵌入与提取)

一、原理 盲数字水印(Blind Watermarking)指提取水印时无需原始载体图像,仅依靠含水印图像和密钥即可完成。 DWT(离散小波变换) 将图像分解为: LL:低频近似分量(能量集中&#xff0c…...

如何高效获取网盘直链:8大平台的完整解决方案

如何高效获取网盘直链:8大平台的完整解决方案 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘 / 迅…...

RootlessJamesDSP:无Root环境下的Android全局音频处理方案解析

1. 项目概述:在无根环境中驯服音频的“魔法师”如果你是一个对手机音质有追求的安卓用户,或者是一个喜欢折腾音频处理插件的玩家,那么你很可能听说过或者用过 JamesDSP。它是一款功能强大的音频处理引擎,能够通过复杂的算法&#…...

交完Essay才发现Turnitin更新了AI检测?我是这么应对的

上学期我的一个朋友被约谈了。 教授发邮件说:"你的Essay和AI生成文本相似度过高,请来办公室解释。" 他确实用了AI——谁没用呢——但他也认真改写了好几遍。问题是,Turnitin在2025年更新了AI检测模型,现在它不只看词汇…...

WIZnet-EVB-Pico2开始,用MicroPython玩转以太网开发

大家好呀,好久没跟大家唠唠我最近捣鼓的嵌入式小玩意儿了! 这段时间一直在折腾 MicroPython 的网络开发,踩了不少 “入门劝退坑”,也挖到了个让我直呼 “相见恨晚” 的宝藏 ——​WIZnet EVB-Pico2 系列开发板​。说真的&#xf…...

ARM GICv4.1 GICD_TYPER2寄存器详解与虚拟化应用

1. GICD_TYPER2寄存器概述 GICD_TYPER2是ARM GICv4.1架构中引入的关键寄存器,属于中断控制器类型寄存器家族。作为GIC Distributor的一部分,它专门用于增强虚拟化场景下的中断管理能力。这个32位寄存器位于内存映射地址Dist_base 0x000C处,仅…...

重磅!移远通信旗下物联网智能品牌 艾络迅™ 正式发布

物联网技术正深刻重塑产业格局,智能化转型已成为企业核心竞争力的关键。然而,企业在推进物联网项目时普遍面临技术门槛高、开发周期长、系统对接难、全球连接复杂等核心挑战。为破解行业智能化转型难题,帮助更多企业提升物联网开发效率&#…...

我花三天实测了DeepSeek V4,发现它根本不是来跟GPT-4o打架的

2026年4月24号,DeepSeek V4发布。 同一天,GPT-5.5也发布了。 这不是巧合,这是宣战。 但测了三天之后,我发现一个反直觉的结论,DeepSeek V4的真正对手根本不是GPT-4o,也不是Claude 3.5。 它要干掉的&#xf…...

uniapp中获取APP应用签名信息

/*** 获取应用签名MD5* returns {Promise<unknown>}*/ function getAppSignatureMD5() {return new Promise((resolve) > {// 1. 环境检查if (typeof plus "undefined" || uni.getSystemInfoSync().platform ! "android") {resolve(null);return…...

Java基础全套教程(三)—— 控制语句、方法、递归算法

Java基础全套教程&#xff08;三&#xff09;—— 控制语句、方法、递归算法 本章是Java编程从基础语法走向逻辑编程的核心转折点。前面我们学习了变量、数据类型、运算符&#xff0c;只能实现简单的顺序执行代码。而真正的程序&#xff0c;需要具备判断能力、重复执行能力、代…...

宁波市新房装修推荐

好的&#xff0c;根据您的要求&#xff0c;我为您生成一篇关于宁波市新房装修的推荐文章&#xff0c;着重推荐宿迁市三色雨装饰材料有限公司的墙布产品&#xff0c;语言力求自然、真实&#xff0c;避免营销话术。宁波新房装修&#xff0c;墙面选择不妨多看看“三色雨”在宁波&a…...

码森防伪溯源系统:一站式构建产品信任桥梁,赋能品牌全流程数字化管理

在假冒伪劣产品屡禁不止、消费者对产品来源与真实性日益关注的今天&#xff0c;如何高效实现防伪、溯源、营销、管理一体化&#xff0c;已成为品牌方与技术开发者共同关注的核心问题。 防伪溯源系统&#xff0c;正是这样一套集低成本、易操作、强扩展性于一体的综合性解决方案。…...