You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue2中v-on绑定nextBtn函数报错及问答切换方案咨询

解决Vue2答题组件Next按钮报错及功能实现

错误原因分析

  • nextBtn、answers等DOM元素变量仅在mounted或局部方法中定义,nextBtn方法中直接引用导致ReferenceError
  • 过度操作DOM,违背Vue数据驱动的核心思想,应该通过状态变量控制UI变化
  • backBtn方法中错误使用this.question,实际应操作this.currentQuestion
  • calculateResult使用箭头函数导致this指向错误,无法访问组件实例

修改后的完整代码

HTML

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app1">
  <display-question></display-question>
</div>

JS

Vue.component('display-question', {
  data: function() {
    return {
      currentQuestion: 0,
      answered: 0,
      showWrongQuestion: false,
      wrongQuestions: [],
      wrongAnswers: 0,
      correctAnswers: 0,
      message: "Enter your answer here",
      WhatAnswer: "default",
      // 新增状态控制按钮禁用和选中样式
      isNextDisabled: true,
      selectedAnswerIndex: null,
      showResult: false,
      questions: [
        {
          question: 'What is the capital of Ukrain ?',
          answer: ['Kyiv', 'Kabul', 'Buenos Aires', 'Praia'],
          correct_answer: 0,
          selected: null,
          sense: 0
        },
        {
          question: 'When was Queen Elizabeth II death ?',
          answer: ['11/09/2022', '08/09/2022', '12/08/2022', '07/09/2022'],
          correct_answer: 1,
          selected: null,
          sense: 0
        },
        {
          question: 'How many bones are there in human body?',
          answer: ['206', '186', '209', '190'],
          correct_answer: 0,
          selected: null,
          sense: 0
        },
        {
          question: 'Who were the 30th president of ?',
          answer: ['Julia Eileen Gillard', 'John Winston Howard ', 'Scott John Morrison ', 'Anthony Albanese'],
          correct_answer: 2,
          selected: null,
          sense: 0
        },
        {
          question: 'What is the biggest continent?',
          answer: ['Oceania', 'Europe', 'Asia', 'Africa'],
          correct_answer: 2,
          selected: null,
          sense: 0
        }
      ]
    }
  },

  methods: {
    backBtn: function() {
      // 修正变量名错误
      if (this.currentQuestion > 0) {
        this.currentQuestion--;
        // 返回上一题时同步选中状态
        this.selectedAnswerIndex = this.questions[this.currentQuestion].selected;
        this.isNextDisabled = this.selectedAnswerIndex === null;
      }
    },
    nextBtn: function() {
      this.answered < this.questions.length ? this.answered++ : '';

      if (this.currentQuestion < this.questions.length - 1) {
        // 保存当前题的选中答案
        this.questions[this.currentQuestion].selected = this.selectedAnswerIndex;
        // 切换到下一题
        this.currentQuestion++;
        // 重置下一题的选中状态和按钮禁用
        this.selectedAnswerIndex = this.questions[this.currentQuestion].selected;
        this.isNextDisabled = this.selectedAnswerIndex === null;
      } else {
        // 计算最终结果
        this.questions.forEach(question => {
          if (question.sense === 0) {
            if (question.selected == question.correct_answer) {
              this.correctAnswers++;
            } else {
              this.wrongAnswers++;
              this.wrongQuestions.push({
                answers: question.answer,
                question: question.question,
                correct_answer: question.correct_answer,
                selected: question.selected
              });
            }
            question.sense = 1;
          }
        });
        // 显示结果面板
        this.showResult = true;
      }
    },
    calculateResult: function() {
      return (this.correctAnswers / this.questions.length) * 100;
    },
    selectAnswer: function(index) {
      // 通过状态控制选中,不再操作DOM
      this.selectedAnswerIndex = index;
      this.isNextDisabled = false;
    }
  },

  template: `
    <div>
      <div v-if="!showResult">
        <h2>{{ questions[currentQuestion].question }}</h2>
        <br>
        <!-- 通过状态绑定class控制选中样式 -->
        <span 
          class="answer" 
          v-for="(answer, index) in questions[currentQuestion].answer" 
          :key="index" 
          @click="selectAnswer(index)"
          :class="{ selected: selectedAnswerIndex === index }"
        >
          {{ answer }}
        </span>
        <p>
          <button class="backBtn" @click="backBtn" :disabled="currentQuestion === 0">BACK</button>
          <!-- 通过状态控制按钮禁用 -->
          <button class="next-btn" @click="nextBtn" :disabled="isNextDisabled">
            {{ currentQuestion < (questions.length -1) ? "Next" : "Result!" }}
          </button>
        </p>
      </div>
      <div v-if="showResult" class="result">
        <div class="success">
          <h3>答题结果</h3>
          <p>正确答案:{{ correctAnswers }}/{{ questions.length }}</p>
          <p>正确率:{{ calculateResult().toFixed(2) }}%</p>
          <h4>错题列表</h4>
          <div v-for="(item, index) in wrongQuestions" :key="index">
            <p>{{ item.question }}</p>
            <p>你的答案:{{ item.answers[item.selected] }}</p>
            <p>正确答案:{{ item.answers[item.correct_answer] }}</p>
          </div>
        </div>
      </div>
    </div>
  `,
})

var test1 = new Vue({
  el: "#app1",
  data: {},
});

关键修改说明

  1. 移除DOM操作:新增isNextDisabled、selectedAnswerIndex、showResult状态变量,通过Vue的响应式绑定控制按钮禁用、答案选中样式、结果面板显示
  2. 修复变量作用域问题:不再直接引用DOM元素变量,所有逻辑通过组件状态实现
  3. 修正方法错误:backBtn方法修正为操作this.currentQuestion,calculateResult改用普通函数保证this指向组件实例
  4. 完善状态同步:切换题目时同步保存当前题的选中状态,返回上一题时恢复选中状态
  5. 增强用户体验:Back按钮在第一题时禁用,结果面板显示正确率和错题详情

内容的提问来源于stack exchange,提问作者James Pumkin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 15:55:20