在这里插入图片描述
在这里插入图片描述

一、设计思路

背诵应用的短板是缺少反馈——背没背会,自己说了不算。本应用(TangPoetryChallenge_29)把古诗背诵做成游戏化测验:出上句猜下句,从 20 道题的题库中随机抽取 10 题,四选一作答、即时判分、逐题给出全诗出处,答完展示成绩单并可跳转背诵页复习错题。用"测验"反哺"背诵",形成学习闭环。

游戏化设计的三个关键决策:随机抽题(每次闯关题目不同,可反复玩)、答案即时反馈(答对/答错立刻高亮标出)、结束总分结算(用成绩激励反复挑战)。

二、数据结构:上下句 + 全诗 + 干扰项

字段 类型 说明
upper string 上句(题干)
lower string 下句(正确答案)
title / poet string 出处:诗题 / 作者
full string[] 全诗,答后展示
distract string[] 3 个干扰选项
interface QuizItem {
  id: number;
  upper: string;      // 上句
  lower: string;      // 下句(正确答案)
  title: string;      // 诗题
  poet: string;       // 作者
  full: string[];     // 全诗
  distract: string[]; // 干扰选项
}

干扰项设计是题库质量的关键:每个干扰项必须来自其他真实诗句(如"处处闻啼鸟"来自《春晓》),不能是乱编的词——这样既有迷惑性,又能顺带复习其他诗。

三、随机抽题:洗牌 + 截取

startQuiz(): void {
  const shuffled: QuizItem[] = this.pool.slice().sort(() => Math.random() - 0.5);
  this.quizItems = shuffled.slice(0, 10);   // 抽 10 题
  this.quizIndex = 0;
  this.score = 0;
  this.answered = false;
  this.quizDone = false;
  this.selected = '';
}

pool.slice() 先拷贝副本再洗牌,避免修改原始题库;sort(() => Math.random() - 0.5) 是经典的洗牌技巧,简单可靠。

四、固定选项缓存:一个容易踩的坑

初始实现里,选项通过 getOptions() 每次渲染时重新随机排序——这会导致一个 Bug:答完题后界面刷新,四个选项重新洗牌,用户看到的选项位置全变了,选错的体验非常糟糕。

修复方案:进入闯关时一次性把每题选项顺序算好存进 optionsCache,渲染时只读缓存,顺序全程固定:

@State optionsCache: string[][] = [];  // 每题固定选项顺序

this.optionsCache = this.quizItems.map((item: QuizItem) => {
  const opts: string[] = [item.lower, item.distract[0], item.distract[1], item.distract[2]];
  return opts.sort(() => Math.random() - 0.5);
});

getOptions(): string[] {
  return this.optionsCache[this.quizIndex] || [];
}

经验教训:ArkTS 中 @State 驱动的方法若含随机逻辑,必须在数据初始化阶段固化结果,不能放在渲染路径里。

五、答题判分:选择即锁定

pickOption(opt: string): void {
  if (this.answered) { return; }        // 已作答则锁定
  this.answered = true;
  this.selected = opt;
  if (opt === this.quizItems[this.quizIndex].lower) {
    this.score++;
  }
}

answered 状态同时承担两个职责:锁住选项(防重复点击)触发反馈区渲染。答对/答错的视觉区分由两个函数完成:

getOptionColor(opt: string): string {
  if (!this.answered) { return '#FFFFFF'; }
  return this.isCorrectOpt(opt) ? '#FEF3C7' : '#F5F5F4';  // 正确答案琥珀底
}

getOptionTextColor(opt: string): string {
  if (!this.answered) { return '#292524'; }
  return this.isCorrectOpt(opt) ? '#92400E' : '#A8A29E';  // 正确答案深棕字
}

反馈文案也由 selected 与正确答案比较得出,而不是错误地依赖累计得分:

Text(this.selected === this.quizItems[this.quizIndex].lower
  ? '✅ 答对了!'
  : '❌ 正确答案是「' + this.quizItems[this.quizIndex].lower + '」')

六、答后展示:全诗 + 出处 + 下一题

答完一题立即展示完整诗句,让测验同时承担复习功能:

反馈要素 内容
对错文案 ✅ 答对了 / ❌ 正确答案是「…」
全诗 full 数组逐句展示
出处 《诗题》作者
下一题 进度 “3 / 10” + 下一步按钮
nextQuiz(): void {
  if (this.quizIndex < this.quizItems.length - 1) {
    this.quizIndex++;
    this.answered = false;
    this.selected = '';
  } else {
    this.quizDone = true;      // 全部答完,进入成绩页
  }
}

七、成绩页与跳转复习

10 题全部答完后展示总分与评语,并提供一个「去背诵页复习」按钮——把测验失败的学习者导回 28 号背诵应用,完成闭环:

Text('得分:' + this.score + ' / ' + this.quizItems.length)
Text(this.score >= 8 ? '🏆 诗词达人!' : this.score >= 6 ? '👍 继续加油!' : '📖 建议先去背诵页复习')
Button('📖 去背诵页复习')
  .onClick(() => { router.pushUrl({ url: 'pages/TangPoetryRecite_28' }); })

八、技术要点总结

技术点 实现方式 坑点警示
随机抽题 拷贝 + 洗牌 + slice(0, 10) 勿直接操作原数组
选项固定 optionsCache 初始化时预生成 随机逻辑禁止放渲染路径
答题锁定 answered 状态双重职责 防重复点击
视觉反馈 正确/错误双色函数 判据是选项本身非得分
成绩结算 quizDone + 得分评语 与背诵页联动闭环
主题配色 #C2410C 橙色系 与背诵页琥珀色呼应

这个"出上句猜下句"的测验框架同样适用于英语单词中英互译、政治知识点问答——题库结构 + 四选一判分 + 结果结算,三件套全通用

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