vue2实现答题组件

需求

实现一个答题组件,点击正确的选项,该选项背景变绿色;点击错误的选项,该选项背景变红色。不管点击了什么选项,延迟一秒后切换下一题。

每次出题,从题库中选随机选择一道用户此次进入这个页面后还没有做过的题目,如果此次进入这个页面把所有题都做了,则重置,重新开始随机选题。

页面结构

html 复制代码
<div class="question">
  {{questions[selectedQuestionIndex].question}}
</div>
<div class="choices">
  <div
    class="choice"
    v-for="(item, index) in questions[selectedQuestionIndex].choices"
    :key="item.content"
    // 当点击了当前的选项,则开始处理背景颜色
    :style="{ background: selectedChoiceIndex === index ? feedbackColor : '' }" // 用来显示点击之后的背景颜色
    @click="handleChoice(index)"
    >
    <span>{{item.index}}</span>
    <span>{{item.content}}</span>
  </div>
</div>

数据结构

javascript 复制代码
data() {
  return {
    selectedQuestionIndex: 0, // 当前显示的问题的索引
    selectedChoiceIndex: null, // 记录用户当前选择的选项索引
    feedbackColor: '', // 记录选项的反馈颜色
    answeredQuestions: new Set(), // 已回答题目索引
    questions: [ // 题库
      // 1
      {
        question: '下列哪一项不是森林生态系统服务的一部分?',
        choices: [
          { index: 'A: ', content: '氧气生产' },
          { index: 'B: ', content: '水土保持' },
          { index: 'C: ', content: '提供化石燃料' },
          { index: 'D: ', content: '生物多样性维持' },
        ],
        correctChoiceIndex: 2
      },
      // 2
      {
        question: '碳汇是指什么?',
        choices: [
          { index: 'A: ', content: '大量排放二氧化碳的地方' },
          { index: 'B: ', content: '能够吸收并储存二氧化碳的自然系统' },
          { index: 'C: ', content: '一种工业过程,用于减少温室气体' },
          { index: 'D: ', content: '用于监测大气中二氧化碳水平的技术' },
        ],
        correctChoiceIndex: 1
      },
    ]
  };
},

方法解析

有三个方法:

  • handleChoice:根据用户的选择决定显示什么背景颜色;切换下一题
  • nextQuestion:决定下一题选哪一道;重置选择状态和选项背景颜色
  • resetQuiz:重新开始测试
javascript 复制代码
handleChoice(choiceIndex) {
  // 判断是否答对
  const currentQuestion = this.questions[this.selectedQuestionIndex]; // 获取当前问题
  // 判断用户点击的是否是正确选项,计算对应的背景颜色
  if (choiceIndex === currentQuestion.correctChoiceIndex) {
    this.feedbackColor = '#adce74'; // 绿色表示答对
  } else {
    this.feedbackColor = '#ea6458'; // 红色表示答错
  }

  // 设置选中选项索引
  // 一旦selectedChoiceIndex有值了,那么页面上就会渲染背景颜色
  this.selectedChoiceIndex = choiceIndex;

  // 延迟一段时间切换到下一题
  setTimeout(() => {
    this.nextQuestion();
  }, 1000); // 延迟1秒
},
javascript 复制代码
nextQuestion() {
  // 将当前题目加入已回答集合
  this.answeredQuestions.add(this.selectedQuestionIndex);

  // 筛选未回答的题目索引
  const unansweredIndexes = this.questions
    .map((_, index) => index) // 得到一个全是问题编号的数组
    .filter(index => !this.answeredQuestions.has(index)); // 过滤出不在answeredQuestions里面的问题的序号

  if (unansweredIndexes.length > 0) {
    // 随机选取一道未回答的题目
    const randomIndex = Math.floor(Math.random() * unansweredIndexes.length);
    this.selectedQuestionIndex = unansweredIndexes[randomIndex];
  } else {
    // 如果没有未回答的题目,重置已回答集合并重新开始
    this.answeredQuestions.clear();
    this.resetQuiz();
  }

  // 重置选中状态
  this.selectedChoiceIndex = null;
  this.feedbackColor = '';
},
javascript 复制代码
resetQuiz() {
  // 重新随机选择一个题目
  this.selectedQuestionIndex = Math.floor(Math.random() * this.questions.length);
}

组件代码

vue 复制代码
<template>
  <div class="question-container">
    <div class="question">
      {{questions[selectedQuestionIndex].question}}
    </div>
    <div class="choices">
      <div
        class="choice"
        v-for="(item, index) in questions[selectedQuestionIndex].choices"
        :key="item.content"
        :style="{ background: selectedChoiceIndex === index ? feedbackColor : '' }"
        @click="handleChoice(index)"
        >
        <span>{{item.index}}</span>
        <span>{{item.content}}</span>
      </div>
    </div>
  </div>
</template>

