簡體   English   中英

將下拉框更改為單選按鈕以進行測驗

[英]Changing Drop Down Boxes To Radio Buttons For Quiz

代碼新手在這里!

我設法整理了一個表格,根據用戶的選擇計算他們的分數。 它有效!

這是我的代碼:

 function finalScore(round) { var correct = 0; var selectValue; var questions = document.getElementsByClassName("question"); var numOfQuestions = questions.length; for (var i = 0; i < questions.length; i++) { //begin for loop //get the value of the select element selectValue = questions[i].options[questions[i].selectedIndex].value; //if the value equals right if (selectValue === "one") { //begin if then //increment the correct variable correct = correct + 1; } else if (selectValue === "two") { correct = correct + 2; } else if (selectValue === "three") { correct = correct + 3; } else if (selectValue === "four") { correct = correct + 4; } } //end for loop alert(correct); if (round === false) { //get the percentage of correct answers(not rounded) document.getElementById("scoreDisplay").innerHTML = correct; } else { //display the rounded value document.getElementById("scoreDisplay").innerHTML = correct; } //end if then else } //end function
 How Old Are You? <select class="question" id="1howold"> <option value="three">19 - 26</option> <option value="four">27 - 36</option> <option value="two">37 - 40</option> <option value="one">41+</option> </select><br /><br /> What's Your Relationship Status? <select class="question" id="2relationshipstatus"> <option value="four">Single and excited to see what's out there.</option> <option value="three">Recently single and emotionally destroyed.</option> <option value="two">Got some casual things on the go, not looking for anything too serious.</option> <option value="one">In a committed relationship and only taking this quiz for the lols.</option> </select><br /><br /> Where Is Your Location? <select class="question" id="3location"> <option value="four">Location Independent</option> <option value="three">London/The UK</option> <option value="two">Europe</option> <option value="one">Elsewhere</option> </select><br /><br /> <button type="button" onclick="finalScore(true)">Submit</button> <div id="scoreDisplay">score goes here</div>

在此處查看 JSfiddle: https://jsfiddle.net/tm3o5g0k/

但是,我意識到由於某些選項的長度,我需要將它們切換為單選按鈕。 試了那么多方法還是老是亂七八糟? 當然有一種我忽略的簡單方法可以做到這一點?

謝謝: :)

根據您問題中的代碼和問題描述,以及對問題的評論,我開發了以下解決方案。 我所做的假設是:

  1. 你想將<option>元素轉換為<input type="radio" />元素,並且
  2. 您想要根據分配給每個<input>元素的值來確定總分。

考慮到這一點,我調整了 HTML 以更好地適應確定的假設及其要求:

  1. 每個option元素的值都是score的等價數值,為了更方便的計算,所以value="four"變成了value="1"
  2. 每個<select>元素之前的textNode已轉換為<legend>以便每個“組”的<input>元素都可以在視覺上識別為一個組,
  3. 我已經從每個<select>id中刪除了這個數字——這似乎在很大程度上是不相關的,而在 HTML 5 下,有一個以數字開頭的id是有效的,它在歷史上是有問題的 select 這樣的id通過 CSS 作為數字是必需的要明確轉義,
  4. 我還為<select>元素分配了一個name屬性,這是因為如果結果應該存儲在數據庫中,並且對於<input type="radio"> ,則需要name才能正確地將值傳遞給服務器<input type="radio">元素充當互斥組(因此一次只能從相關元素中選擇一個<input> )必須分配name屬性來標識該關系。 因此,在操作之前將name添加到<select>而不是依賴自動生成的name是有意義的,這會或可能會導致服務器端存儲問題。

盡管如此,解決問題的一種方法如下:

 // declaring the functions as constants, using 'const'; // variables declared with const cannot be reassigned, // though if the variable is an Object or Array the // properties, or contents, of that Object or Array can // be changed/updated later: const selectToRadio = (selectSelector) => { // within the function body we retrieve all relevant elements // using document.querySelectorAll(), passing the CSS selector // supplied to the function; then that iterable static // NodeList is converted to an Array using the spread syntax: const selects = [...document.querySelectorAll(selectSelector)], // we create basic elements: input = document.createElement('input'), label = document.createElement('label'), span = document.createElement('span'); // set the type of the created <input> element: input.type = 'radio'; // here we take the Array of Nodes and iterate over that // Array using Array.prototype.forEach() with an Arrow // function: selects.forEach( // 'sel' is a reference to the current <select> element // from the Array of <select> elements over which we're // iterating: (sel) => { // here we assign the property-value of the 'name' property // of the <select> element as the 'groupName' of the <inpu> // elements we're creating: let groupName = sel.name, // here we retrieve all descendant <option> elements // from the current <select> element, using // Element.querySelectorAll() and, again, creating // an Array - with the spread operator - of the // resulting iterable NodeList: options = [...sel.querySelectorAll('option')], // here we create a documentFragment() so all the // created elements can be appended at the same time: fragment = document.createDocumentFragment(); // here we again use Array.prototype.forEach() to iterate over // the Array of <option> elements: options.forEach( // 'opt' (these variables can be named whatever you like, so // so long as it's a valid variable-name within the naming // rules of JavaScript) is a reference to the current <option> // of the Array of <option> elements over which we're // iterating: (opt) => { // here we create clones of the various elements we // created earlier (rather than creating the same // type of element multiple times in each iteration // of the loop): let inputClone = input.cloneNode(), labelClone = label.cloneNode(), spanClone = span.cloneNode(); // here we set the 'name' and 'value' properties of the // cloned <input>: inputClone.name = groupName; inputClone.value = opt.value; // we use the Element.classList API to add the 'answer' // class-name to the created element: inputClone.classList.add('answer'); // we set the textContent of the created <span> to be // equal to the text from the current <option>: spanClone.textContent = opt.text; // we use the parentNode.append() method to append the // cloned <input> and the cloned <span> elements to // the cloned <label>: labelClone.append(inputClone, spanClone); // then we append the cloned <label> to the documentFragment: fragment.append(labelClone); }); // we use parentNode.insertBefore() method to insert the // documentFragment into the DOM before the current <select> // element: sel.parentNode.insertBefore(fragment, sel); // and then use childNode.remove() method to remove // the current <select> element - and its descendants - // from the DOM: sel.remove(); }); }, score = () => { // here we use the same approach as above to create an Array of // element-nodes that have the 'answer' class-name and are also checked: const answers = [...document.querySelectorAll('.answer:checked')], // here we take the answers Array, and then call: result = answers // Array.prototype.map() to create a new Array based on the // contents of the current Array; here that new Array is // an Array of Numbers: .map( // we again use Arrow syntax for the anonymous function, // here 'el' is a reference to the current checked <input> // element; the function body (the single line following // the '=>' characters) simply returns the value of the // checked <option> parsed as a Number in base 10. Any // attribute-value (from which the value property is // derived is returned as a String from JavaScript, which // is why we're parsing it to a Number): (el) => parseInt(el.value, 10)) // we then pass the Array of Numbers to the // Array.prototype.reduce() function in order to reduce // the chained Array to a single result; again we use an // Arrow function syntax; here the body of the function // is taking the previously-held (or default) value ('a') and // adding it to the value of the current Array-element (b); // the '0' at the end of the function is the default-value with // which the reduce function starts: .reduce((a, b) => a + b, 0); // we then find the element that will show the result, and update its // text-content to be equal to the resulting score: document.querySelector('#scoreDisplay').textContent = result; // here we return the result to the calling context in the event you want // to also store or otherwise manipulate the derived score: return result; }; // here we call the selectToRadio() function, passing in an // appropriate CSS selector: selectToRadio('select'); // here we retrieve the first or only <button> element in the document: document.querySelector('button') // and use EventTarget.addEventListener() to bind the named score() // function (note the deliberate lack of parentheses) as the // event-handler for the 'click' event: .addEventListener('click', score);
 fieldset { margin: 0.5em 0; } legend { padding: 0 0.6em; } label { display: flex; gap: 0 0.6em; margin: 0.3em 0; } input+span { border-radius: 0.6em; } input:checked+span { color: limegreen; }
 <form action=""> <fieldset> <legend>How old are you?</legend> <select class="question" id="howold" name="ageRange"> <option value="3">19 - 26</option> <option value="4">27 - 36</option> <option value="2">37 - 40</option> <option value="1">41+</option> </select> </fieldset> <fieldset> <legend>What's your relationship status?</legend> <select class="question" id="relationshipstatus" name="relationshipStatus"> <option value="4">Single and excited to see what's out there.</option> <option value="3">Recently single and emotionally destroyed.</option> <option value="2">Got some casual things on the go, not looking for anything too serious.</option> <option value="1">In a committed relationship and only taking this quiz for the lols.</option> </select> </fieldset> <fieldset> <legend>What is your location?</legend> <select class="question" id="location" name="location"> <option value="4">Location Independent</option> <option value="3">London/The UK</option> <option value="2">Europe</option> <option value="1">Elsewhere</option> </select> </fieldset> <button type="button">Submit</button> </form> <div id="scoreDisplay"></div>

JS 小提琴演示

在上面的代碼中,我們使用了以下方法:

[...document.querySelectorAll('CSS-selector')]

為了從document.querySelectorAll()的 NodeList 結果中有效地創建 Arrays,這在selectToRadio() function 中是不必要的,因為我們只使用Array.prototype.forEach()可以用NodeList.prototype.forEach()代替,沒有語法的變化。

然而在函數的組合上我還沒有完全決定我將如何提前實現代碼,所以我將NodeList s 轉換為 Arrays 只是為了我可以使用其他 Array 方法 - 例如Array.prototype.map() , Array.prototype.filter() – 正如我在score() function 中所做的那樣。

我不相信它會提高很多效率,如果有的話,但如果你不想浪費處理時間將NodeList轉換為 Array 那么只需轉換以下行:

const selects = [...document.querySelectorAll(selectSelector)],

和:

options = [...sel.querySelectorAll('option')],

進入:

const selects = document.querySelectorAll(selectSelector),

和:

options = sel.querySelectorAll('option'),

除此之外,不需要進行任何更改,例如:

selects.forEach(
  (sel) => ....

稱為 JavaScript 的引擎將自動使用NodeList.prototype.forEach()代替Array.prototype.forEach() (概念證明: JS Fiddle 演示)。

然而,在score() function 中,我確實使用了Array.prototype的其他方法,這些方法未轉換為 NodeLists 或在 NodeLists 上不可用,因此必須保留為 Array。

參考:

參考書目:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM