【问题标题】:javascript quiz how to give the answer array a default value?javascript quiz 如何给答案数组一个默认值?
【发布时间】:2022-01-14 15:57:29
【问题描述】:

我正在创建一个需要回答每个答案的测验。问题是如果您没有答案,您应该能够跳过问题。每次按下一步时,我都会尝试设置默认答案,因此当我尝试跳过一个时,我不必回答它即可获得价值。我想要的默认值是每次我数组的最后一个值。

下一个和上一个问题

        SetQuestion(question) {

            if (this.questionNumber >= 0) {
                let oldAnswerButton = document.querySelectorAll('.filter_anwser');

                // Deletes old question when the next question is clicked
                for (let answerButton of oldAnswerButton) {
                    answerButton.style.display = 'none';
                }
            }

            this.questionNumber = question;

            let q = this.quiz[question];
            // Check if your at the last question so the next button will stop being displayed.
            if (this.questionNumber === Quiz.length - 1) {
                this.nextbtn.style.display = 'none';
                this.prevbtn.style.display = 'block';
                this.resultbtn.style.display = 'grid';
            } else if (this.questionNumber === 0) {
                this.nextbtn.style.display = 'block';
                this.prevbtn.style.display = 'none';
                this.resultbtn.style.display = 'none';
            } else {
                this.nextbtn.style.display = 'block';
                this.prevbtn.style.display = 'block';
                this.resultbtn.style.display = 'none';
            }

            // Displays Question
            this.questionName.textContent = q.questionText;
            this.questionName.id = "questionID";

            return q;
            console.log(this.getLink())
            console.log(this.tmp)

        }

        IntoArray() {
            const UrlVar = new URLSearchParams(this.getLink())
            this.UrlArray = [...UrlVar.entries()].map(([key, values]) => (
                    {[key]: values.split(",")}
                )
            );
        }

        NextQuestion() {
            // let quizUrl = this.url[this.questionNumber];
            let question = this.SetQuestion(this.questionNumber + 1);
            let pre = question.prefix;
            let prefixEqual = pre.replace('=', '');
            let UrlArr = this.UrlArray;
            let UrlKeys = UrlArr.flatMap(Object.keys)
            let answers = question.chosenAnswer.slice(0, -1);

            this.clicked = true;

            // Displays answers of the questions
            for (let y = 0; y < answers.length; y++) {
                let item = answers[y];

                // Display answer buttons
                if (UrlKeys.includes(prefixEqual)) { 
                    console.log("exists");
                    let btn = document.querySelector('button[value="' + item.id + '"]');
                    btn.style.display = 'block';
                } else {
                    let btn = document.createElement('button');
                    btn.value = item.id;
                    btn.classList.add("filter_anwser", pre)
                    btn.id = 'answerbtn';
                    btn.textContent = item.name;
                    this.button.appendChild(btn);
                }

                // let quizUrl = control.url[control.questionNumber];
                // // console.log(this.tmp);
                // if (quizUrl === undefined) {
                //     quizUrl.push(question.prefix[y] + '');
                // }

                // if (quizUrl === undefined){
                //     this.tmp.push('');
                // }
            }


            this.IntoArray();
        }

        PrevQuestion() {
            let question = this.SetQuestion(this.questionNumber - 1);
            let answers = question.chosenAnswer.slice(0, -1);

            // Displays answers of the questions
            for (let y = 0; y < answers.length; y++) {
                let item = answers[y];

                // Display answer buttons
                let btn = document.querySelector('button[value="' + item.id + '"]');
                btn.style.display = 'block';
            }
            this.IntoArray();
        }

链接创建者:

        /**
         * Returns the parameters for the URL.
         *
         * @returns {string}
         */
        getLink() {
            this.tmp = [];
            for (let i = 0; i < this.url.length; i++) {
                // Check if question is from the same quiz part and adds a , between chosen answers and add the right prefix at the beginning
                if (this.url[i].length > 0) {
                    this.tmp.push("" + Quiz[i].prefix + this.url[i].join(","))
                    // console.log(this.url)
                }
                if (this.url[i].length === 0) {
                    this.tmp.push("");
                }
            }
            /// If answers are from different quiz parts add a & between answers.
            return "" + this.tmp.join("&");
            // console.log(this.url[i].prefix);
        };

应答点击事件

    control.button.addEventListener("click", function (e) {
        const tgt = e.target;
        control.clicked = true;

        // clear the url array if there's nothing clicked
        if (control.url.length === control.questionNumber) {
            control.url.push([]);
        }

        let quizUrl = control.url[control.questionNumber];

        // Check if a button is clicked. Changes color and adds value to the url array.
        if (quizUrl.indexOf(tgt.value) === -1) {
            quizUrl.push(tgt.value);
            e.target.style.backgroundColor = "orange";
            // Check if a button is clicked again. If clicked again changes color back and deletes value in the url array.
        } else {
            quizUrl.splice(quizUrl.indexOf(tgt.value), 1);
            e.target.style.backgroundColor = "white";
        }

        console.log(control.getLink());
        console.log(quizUrl)

    })

数组:

    class QuizPart {
        constructor(questionText, chosenAnswer, prefix, questionDescription) {
            this.questionText = questionText;
            this.chosenAnswer = chosenAnswer;
            this.prefix = prefix;
            this.questionDescription = questionDescription;
        }
    }

    class ChosenAnswer {
        constructor(id, name) {
            this.id = id;
            this.name = name;
        }
    }

    let Quiz = [
        new QuizPart('Whats your size?', [
                new ChosenAnswer('6595', '41'),
                new ChosenAnswer('6598', '42'),
                new ChosenAnswer('6601', '43'),
                new ChosenAnswer('', ''),
            ], 'bd_shoe_size_ids=',
            'The size of your shoes is very important. If you have the wrong size, they wont fit.'),

        new QuizPart('What color would you like?', [
                new ChosenAnswer('6053', 'Red'),
                new ChosenAnswer('6044', 'Blue'),
                new ChosenAnswer('6056', 'Yellow'),
                new ChosenAnswer('6048', 'Green'),
                new ChosenAnswer('', ''),
            ], 'color_ids=',
            'Color isn t that important, It looks good tho.'),

        new QuizPart('What brand would you like?', [
                new ChosenAnswer('5805', 'Adidas'),
                new ChosenAnswer('5866', 'Nike'),
                new ChosenAnswer('5875', 'Puma'),
                new ChosenAnswer('', ''),
            ], 'manufacturer_ids=',
            'Brand is less important. Its just your own preference'),
    ]

我尝试为数组的链接创建者和我的事件侦听器提供一个默认值,并在我从我的一个按钮获得实际值时替换它,但它只是不起作用。有人可以帮帮我吗?