<script>
  import {mapMutations} from "vuex";

  export default {
    name: "questionDetail",
    data() {
      return {
        selectedQuestionIndex: 0,
        selectedChoiceIndex: null, // 记录用户当前选择的选项索引
        feedbackColor: '', // 记录选项的反馈颜色
        answeredQuestions: new Set(), // 已回答题目索引
        questions: [
          // 1
          {
            question: '下列哪一项不是森林生态系统服务的一部分?',
            choices: [
              { index: 'A: ', content: '氧气生产' },
              { index: 'B: ', content: '水土保持' },
              { index: 'C: ', content: '提供化石燃料' },
              { index: 'D: ', content: '生物多样性维持' },
            ],
            correctChoiceIndex: 2
          },
          // 2
          {
            question: '碳汇是指什么?',
            choices: [
              { index: 'A: ', content: '大量排放二氧化碳的地方' },
              { index: 'B: ', content: '能够吸收并储存二氧化碳的自然系统' },
              { index: 'C: ', content: '一种工业过程,用于减少温室气体' },
              { index: 'D: ', content: '用于监测大气中二氧化碳水平的技术' },
            ],
            correctChoiceIndex: 1
          },
        ]
      };
    },
    methods: {
      ...mapMutations(['addQuestion']),
      handleChoice(choiceIndex) {
        // 判断是否答对
        const currentQuestion = this.questions[this.selectedQuestionIndex];
        if (choiceIndex === currentQuestion.correctChoiceIndex) {
          this.feedbackColor = '#adce74'; // 绿色表示答对
          this.addQuestion();
        } else {
          this.feedbackColor = '#ea6458'; // 红色表示答错
        }

        // 设置选中选项索引
        this.selectedChoiceIndex = choiceIndex;

        // 延迟一段时间切换到下一题
        setTimeout(() => {
          this.nextQuestion();
        }, 1000); // 延迟1秒
      },
      nextQuestion() {
        // 将当前题目加入已回答集合
        this.answeredQuestions.add(this.selectedQuestionIndex);

        // 筛选未回答的题目索引
        const unansweredIndexes = this.questions
          .map((_, index) => index)
          .filter(index => !this.answeredQuestions.has(index));

        if (unansweredIndexes.length > 0) {
          // 随机选取一道未回答的题目
          const randomIndex = Math.floor(Math.random() * unansweredIndexes.length);
          this.selectedQuestionIndex = unansweredIndexes[randomIndex];
        } else {
          // 如果没有未回答的题目,重置已回答集合并重新开始
          this.answeredQuestions.clear();
          this.resetQuiz();
        }

        // 重置选中状态
        this.selectedChoiceIndex = null;
        this.feedbackColor = '';
      },
      resetQuiz() {
        // 重新随机选择一个题目
        this.selectedQuestionIndex = Math.floor(Math.random() * this.questions.length);
      }
    }
  };
</script>

<style scoped lang="scss">
.question-container {
  width: 98%;
  height: calc(100vh - 210px);
  margin-top: 15px;
  padding: 0 15px 0 15px;
  //border: 1px red solid;
  overflow: auto;
  .question {
    font-family: 'SanJinSong-Cu', serif;
    color: #7c9a92;
    font-size: 35px;
  }
  .choices {
    margin-top: 30px;
    display: flex;
    flex-direction: column;
    gap: 15px;
    .choice {
      box-sizing: border-box;
      padding: 10px 20px;
      color: white;
      font-family: 'SanJinSong-Xi', serif;
      font-size: 25px;
      width: 100%;
      min-height: 80px;
      display: flex;
      align-items: center;
      border-radius: 8px;
      background: linear-gradient(to right, #1F6D5E, #43D6B9);
      cursor: pointer;
      transition: background 0.3s ease;
    }
  }
}
</style>

效果演示

相关推荐
NoneCoder11 分钟前
CSS系列(18)-- 工程化实践详解
前端·css
·云扬·24 分钟前
Java 垃圾回收机制详解
java·开发语言·jvm·笔记·学习
huipeng92633 分钟前
第十章 类和对象(二)
java·开发语言·学习·1024程序员节
dubochao_xinxi38 分钟前
在 Termux 中安装 Docker
开发语言·数据库·python·qt
一枚生瓜子1 小时前
黑皮书-计算机科学导论02
开发语言
請你喝杯Java1 小时前
Mac软件清单(前后端开发环境搭建)
前端·后端·macos·软件
稀土君1 小时前
角逐20万奖金!这里有一份完整的豆包MarsCode AI编程挑战赛参赛指南!
前端·人工智能·豆包marscode
dubochao_xinxi1 小时前
E: 仓库目录 /var/cache/apt/archives/partial 确实。 - Acquire (2: 没有那个文件或目录)
开发语言·数据库·python·qt
咖猫1 小时前
Guava库中的`ImmutableCollections`进行集合操作的示例
java·开发语言·guava
液态不合群1 小时前
使用Python实现两组数据纵向排序
开发语言·python·算法