全唐诗接龙挑战应用:20 题题库 + 随机闯关 + 四选一答题计分 - 鸿蒙实战


一、设计思路
背诵应用的短板是缺少反馈——背没背会,自己说了不算。本应用(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 橙色系 |
与背诵页琥珀色呼应 |
这个"出上句猜下句"的测验框架同样适用于英语单词中英互译、政治知识点问答——题库结构 + 四选一判分 + 结果结算,三件套全通用。
更多推荐


所有评论(0)