ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

灯光模拟HarmonyOS应用实战-13-答题后为何要锁定选项并立即写入错题记录

灯光模拟HarmonyOS应用实战-13-答题后为何要锁定选项并立即写入错题记录 ![理论题如果允许连续点选第一次误选可能被第二次正确覆盖。源码在answerTheoryQuestion开头用 selectedAnswer 锁定。本文只看答题锁定和错题记录。源码要求一题只记录第一次选择避免用户反复点击把第一次误选覆盖掉。先看这篇要解决的具体问题答题记录的核心不是某个 ArkTS 语法点而是边界划分。一个练习功能至少有四个层面入口从哪里来数据在哪里定义用户动作怎样改变状态结果是否保存。只看 UI 会漏掉判题只看题库会漏掉重置只看存储又解释不了按钮为什么这样设计。更稳的做法是把本文的功能拆成下面六步点击选项 - 已答则返回 - 取得正确答案 - 设置反馈文案 - 写入本地记录 - 历史页复盘。后面所有代码片段都服务于这条线不额外展开无关模块。源码边界和文件分工源码位置作用entry/src/main/ets/pages/Index.ets页面状态、Builder、入口分发和业务处理entry/src/main/ets/services/PracticeStore.etsPreferences 本地记录和统计这些节选不是为了贴完整文件而是为了把当前链路看清楚。Index.ets的选项 Builder、answerTheoryQuestion、getOptionColor和addSimpleRecord串起答题流程PracticeStore负责落盘。源码路径D:\ProgramData\huawei\lesson\The_kemusan 阅读顺序入口 - 数据 - 状态 - UI - 本地记录 写作边界只解释当前源码能证实的功能不替代真机运行和发布验证选项点击后立即锁定本题源码节选entry/src/main/ets/pages/Index.ets:557Builder TheoryQuestionCard() { if (this.activeQuestions.length 0) { this.EmptyState(暂无题目, 当前分类暂无内置题目。) } else { Column({ space: 12 }) { Text(${this.activeMode} · ${this.activeQuestionIndex 1}/${this.activeQuestions.length}) .fontSize(13) .fontColor($r(app.color.text_secondary)) Text(this.getDisplayQuestionTitle()) .fontSize(22) .fontWeight(FontWeight.Bold) .fontColor($r(app.color.text_primary)) .lineHeight(31) if (this.getCurrentQuestion().type TYPE_JUDGE) { Row({ space: 10 }) { ForEach(this.getCurrentQuestion().options, (option: QuestionOption) { this.JudgeAnswerOption(option) }, (option: QuestionOption) this.getQuestionOptionRenderKey(option)) } .width(100%) } else { ForEach(this.getCurrentQuestion().options, (option: QuestionOption) { this.AnswerOption(option) }, (option: QuestionOption) this.getQuestionOptionRenderKey(option)) } Text(this.answerMessage) .fontSize(14) .fontWeight(FontWeight.Medium) .fontColor(this.answerCorrect ? $r(app.color.success) : $r(app.color.danger)) .lineHeight(22) if (this.selectedAnswer.length 0) { Text(this.getCurrentQuestion().explanation) .fontSize(14) .fontColor($r(app.color.text_secondary)) .lineHeight(22) } } .width(100%) .padding(18) .backgroundColor($r(app.color.surface_bg)) .borderRadius(20) .border({ width: 1, color: $r(app.color.border_subtle) }) } } Builder AnswerOption(option: QuestionOption) { Text(${option.key}. ${option.text}) .fontSize(16) .fontColor(this.getOptionColor(option.key)) .padding(13) .width(100%) .backgroundColor(this.selectedAnswer option.key ? $r(app.color.panel_bg) : $r(app.color.button_bg)) .borderRadius(14) .border({ width: 1, color: this.selectedAnswer option.key ? $r(app.color.accent) : $r(app.color.border_subtle) }) .onClick(() { this.answerTheoryQuestion(option.key); }) } Builder JudgeAnswerOption(option: QuestionOption) { Text(option.text) .fontSize(17) .fontWeight(FontWeight.Bold) .fontColor(this.getOptionColor(option.key)) .textAlign(TextAlign.Center) .height(50) .layoutWeight(1) .backgroundColor(this.selectedAnswer option.key ? $r(app.color.panel_bg) : $r(app.color.button_bg)) .borderRadius(14) .border({ width: 1, color: this.selectedAnswer option.key ? $r(app.color.accent) : $r(app.color.border_subtle) }) .onClick(() { this.answerTheoryQuestion(option.key); }) }源码节选entry/src/main/ets/pages/Index.ets:1266private answerTheoryQuestion(answer: string): void { if (this.selectedAnswer.length 0 || this.activeQuestions.length 0) { return; } const question this.getCurrentQuestion(); const correctAnswer getQuestionAnswer(question); const correct answer correctAnswer; const correctText this.getOptionText(question, correctAnswer); const selectedText this.getOptionText(question, answer); this.selectedAnswer answer; this.answerCorrect correct; this.answerMessage correct ? 回答正确 : 回答错误正确选项${correctAnswer}. ${correctText}; this.addSimpleRecord(question.subject, this.activeMode, correct, correct ? 答对${question.title} : 答错${question.title}, correct ? : question.id, correct ? : correctText, correct ? : selectedText); }答题页的第一条规则是一题一次。selectedAnswer.length 0时直接返回保证历史记录反映首次判断。这不是限制用户学习而是保证错题本可信。想重答可以做“下一题”或“重新开始”不要让选项点击覆盖记录。颜色反馈由 selectedAnswer 驱动源码节选entry/src/main/ets/pages/Index.ets:1664private getOptionColor(key: string): ResourceColor { if (this.selectedAnswer.length 0) { return $r(app.color.text_primary); } if (key getQuestionAnswer(this.getCurrentQuestion())) { return $r(app.color.success); } if (key this.selectedAnswer) { return $r(app.color.danger); } return $r(app.color.text_secondary); }源码节选entry/src/main/ets/pages/Index.ets:1614private addSimpleRecord(subject: string, mode: string, passed: boolean, reason: string, wrongQuestionId: string, correctOption: string, selectedOption: string, score?: number, total?: number, durationSeconds?: number): void { const record: PracticeRecord { id: ${Date.now()}_${Math.floor(Math.random() * 1000)}, subject, mode, passed, score: score undefined ? (passed ? 1 : 0) : score, total: total undefined ? 1 : total, reason, wrongQuestionId, correctOption, selectedOption, createdAt: Date.now(), durationSeconds: durationSeconds undefined ? 1 : durationSeconds, mastered: false }; this.store.addRecord(record).then((records: PracticeRecord[]) { this.records records; });颜色反馈由selectedAnswer和正确答案共同决定。答题前所有选项正常显示答题后正确项和误选项分开高亮。这种反馈应该来自状态而不是直接给某个按钮改样式。否则切题后很容易留下旧颜色。错题记录同步保存正确项和误选项源码节选entry/src/main/ets/services/PracticeStore.ets:54async addRecord(record: PracticeRecord): PromisePracticeRecord[] { const records await this.listRecords(); records.unshift(record); const nextRecords records.slice(0, MAX_HISTORY_COUNT); await this.putString(HISTORY_KEY, JSON.stringify(nextRecords)); return nextRecords; }答错时记录会保存题目 id、正确选项文本和误选文本。历史页能显示“正确选项”和“误选”靠的就是这些字段。迁移时把“锁定、反馈、记录”视为一次事务。只做前两步没有错题本只做记录没有即时反馈。迁移到自己的 HarmonyOS 项目迁移顺序建议保持保守先抽模型再接入口然后接页面最后接本地记录。不要一上来就把所有 Builder、题库和存储混在一个文件里。当前主题答题记录可以按下面的最小切片实现1. 定义模型Subject、QuestionItem、PracticeRecord、action 常量。 2. 定义数据模块入口、题库、灯光命令或历史记录结构。 3. 定义状态当前页面、当前题、当前灯光、反馈文案和记录列表。 4. 定义 UI状态行、题面、按钮区、历史卡片或搜索结果。 5. 定义验证正确流、错误流、重置流和边界流都要能复现。这个流程稳定后选择题和判断题可以共用同一套判题方法只是选项展示形式不同。验证路线同一题再次点击不改结果误选时提示正确项错题记录包含正确项和误选项除了上面的业务核对还建议记录一个最小验证表主题答题记录 输入入口点击、按钮点击、题目选择或关键词输入 状态currentPage、lightState、timeLeft、selectedAnswer、records 输出页面提示、状态高亮、历史记录、搜索结果 边界返回首页、重置、重复点击、空记录、超时这里的验证是面向源码链路的核对不等同于真机兼容性、性能或上架流程。如果要证明设备行为还需要单独构建安装并操作页面。常见问题与处理方式现象常见原因处理方式页面能点但结果不对按钮 action 与题库 action 没有对齐先看模型常量再看题库命令和处理函数返回后状态残留计时器或闪烁器没有释放核对 stopTimer、stopAltFlash 和 reset 方法历史记录不完整写记录时只保存了展示文案补齐 subject、mode、correctOption、selectedOption答题问题先看selectedAnswer是否清零和锁定。重复点击能改结果基本就是锁定条件漏了。小结答题记录这条线把灯光模拟从“能点按钮”推进到“可练习、可判题、可复盘”。The_kemusan 的代码没有把所有能力做成复杂框架而是用清晰的模型、页面状态和本地记录完成闭环。写 CSDN 文章时把这条闭环讲清楚比堆更多 API 名词更有价值。](https://i-blog.csdnimg.cn/direct/77f654e5a79c421f96059f45f18e02d0.png#pic_center)
返回列表