首页 > 解决方案 > Vue 调查没有索引问题

问题描述

我必须在 vue.js 中构建一个测验/调查应用程序,我对 vue 还是很陌生,并且仍在尝试学习它。我有一个测验/调查,根据用户在初始问题中的回答提出不同的问题。

因此,如果用户选择是,它将显示问题 2,如果用户选择否,它将显示问题 3,依此类推。

我不确定最好的解决方法是什么,但到目前为止我有这个。

无论如何我可以在一个人点击下一步后将我的答案的值用作 questionIndex 吗?

JS文件:

"use strict";

let quiz = {
  title: "Asbestos Quiz",
  questions: [
    {
      text: 'Do you need help with an Asbestos Survey?',
      answers: [
        {
          text: "Yes",
          value: '2'`enter code here`
        },
        {
          text: "No",
          value: '3'
        },       
      ]
    },
    {
      text: 'Was your property constructed pre 2000',
      answers: [
        {
          text: "Yes",
          value: '4'
        },
        {
          text: "No",
          value: '5'
        },
      ]
    },
    {
      text: 'Do you need an Asbestos Management plan?',
      answers: [
        {
          text: "Yes",
          value: '6'
        },
        {
          text: "No",
          value: '7'
        },
      ]
    }
  ]
};

var app = new Vue({
  el: "#app",
  data: {
    quiz: quiz,
    questionIndex: 0,
    responses: [],
    errors: [],
    error: ''
  },
  
  methods: {
    prev: function() {
      this.questionIndex--;
    },
    
    next: function() {
      if (this.responses[this.questionIndex] === undefined) {
        this.errors[this.questionIndex] = 1;
        this.error = 'Please select your answer';
      } 
      else {
        this.errors[this.questionIndex] = 0;
        this.questionIndex++;
      } 
    },
    score: function() {
      
    },
    
    playAgain: function() {
      this.questionIndex = 0;
    }
  }
});


HTML:

<html lang="en">
  <head>
    <title>Vue quiz/survey</title>
    <meta name="viewport" content="width=device-width"/>
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <!-- <link rel="stylesheet" href="index.css"> -->
  </head>
  <body>
          <div id="app">
    <div class="container">
      <div class="jumbotron mt-3">
        <h1 class="mb-5">{{ quiz.title }}</h1>
        <hr>
         <p v-if="errors[questionIndex]" class="alert alert-danger">
            {{ error }}
          </p>
        <div v-for="(question, index) in quiz.questions">
          <div v-show="index === questionIndex">
           
            <h4 class="mt-5 mb-3">{{ question.text }}</h4> 
            
            <div v-for="answer in question.answers" class="form-check">
              <label class="form-check-label">
                <input class="form-check-input" type="radio"
                     :value="answer.value"
                     :name="index"
                     v-model="responses[index]">
                {{answer.text}}
              </label>
            </div>
            
            <div class="mt-5">
              <button 
                 class="btn btn-primary" 
                 v-if="questionIndex > 0" 
                 @click="prev">
                  prev
              </button>
              <button class="btn btn-secondary" @click="next">
                  next
              </button>  
            </div>
          </div>
        </div>
        
        <div v-show="questionIndex === quiz.questions.length">
          <h3>Your Results</h3>
          <p>
            You are: {{ score() }}
          </p>
          
          <button class="btn btn-success" @click="playAgain">
            Play Again!
          </button>
        </div>
      </div>
    </div>
  </div>
        <script type="text/javascript" src="index.js"></script>
    </body>
</html>

标签: javascriptvue.js

解决方案


我认为这听起来像是一个可能很有趣的练习,所以我花了一些时间在一个 Vue CLI 沙盒应用程序中创建一个实现,我构建并使用它来尝试各种想法。

我学到了一些东西,希望你能从中有所收获。如果您决定喜欢它并希望自己实现它,我会将“以前的”功能作为 TODO 保留。

测验问题.vue

<template>
  <div class="quiz-questions">
    <div class="jumbotron mt-3">
      <h1 class="mb-5">{{ quiz.title }}</h1>
      <hr>

      <question v-if="!showResults" :question="currentQuestion" @answer-selected="processAnswer" />

      <div class="mt-5">
        <button class="btn btn-primary" v-if="currentQuestionId > 1 && !showResults" @click="getPreviousQuestion">
          prev
        </button>
        <button v-if="!showResults" class="btn btn-secondary" @click="getNextQuestion">
          {{ nextButtonLabel }}
        </button>
      </div>

      <div v-if="showResults">
        <h3>Your Results</h3>
        <table class="table table-bordered">
          <thead>
            <tr>
              <th>QUESTION</th>
              <th>ANSWER</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="(response, index) in responses" :key="index">
              <td>{{ getQuestionText(response.questionId) }}</td>
              <td>{{ getAnswerText(response.answerId) }}</td>
            </tr>
          </tbody>
        </table>

        <button class="btn btn-success" @click="playAgain">
          Play Again!
        </button>
      </div>
    </div>

  </div>
</template>

