简体   繁体   English

将测验 (JS) 扩展到多项选择题

[英]Expand quiz (JS) to multipe choice questions

I'm happy with this script but at the moment it only accepts one right answer and automatically jumps to the next question when an answer has been selected.我对这个脚本很满意,但目前它只接受一个正确答案,并在选择答案后自动跳到下一个问题

Is it possible to expand the existing script easily with these features?是否可以使用这些功能轻松扩展现有脚本?

a) Accept more then only one right answer a) 接受多于一个的正确答案

Look at the Coke question: it should be something like看看可乐问题:应该是这样的

    solution: ['Zero','Vanilla','Cherry'], falses: ['Mud'],

b) Adding a "next question"-button b) 添加“下一个问题”按钮

This is needed because of the new feature of a)这是必需的,因为 a) 的新功能

 if (!Array.from) { Array.from = (function () { var toStr = Object.prototype.toString; var isCallable = function (fn) { return typeof fn === 'function' || toStr.call(fn) === '[object Function]'; }; var toInteger = function (value) { var number = Number(value); if (isNaN(number)) { return 0; } if (number === 0 || !isFinite(number)) { return number; } return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number)); }; var maxSafeInteger = Math.pow(2, 53) - 1; var toLength = function (value) { var len = toInteger(value); return Math.min(Math.max(len, 0), maxSafeInteger); }; // The length property of the from method is 1. return function from(arrayLike /*, mapFn, thisArg */ ) { // 1. Let C be the this value. var C = this; // 2. Let items be ToObject(arrayLike). var items = Object(arrayLike); // 3. ReturnIfAbrupt(items). if (arrayLike == null) { throw new TypeError( "Array.from requires an array-like object - not null or undefined"); } // 4. If mapfn is undefined, then let mapping be false. var mapFn = arguments.length > 1 ? arguments[1] : void undefined; var T; if (typeof mapFn !== 'undefined') { // 5. else // 5. a If IsCallable(mapfn) is false, throw a TypeError exception. if (!isCallable(mapFn)) { throw new TypeError( 'Array.from: when provided, the second argument must be a function'); } // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined. if (arguments.length > 2) { T = arguments[2]; } } // 10. Let lenValue be Get(items, "length"). // 11. Let len be ToLength(lenValue). var len = toLength(items.length); // 13. If IsConstructor(C) is true, then // 13. a. Let A be the result of calling the [[Construct]] internal method // of C with an argument list containing the single item len. // 14. a. Else, Let A be ArrayCreate(len). var A = isCallable(C) ? Object(new C(len)) : new Array(len); // 16. Let k be 0. var k = 0; // 17. Repeat, while k < len… (also steps a - h) var kValue; while (k < len) { kValue = items[k]; if (mapFn) { A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k); } else { A[k] = kValue; } k += 1; } // 18. Let putStatus be Put(A, "length", len, true). A.length = len; // 20. Return A. return A; }; }()); } 'use strict'; var myQuiz = { container: null, // helper function createElement: function (o) { var el, p; if (o && (o.tag || o.tagName)) { el = document.createElement(o.tag || o.tagName); if (o.text || o.txt) { var text = (o.text || o.txt) el.innerHTML = text; } for (p in o) { if (!p.match(/^t(e)?xt|tag(name)?$/i)) { el[p] = o[p]; } } } return el; }, // user interface for a quiz question createOptions: function () { var t = this, options = [], ul = document.createElement("ul"); t.emptyContainer(); t.intoContainer(t.createElement({ tag: "h2", text: "(" + t.currentQuestion.category + ") " + t.currentQuestion.question })); t.intoContainer(ul); // create options options.push(t.currentQuestion.solution); t.currentQuestion.falses.forEach(function (s) { options.push(s); }); t.shuffleArray(options); options.forEach(function (s, i) { var li = document.createElement("li"), label = t.createElement({ htmlFor: "a" + t.questions.length + "_" + i, tag: "label", text: s }), radio = t.createElement({ id: "a" + t.questions.length + "_" + i, name: "answer", tag: "input", type: "radio", tabindex: "0", value: s }); ul.appendChild(li); li.appendChild(radio); li.appendChild(label); }); // Hinweis für Tastatur-User t.intoContainer(t.createElement({ tag: "button", text: "confirm choice", type: "submit" })); }, currentChoices: [], currentQuestion: null, // data could be filled from an external source (JSON) data: [{ category: 'Capitals', question: 'What is the capital of Canada?', solution: 'Ottawa', falses: ['Berlin', 'New York', 'Sidney'], explanation: '...' }, { category: 'Food', question: 'What Coke flavors do exist?', solution: 'Zero', falses: ['Vanilla','Cherry','Mud' ], explanation: '...' }], emptyContainer: function () { var t = this; while (t.container.firstChild) { t.container.removeChild(t.container.firstChild); } }, handleInput: function () { var t = this, // t points to myQuiz // create real array so we can use forEach inputs = Array.from(t.container.getElementsByTagName("input")), selectedSolution = ""; // determine selection inputs.forEach(function (o) { if (o.checked) { selectedSolution = o.value; } }); // process selected answer if (selectedSolution && t.currentQuestion) { t.currentChoices.push({ a: selectedSolution, q: t.currentQuestion }); t.play(); } // accept start button if (!t.currentQuestion) { t.play(); } }, init: function () { var t = this; // here goes any code for loading data from an external source t.container = document.getElementById("quiz"); if (t.data.length && t.container) { // use anonymous functions so in handleInput // "this" can point to myQuiz t.container.addEventListener("submit", function (ev) { t.handleInput(); ev.stopPropagation(); ev.preventDefault(); return false; }); t.container.addEventListener("mouseup", function (ev) { // we want to only support clicks on start buttons... var go = ev.target.tagName.match(/^button$/i); // ... and labels for radio buttons when in a game if (ev.target.tagName.match(/^label$/i) && t.currentQuestion) { go = true; } if (go) { window.setTimeout(function () { t.handleInput(); }, 50); ev.stopPropagation(); ev.preventDefault(); return false; } }); t.start(); } }, intoContainer: function (el, parentType) { var t = this, parent; if (!el) { return; } if (parentType) { parent = document.createElement(parentType); parent.appendChild(el); } else { parent = el; } t.container.appendChild(parent); return parent; }, // ask next question or end quiz if none are left play: function () { var t = this, ol; // game over? if (!t.questions.length) { t.showResults(); // offer restart window.setTimeout(function () { t.start(); }, 50); return; } t.currentQuestion = t.questions.shift(); t.createOptions(); }, // list with remaining quiz question objects questions: [], // list original questions and given answers and elaborate on solutions showResults: function () { var cat, ol, s, scores = {}, t = this, tab, thead, tbody, tr; t.emptyContainer(); // show message t.intoContainer(t.createElement({ tag: "p", text: "You've answered all questions of this quiz. Here are your results:" })); // list questions and given answers ol = t.intoContainer(t.createElement({ id: "result", tag: "ol" })); t.currentChoices.forEach(function (o) { var p, li = ol.appendChild(t.createElement({ tag: "li" })); // list original question li.appendChild(t.createElement({ className: "question", tag: "p", text: "(" + oqcategory + ") " + oqquestion })); // list given answer p = li.appendChild(t.createElement({ tag: "p", text: "Your answer: " })); p.appendChild(t.createElement({ className: (oqsolution == oa ? "correct" : "wrong"), tag: "em", text: oa })); // wrong answer? if (oqsolution != oa) { p = li.appendChild(t.createElement({ tag: "p", text: "The right answer should be: " })); p.appendChild(t.createElement({ tag: "em", text: oqsolution })); } // elaborate on solution? if (oqexplanation) { p = li.appendChild(t.createElement({ tag: "p", text: "Explanation (why): " })); p.appendChild(t.createElement({ tag: "em", text: oqexplanation })); } }); // display a kind of percentual score over the categories cat = []; t.currentChoices.forEach(function (o) { if (!cat.includes(oqcategory)) { cat.push(oqcategory); } }); cat.sort(); cat.forEach(function (c) { var correct = 0, num = 0; t.currentChoices.forEach(function (o) { if (oqcategory == c) { num++; if (oqsolution == oa) { correct++; } } }); scores[c] = Math.floor(100 * correct / num) + "%"; }); tab = t.intoContainer(t.createElement({ id: "scores", tag: "table" })); tab.appendChild(t.createElement({ tag: "caption", text: "Overview categories" })) thead = tab.appendChild(t.createElement({ tag: "thead" })) tr = thead.appendChild(t.createElement({ tag: "tr" })) for (s in scores) { tr.appendChild(t.createElement({ tag: "th", text: s })); } tbody = tab.appendChild(t.createElement({ tag: "tbody" })) tr = tbody.appendChild(t.createElement({ tag: "tr" })) for (s in scores) { tr.appendChild(t.createElement({ tag: "td", text: scores[s] })); } // show message t.intoContainer(t.createElement({ tag: "p", text: "Do you want to restart?" })); }, shuffleArray: function (a) { var i = a.length; while (i >= 2) { var zi = Math.floor(Math.random() * i); var t = a[zi]; a[zi] = a[--i]; a[i] = t; } // no return argument since the array has been // handed over as a reference and not a copy! }, // start quiz with a start button start: function () { var t = this; // fill list of remaining quiz questions t.questions = []; t.data.forEach(function (o) { t.questions.push(o); }); t.shuffleArray(t.questions); t.currentChoices = []; t.currentQuestion = null; // install start button t.intoContainer(t.createElement({ className: "startBtn", tag: "button", text: "Start quiz!" }), "p"); } }; document.addEventListener("DOMContentLoaded", function () { myQuiz.init(); });
 h1 { background: #f1f3f4 none repeat scroll 0 0 !important; padding: 1rem !important; } #quiz ul { list-style: none; margin: 0; padding: 0; } #quiz li { margin: 0; padding: 0; } #quiz label { display: block; background-color: #fffbf0; border: 2px solid #e7c157; border-radius: 0.2em; margin: 0.1em 0; padding: 1em 2em; text-align: start; max-width: 33em; } #quiz label:hover { background-color: #dfac20; } #quiz input:checked ~ label, #quiz input:focus ~ label { background-color: #dfac20; border-color: #866a00; } #quiz input { left: -9999px; position: absolute; } #quiz button:not(.startBtn) { display: none; } #quiz button, #quiz label { cursor: pointer; } /* listing with solutions */ .question { font-weight: bold; } .correct { color: #0c0; } .wrong { color: #c00; } .correct:before { content: '✓'; color: #0d0; } .wrong:before { content: '✗'; color: #f00; } .correct:before, .wrong:before { font: 2em bold; padding: 0 0.2em; } #scores, #scores td, #scores th { border: 1px solid black; border-collapse: collapse; text-align: center; }
 <h1>Quiz</h1><main id="main"><form id="quiz" action=""></form></main>

You can change solution from a string to solutions as an array and then use Array.includes to have multiple correct answers.您可以将solution从字符串更改为数组solutions ,然后使用Array.includes获得多个正确答案。

 if (!Array.from) { Array.from = (function () { var toStr = Object.prototype.toString; var isCallable = function (fn) { return typeof fn === 'function' || toStr.call(fn) === '[object Function]'; }; var toInteger = function (value) { var number = Number(value); if (isNaN(number)) { return 0; } if (number === 0 || !isFinite(number)) { return number; } return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number)); }; var maxSafeInteger = Math.pow(2, 53) - 1; var toLength = function (value) { var len = toInteger(value); return Math.min(Math.max(len, 0), maxSafeInteger); }; // The length property of the from method is 1. return function from(arrayLike /*, mapFn, thisArg */ ) { // 1. Let C be the this value. var C = this; // 2. Let items be ToObject(arrayLike). var items = Object(arrayLike); // 3. ReturnIfAbrupt(items). if (arrayLike == null) { throw new TypeError( "Array.from requires an array-like object - not null or undefined"); } // 4. If mapfn is undefined, then let mapping be false. var mapFn = arguments.length > 1 ? arguments[1] : void undefined; var T; if (typeof mapFn !== 'undefined') { // 5. else // 5. a If IsCallable(mapfn) is false, throw a TypeError exception. if (!isCallable(mapFn)) { throw new TypeError( 'Array.from: when provided, the second argument must be a function'); } // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined. if (arguments.length > 2) { T = arguments[2]; } } // 10. Let lenValue be Get(items, "length"). // 11. Let len be ToLength(lenValue). var len = toLength(items.length); // 13. If IsConstructor(C) is true, then // 13. a. Let A be the result of calling the [[Construct]] internal method // of C with an argument list containing the single item len. // 14. a. Else, Let A be ArrayCreate(len). var A = isCallable(C) ? Object(new C(len)) : new Array(len); // 16. Let k be 0. var k = 0; // 17. Repeat, while k < len… (also steps a - h) var kValue; while (k < len) { kValue = items[k]; if (mapFn) { A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k); } else { A[k] = kValue; } k += 1; } // 18. Let putStatus be Put(A, "length", len, true). A.length = len; // 20. Return A. return A; }; }()); } 'use strict'; var myQuiz = { container: null, // helper function createElement: function (o) { var el, p; if (o && (o.tag || o.tagName)) { el = document.createElement(o.tag || o.tagName); if (o.text || o.txt) { var text = (o.text || o.txt) el.innerHTML = text; } for (p in o) { if (!p.match(/^t(e)?xt|tag(name)?$/i)) { el[p] = o[p]; } } } return el; }, // user interface for a quiz question createOptions: function () { var t = this, options = [], ul = document.createElement("ul"); t.emptyContainer(); t.intoContainer(t.createElement({ tag: "h2", text: "(" + t.currentQuestion.category + ") " + t.currentQuestion.question })); t.intoContainer(ul); // create options options.push(...t.currentQuestion.solutions, ...t.currentQuestion.falses) t.shuffleArray(options); options.forEach(function (s, i) { var li = document.createElement("li"), label = t.createElement({ htmlFor: "a" + t.questions.length + "_" + i, tag: "label", text: s }), radio = t.createElement({ id: "a" + t.questions.length + "_" + i, name: "answer", tag: "input", type: "radio", tabindex: "0", value: s }); ul.appendChild(li); li.appendChild(radio); li.appendChild(label); }); // Hinweis für Tastatur-User t.intoContainer(t.createElement({ tag: "button", text: "confirm choice", type: "submit" })); }, currentChoices: [], currentQuestion: null, // data could be filled from an external source (JSON) data: [{ category: 'Capitals', question: 'What is the capital of Canada?', solutions: ['Ottawa'], falses: ['Berlin', 'New York', 'Sidney'], explanation: '...' }, { category: 'Food', question: 'What Coke flavors do exist?', solutions: ['Zero', 'Cherry', 'Vanilla'], falses: ['Mud' ], explanation: '...' }], emptyContainer: function () { var t = this; while (t.container.firstChild) { t.container.removeChild(t.container.firstChild); } }, handleInput: function () { var t = this, // t points to myQuiz // create real array so we can use forEach inputs = Array.from(t.container.getElementsByTagName("input")), selectedSolution = ""; // determine selection inputs.forEach(function (o) { if (o.checked) { selectedSolution = o.value; } }); // process selected answer if (selectedSolution && t.currentQuestion) { t.currentChoices.push({ a: selectedSolution, q: t.currentQuestion }); t.play(); } // accept start button if (!t.currentQuestion) { t.play(); } }, init: function () { var t = this; // here goes any code for loading data from an external source t.container = document.getElementById("quiz"); if (t.data.length && t.container) { // use anonymous functions so in handleInput // "this" can point to myQuiz t.container.addEventListener("submit", function (ev) { t.handleInput(); ev.stopPropagation(); ev.preventDefault(); return false; }); t.container.addEventListener("mouseup", function (ev) { // we want to only support clicks on start buttons... var go = ev.target.tagName.match(/^button$/i); // ... and labels for radio buttons when in a game if (ev.target.tagName.match(/^label$/i) && t.currentQuestion) { go = true; } if (go) { window.setTimeout(function () { t.handleInput(); }, 50); ev.stopPropagation(); ev.preventDefault(); return false; } }); t.start(); } }, intoContainer: function (el, parentType) { var t = this, parent; if (!el) { return; } if (parentType) { parent = document.createElement(parentType); parent.appendChild(el); } else { parent = el; } t.container.appendChild(parent); return parent; }, // ask next question or end quiz if none are left play: function () { var t = this, ol; // game over? if (!t.questions.length) { t.showResults(); // offer restart window.setTimeout(function () { t.start(); }, 50); return; } t.currentQuestion = t.questions.shift(); t.createOptions(); }, // list with remaining quiz question objects questions: [], // list original questions and given answers and elaborate on solutions showResults: function () { var cat, ol, s, scores = {}, t = this, tab, thead, tbody, tr; t.emptyContainer(); // show message t.intoContainer(t.createElement({ tag: "p", text: "You've answered all questions of this quiz. Here are your results:" })); // list questions and given answers ol = t.intoContainer(t.createElement({ id: "result", tag: "ol" })); t.currentChoices.forEach(function (o) { var p, li = ol.appendChild(t.createElement({ tag: "li" })); // list original question li.appendChild(t.createElement({ className: "question", tag: "p", text: "(" + oqcategory + ") " + oqquestion })); // list given answer p = li.appendChild(t.createElement({ tag: "p", text: "Your answer: " })); p.appendChild(t.createElement({ className: (oqsolutions.includes(oa) ? "correct" : "wrong"), tag: "em", text: oa })); // wrong answer? if (!oqsolutions.includes(oa)) { p = li.appendChild(t.createElement({ tag: "p", text: "The right answer should be: " })); p.appendChild(t.createElement({ tag: "em", text: oqsolutions.join(', ') })); } // elaborate on solution? if (oqexplanation) { p = li.appendChild(t.createElement({ tag: "p", text: "Explanation (why): " })); p.appendChild(t.createElement({ tag: "em", text: oqexplanation })); } }); // display a kind of percentual score over the categories cat = []; t.currentChoices.forEach(function (o) { if (!cat.includes(oqcategory)) { cat.push(oqcategory); } }); cat.sort(); cat.forEach(function (c) { var correct = 0, num = 0; t.currentChoices.forEach(function (o) { if (oqcategory == c) { num++; if (oqsolutions.includes(oa)) { correct++; } } }); scores[c] = Math.floor(100 * correct / num) + "%"; }); tab = t.intoContainer(t.createElement({ id: "scores", tag: "table" })); tab.appendChild(t.createElement({ tag: "caption", text: "Overview categories" })) thead = tab.appendChild(t.createElement({ tag: "thead" })) tr = thead.appendChild(t.createElement({ tag: "tr" })) for (s in scores) { tr.appendChild(t.createElement({ tag: "th", text: s })); } tbody = tab.appendChild(t.createElement({ tag: "tbody" })) tr = tbody.appendChild(t.createElement({ tag: "tr" })) for (s in scores) { tr.appendChild(t.createElement({ tag: "td", text: scores[s] })); } // show message t.intoContainer(t.createElement({ tag: "p", text: "Do you want to restart?" })); }, shuffleArray: function (a) { var i = a.length; while (i >= 2) { var zi = Math.floor(Math.random() * i); var t = a[zi]; a[zi] = a[--i]; a[i] = t; } // no return argument since the array has been // handed over as a reference and not a copy! }, // start quiz with a start button start: function () { var t = this; // fill list of remaining quiz questions t.questions = []; t.data.forEach(function (o) { t.questions.push(o); }); t.shuffleArray(t.questions); t.currentChoices = []; t.currentQuestion = null; // install start button t.intoContainer(t.createElement({ className: "startBtn", tag: "button", text: "Start quiz!" }), "p"); } }; document.addEventListener("DOMContentLoaded", function () { myQuiz.init(); });
 h1 { background: #f1f3f4 none repeat scroll 0 0 !important; padding: 1rem !important; } #quiz ul { list-style: none; margin: 0; padding: 0; } #quiz li { margin: 0; padding: 0; } #quiz label { display: block; background-color: #fffbf0; border: 2px solid #e7c157; border-radius: 0.2em; margin: 0.1em 0; padding: 1em 2em; text-align: start; max-width: 33em; } #quiz label:hover { background-color: #dfac20; } #quiz input:checked ~ label, #quiz input:focus ~ label { background-color: #dfac20; border-color: #866a00; } #quiz input { left: -9999px; position: absolute; } #quiz button:not(.startBtn) { display: none; } #quiz button, #quiz label { cursor: pointer; } /* listing with solutions */ .question { font-weight: bold; } .correct { color: #0c0; } .wrong { color: #c00; } .correct:before { content: '✓'; color: #0d0; } .wrong:before { content: '✗'; color: #f00; } .correct:before, .wrong:before { font: 2em bold; padding: 0 0.2em; } #scores, #scores td, #scores th { border: 1px solid black; border-collapse: collapse; text-align: center; }
 <h1>Quiz</h1><main id="main"><form id="quiz" action=""></form></main>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM