鸿蒙掌上驾考宝典应用开发15:答题交互组件——Exam 与 SelectComponent 全解析
·
第15篇:答题交互组件——Exam 与 SelectComponent 全解析
一、引言
答题交互是驾考应用最核心的用户交互场景。DriverLicenseExam 项目的 Exam 组件和 SelectComponent 组件共同实现了完整的答题交互体验,包括试题展示、选项选择、答案判断、答题卡、倒计时等。本文将深入解析这两个组件的实现。
二、Exam 组件架构
2.1 组件职责
Exam 组件是考试页面的核心容器,负责:
- 管理试题列表(Swiper 滑动切换)
- 展示倒计时(模拟考试)
- 管理答题卡浮层
- 处理模拟考试结束弹窗
2.2 组件接口
// components/exam/src/main/ets/components/Exam.ets
@Entry
@ComponentV2
export struct Exam {
@Param @Require appPathStack: NavPathStack; // 路由栈
@Param @Require examManager: ExamManager; // 试卷数据
@Param mockExamCall: (score: number) => void = (score: number) => {}; // 模拟考试回调
private examController: ExamController = ExamController.instance;
@Local remainTime: number = 0; // 剩余时间
@Local isShowProblemListSheet: boolean = false; // 答题卡显示
@Local currentIndex: number = 0; // 当前第几题
@Local isStop: boolean = false; // 暂停状态
private readonly renderWindowSize: number = 2; // 渲染窗口大小
}
三、答题交互流程
3.1 试题渲染
build() {
Column() {
// 模拟考试倒计时
this.showRemainTime();
// 试题列表(Swiper 滑动切换)
Swiper(examController.swiperController) {
ForEach(this.examManager.examDetails, (item: ExamDetail, examIndex: number) => {
Column({ space: 12 }) {
if (this.shouldRenderQuestion(examIndex)) {
SelectComponent({
item: item,
changeCorrectNum: (isAdd: boolean) => {
isAdd ? this.examManager.correctNumber++ : this.examManager.correctNumber--;
},
});
}
}
});
}
// ... 底部导航(答题卡、上一题、下一题)
}
}
3.2 渲染窗口优化
// 只渲染当前题附近的题目,提高大题库性能
private readonly renderWindowSize: number = 2;
shouldRenderQuestion(examIndex: number): boolean {
return Math.abs(examIndex - this.currentIndex) <= this.renderWindowSize;
}
四、模拟考试倒计时
4.1 倒计时实现
aboutToAppear(): void {
this.currentIndex = this.examManager.currentQuestionId + 1;
if (this.examManager.timeLimit !== 0) {
this.remainTime = this.examManager.timeLimit * 60;
let showDialog: boolean = true;
setInterval(() => {
if (showDialog && !this.isStop) {
if (this.remainTime >= 1) {
this.remainTime--;
} else {
showDialog = false;
this.isStop = true;
this.examSubmitDialog.open();
}
}
}, 1000);
}
}
4.2 时间格式化
@Builder
showRemainTime() {
if (this.examManager.timeLimit !== 0) {
Row() {
Image($r('app.media.ic_time')).width(16).height(16);
Text(`${Math.floor(this.remainTime / 60)}:${String(this.remainTime % 60).padStart(2, '0')}`)
.fontSize(14)
.fontColor('#FF6B6B');
}
}
}
五、答题卡实现
5.1 答题卡数据
// 生成答题卡数据
get answerCardData() {
return this.examManager.examDetails.map((item, index) => ({
index: index + 1,
status: item.isCorrect === undefined ? 'unanswered' :
item.isCorrect ? 'correct' : 'wrong',
isCurrent: index === this.currentIndex
}));
}
5.2 答题卡交互
// 底部打开答题卡浮层
Button('答题卡')
.onClick(() => {
this.isShowProblemListSheet = true;
})
.bindSheet($$this.isShowProblemListSheet, this.answerCardSheet(), {
height: 400,
title: { title: '答题卡' },
});
六、总结
Exam 和 SelectComponent 组件的设计体现了 ArkUI 组件化的最佳实践:
- 职责分离:Exam 管理流程,SelectComponent 管理交互
- 性能优化:渲染窗口机制减少不必要的渲染
- 状态管理:@Local 管理内部状态,@Param 接收外部数据
- 用户体验:倒计时、答题卡、弹窗等交互细节
关键源码文件:
components/exam/src/main/ets/components/Exam.ets— 考试主组件components/exam/src/main/ets/components/SelectComponent.ets— 选择组件components/exam/src/main/ets/controller/ExamController.ets— 考试控制器
更多推荐




所有评论(0)