<script>
  import quiz from './quiz.js';
  import Question from '@/components/stackoverflow/Question'

  export default {
    components: {
      Question
    },
    data() {
      return {
        quiz: quiz,
        currentQuestionId: 1,
        currentAnswerId: 1,
        previousQuestionId: 0,
        responses: [],
        showResults: false,
        errors: [],
        error: ''
      }
    },
    computed: {
      currentQuestion() {
        return this.quiz.questions.find( question => {
          return question.id === this.currentQuestionId;
        })
      },
      nextQuestionId() {
        let retVal = 0;
        if (this.currentAnswerId > 0) {
          let tempAnswer = this.currentQuestion.answers.find( answer => {
            return answer.id === this.currentAnswerId;
          });
          retVal = tempAnswer.nextQuestionId;
        }
      
        return retVal;
      },
      lastQuestion() {
        return this.currentQuestion.answers[0].nextQuestionId === 0;
      },
      nextButtonLabel() {
        return this.lastQuestion ? 'Finish' : 'Next';
      }
    },
    methods: {
      getPreviousQuestion() {
        this.currentQuestionId = this.previousQuestionId;
      },
      getNextQuestion() {
        // TODO: Look for existing response for this question in case the 'Previous' button was pressed
        // If found, update answer
        
        // Store current question id and answer id in responses
        let response = { questionId: this.currentQuestionId, answerId: this.currentAnswerId };
        this.responses.push(response);

        if (this.lastQuestion) {
          this.showResults = true;
          return;
        }

        this.previousQuestionId = this.currentQuestionId;
        this.currentQuestionId = this.nextQuestionId;
        //console.log(this.responses);
      },
      getQuestionText(id) {
          let result = this.quiz.questions.find( question => {
              return question.id === id;
          });
          return result.text;
      },
      getAnswerText(id) {
          // NOTE: Since answers are currently limited to '1 = Yes' and '2 = No',
          // this method does not need to involve any look up
          return id === 1 ? 'Yes' : 'No';
      },
      processAnswer(selectedAnswerId) {
        this.currentAnswerId = selectedAnswerId;
      },
      score() {
        return 'TODO'
      },
      playAgain() {
        this.currentQuestionId = 1;
        this.showResults = false;
        this.responses = [];
      }
    }
  }
</script>

问题.vue

<template>
  <div class="question">
    <h4 class="mt-5 mb-3">{{ question.text }}</h4>

    <div class="form-check" v-for="(answer, idx) in question.answers" :key="idx">
      <input class="form-check-input" type="radio"
        :value="answer.id" v-model="answerId" @change="answerSelected">
      <label class="form-check-label">
        {{answer.text}}
      </label>
    </div>

  </div>
</template>

<script>
  export default {
    props: {
      question: {
        type: Object,
        required: true
      }
    },
    data() {
      return {
        answerId: 1
      }
    },
    watch:{
      question() {
        // Reset on new question
        this.answerId = 1;
      }
    },
    methods: {
      answerSelected() {
        this.$emit('answer-selected', this.answerId);
      }

    }
  }
</script>

我还通过添加各种 ID 属性来帮助跟踪来修改您的测试数据,并创建了更多的占位符问题。

测验.js

const quiz = {
  title: "Asbestos Quiz",
  questions: [
    {
      id: 1,
      text: 'Do you need help with an Asbestos Survey?',
      answers: [
        {
          id: 1,
          text: "Yes",
          nextQuestionId: 2
        },
        {
          id: 2,
          text: "No",
          nextQuestionId: 3
        },
      ]
    },
    {
      id: 2,
      text: 'Was your property constructed pre 2000',
      answers: [
        {
          id: 1,
          text: "Yes",
          nextQuestionId: 4
        },
        {
          id: 2,
          text: "No",
          nextQuestionId: 5
        },
      ]
    },
    {
      id: 3,
      text: 'Do you need an Asbestos Management plan?',
      answers: [
        {
          id: 1,
          text: "Yes",
          nextQuestionId: 6
        },
        {
          id: 2,
          text: "No",
          nextQuestionId: 7
        },
      ]
    },
    {
      id: 4,
      text: 'Question 4',
      answers: [
        {
          id: 1,
          text: "Yes",
          nextQuestionId: 0
        },
        {
          id: 2,
          text: "No",
          nextQuestionId: 0
        },
      ]
    },
    {
      id: 5,
      text: 'Question 5',
      answers: [
        {
          id: 1,
          text: "Yes",
          nextQuestionId: 0
        },
        {
          id: 2,
          text: "No",
          nextQuestionId: 0
        },
      ]
    },
    {
      id: 6,
      text: 'Question 6',
      answers: [
        {
          id: 1,
          text: "Yes",
          nextQuestionId: 0
        },
        {
          id: 2,
          text: "No",
          nextQuestionId: 0
        },
      ]
    },
    {
      id: 7,
      text: 'Question 7',
      answers: [
        {
          id: 1,
          text: "Yes",
          nextQuestionId: 0
        },
        {
          id: 2,
          text: "No",
          nextQuestionId: 0
        },
      ]
    }
  ]
};

export default quiz;

推荐阅读