【问题讨论】:

    标签: javascript arrays function


    【解决方案1】:

    我知道,这可能与您对答案的期望相差甚远 - 但是您为什么不看看像 Vue 这样的响应式工具呢?它拥有完成此类任务可能需要的所有工具,甚至更多:

    • 可以将整个测验抽象为一组简单的对象(问题)
    • 下一个,上一个,设置默认答案变得轻而易举
    • 易于扩展(带问题)
    • 易于更新(模板、功能等)

    Vue.component('QuizQuestion', {
      props: ['data', 'selected'],
      computed: {
        valSelected: {
          get() {
            return this.selected
          },
          set(val) {
            this.$emit('update:selected', val)
          }
        },
      },
      template: `
        <div>
          {{ data.text }}<br />
          {{ data.description }}<br />
          <div class="quiz-options">
            <label
              v-for="val in data.options"
              :key="val[0]"
            >
              <input
                type="radio"
                :name="data.text"
                :value="val"
                v-model="valSelected"
              />
              {{ val[1] }}
            </label>
          </div>
        </div>
      `
    })
    new Vue({
      el: "#app",
      computed: {
        currentQuestion() {
          return this.questions[this.current]
        },
        hasPrev() {
          return !!this.current
        },
        hasNext() {
          return this.current < this.questions.length - 1
        },
      },
      data() {
        return {
          current: 0,
          questions: [{
            text: 'Whats your size?',
            description: 'The size of your shoes is very important. If you have the wrong size, they wont fit.',
            options: [
              ['6595', '41'],
              ['6598', '42'],
              ['6601', '43'],
              ['', ''],
            ],
            selected: null,
          }, {
            text: 'What color would you like?',
            description: 'Color isn\'t that important, It looks good tho.',
            options: [
              ['6053', 'Red'],
              ['6044', 'Blue'],
              ['6056', 'Yellow'],
              ['6048', 'Green'],
              ['', ''],
            ],
            selected: null,
          }, {
            text: 'What brand would you like?',
            description: 'Brand is less important. Its just your own preference',
            options: [
              ['5805', 'Adidas'],
              ['5866', 'Nike'],
              ['5875', 'Puma'],
              ['', ''],
            ],
            selected: null,
          }, ],
        }
      },
      methods: {
        selectDefault() {
          this.questions[this.current] = {
            ...this.questions[this.current],
            selected: this.questions[this.current].options.slice(-1)[0],
          }
        },
        getPrev() {
          if (this.hasPrev) {
            if (!this.currentQuestion.selected) {
              this.selectDefault()
            }
            this.current -= 1
          }
        },
        getNext() {
          if (this.hasNext) {
            if (!this.currentQuestion.selected) {
              this.selectDefault()
            }
            this.current += 1
          }
        },
      },
      template: `
        <div>
          <quiz-question
            :data="currentQuestion"
            :selected.sync="currentQuestion.selected"
          /><br />
          <button v-if="hasPrev" @click="getPrev">PREV</button>
          <button v-if="hasNext" @click="getNext">NEXT</button>
          <button v-if="!hasNext">RESULT</button>
        </div>
      `
    })
    .quiz-options {
      display: flex;
      flex-direction: column;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <div id="app"></div>

    编辑

    但是,如果不使用框架/库,这里有一个更 OOP 的方法:

    class Quiz {
      constructor(questions) {
        this._current = 0
        this._questions = questions
      }
      get current() {
        return this._current
      }
      set current(val) {
        this._current = val
      }
      get hasNext() {
        return this.current < this.questions.length - 1
      }
      get hasPrev() {
        return !!this.current
      }
      get questions() {
        return this._questions
      }
      get next() {
        this.current = this.hasNext ? this.current + 1 : this.current
        return this.currentQuestion
      }
      get prev() {
        this.current = this.hasPrev ? this.current - 1 : this.current
        return this.currentQuestion
      }
      get currentQuestion() {
        return this.questions[this.current]
      }
    }
    
    class Question {
      constructor({
        text,
        description,
        options,
        prefix,
      }) {
        this.text = text
        this.desc = description
        this.prefix = prefix
        this._options = options.map(([key, val]) => ({
          id: key,
          value: [key, val],
          selected: false,
        }))
      }
      get options() {
        return this._options
      }
      set options(newOptions) {
        this._options = newOptions
      }
      get selected() {
        return this.options.find(({
          selected
        }) => !!selected)
      }
      set selected(selectedVal) {
        this.options = [...this.options.map(({
          value: [key, val],
          selected,
          ...rest
        }) => {
          return {
            ...rest,
            value: [key, val],
            selected: key === selectedVal
          }
        })]
      }
      get lastOption() {
        return this.options.slice(-1)[0]
      }
      setDefault() {
        if (!this.selected) {
          this.selected = this.lastOption.id
        }
      }
    }
    
    const urlParser = (quiz) => {
      return quiz.questions.map(({
        prefix,
        selected = {
          value: ['']
        }
      }) => {
        const s = selected.value[0] ? selected.value[0] : ''
        return `${prefix}${s}`
      }).join('&')
    }
    
    const qArr = [{
        text: 'text1',
        description: 'desc1',
        options: [
          ['1_1', '11'],
          ['1_2', '12'],
          ['1_3', '13'],
        ],
        prefix: 'prefix_1_',
      },
      {
        text: 'text2',
        description: 'desc2',
        options: [
          ['2_1', '21'],
          ['2_2', '22'],
          ['2_3', '23'],
        ],
        prefix: 'prefix_2_',
      },
      {
        text: 'text3',
        description: 'desc3',
        options: [
          ['3_1', '31'],
          ['3_2', '32'],
          ['3_3', '33'],
        ],
        prefix: 'prefix_3_',
      },
    ]
    
    const getOptionsHtml = ({
      text,
      options
    }) => {
      let html = ''
      options.forEach(({
        id,
        value,
        selected
      }, i) => {
        html += `
            <label>
            <input
                class="question-input"
                type="radio"
              name="${text}"
              value="${value[0]}"
              ${selected ? 'checked' : ''}
            />
            ${value[1]}
          </label>
        `
      })
      return html
    }
    
    const getSingleQuestionHtml = (q) => {
      const optionsHtml = getOptionsHtml({
        text: q.text,
        options: q.options
      })
      return `
        ${q.text}<br />
        ${q.desc}<br />
        ${optionsHtml}
      `
    }
    
    const registerEventHandlers = ({
      container,
      question
    }) => {
      const radioBtns = document.querySelectorAll('.question-input')
      radioBtns.forEach((input, i) => {
        input.addEventListener('change', function(e) {
          question.selected = e.target.value
        })
      })
    }
    
    const updateHtml = ({
      container,
      question
    }) => {
      container.innerHTML = getSingleQuestionHtml(question)
      registerEventHandlers({
        container,
        question
      })
    };
    
    const updateContainer = (container) => (question) => updateHtml({
      container,
      question
    });
    
    const setElDisplay = ({
      el,
      display
    }) => {
      if (display) {
        el.classList.add("d-inline-block")
        el.classList.remove("d-none")
      } else {
        el.classList.remove("d-inline-block")
        el.classList.add("d-none")
      }
    }
    
    const updateBtnVisibility = ({
      btnNext,
      btnPrev,
      btnResult,
      quiz
    }) => () => {
      setElDisplay({
        el: btnNext,
        display: quiz.hasNext
      })
      setElDisplay({
        el: btnResult,
        display: !quiz.hasNext
      })
      setElDisplay({
        el: btnPrev,
        display: quiz.hasPrev
      })
    }
    
    (function() {
      const quiz = new Quiz(qArr.map(q => new Question(q)))
    
      const container = document.getElementById('quiz-container')
      updateQuizContainer = updateContainer(container)
      updateQuizContainer(quiz.currentQuestion)
    
      const btnPrev = document.getElementById('btn-prev')
      const btnNext = document.getElementById('btn-next')
      const btnResult = document.getElementById('btn-result')
    
      const updateBtns = updateBtnVisibility({
        btnPrev,
        btnNext,
        btnResult,
        quiz
      })
      updateBtns()
    
      btnPrev.addEventListener('click', function() {
        if (quiz.hasPrev) {
          quiz.currentQuestion.setDefault()
        }
        updateQuizContainer(quiz.prev)
        updateBtns()
      })
      btnNext.addEventListener('click', () => {
        if (quiz.hasNext) {
          quiz.currentQuestion.setDefault()
        }
        updateQuizContainer(quiz.next)
        updateBtns()
      })
      btnResult.addEventListener('click', function() {
        quiz.currentQuestion.setDefault()
        console.log(urlParser(quiz))
      })
    })();
    .d-inline-block {
      display: inline-block;
    }
    
    .d-none {
      display: none;
    }
    <div id="quiz-container"></div>
    <div id="quiz-controls">
      <button id="btn-prev" class="d-inline-block">
        PREV
      </button>
      <button id="btn-next" class="d-inline-block">
        NEXT
      </button>
      <button id="btn-result" class="d-none">
        RESULT
      </button>
    </div>
    <div id="result"></div>

    【讨论】:

    • 谢谢!我确实想在 oop 方面做得更好,但老实说,我仍然很难学习它,所以这对我来说很难阅读。我已经复习了很多次,我终于能够知道它的作用,但是有没有一种方法可以告诉我如何使用我的代码来做到这一点?现在对我来说容易多了。如果不是,非常感谢!
    • @thijs 可能,它可能是 - 但如果没有一个有效的版本,它有点'不可能重新创建你拥有的东西。例如,您没有提供 HTML(在您的问题示例代码中实际引用了该 HTML)。请添加一个有效的 sn-p(有你试图克服的问题) - 然后我认为它可能是。
    • 谢谢,但我已经在您的代码和一些资源的帮助下修复了它!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-17
    • 2019-09-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多