如何附加事件侦听器以动态生成单选按钮?
How do I attach eventListeners to dynamically generated radio buttons?
我想为每个单选输入点击附加一个事件侦听器,以便我可以检索该单选输入的值并将其分配为 allQuestions 数组中当前问题对象中的新 属性 的值.
我不确定为什么我在 choice.addEventListener
工作时遇到困难。
我的HTML:
<div id="quiz"></div>
<button id="button">Next</button>
我的JavaScript:
var allQuestions = [{question: "What is the capital of the Czech Republic?",
choices: ["Skopje", "Budapest", "Prague", "Bucharest"],
correctAnswer: 2},
{question: "When was the Declaration of Independence signed?",
choices: ["1492", "1776", "1812", "1791"],
correctAnswer: 1}];
var quiz = document.getElementById("quiz");
var index = -1;
var next = function() {
index += 1;
quiz.innerHTML = "";
for (var i = 0; i < allQuestions[index]['choices'].length; i++) {
var choice = document.createElement('input');
choice.type = 'radio';
choice.name = 'choices';
choice.value = i;
choice.addEventListener('click', function() {
alert('hi');
});
quiz.appendChild(choice);
quiz.innerHTML += allQuestions[index]['choices'][i] + '<br>';
}
};
var button = document.getElementById('button');
button.addEventListener('click', next);
您正在尝试同时使用标记和 DOM 元素。这是主要问题:
quiz.appendChild(choice);
quiz.innerHTML += allQuestions[index]['choices'][i] + '<br>';
第一行将带有附加事件处理程序的 DOM 元素附加到 quiz
元素。第二行将 quiz
的内容转换为 HTML 字符串,向该字符串附加一些进一步的文本(标记),然后解析 HTML 和 替换 quiz
的内容和解析后的结果。这会清除 HTML 中未表示的所有内容,包括 dynamically-added 事件处理程序。
解决方案是不做 innerHTML += ...
,这几乎总是一个坏主意。在这种特殊情况下,您可以这样做:
quiz.appendChild(choice);
quiz.appendChild(document.createTextNode(allQuestions[index]['choices'][i]));
quiz.appendChild(document.createElement('br'));
...这还有一个优点,即 HTML 中的任何特殊字符(如 <
)都按字面意思处理(因为那是 createTextNode
所做的)。
话虽如此,您不需要在每个单选按钮上都使用处理程序。相反,您可以通过在 quiz
元素上使用处理程序来使用 事件委托 ,然后在处理程序中使用 e.target
来了解单击了哪个单选按钮:
quiz.addEventListener("click", function(e) {
if (e.target.tagName.toUpperCase() === "INPUT") {
var value = e.target.value; // The value of the clicked radio button
}
});
这样,您就不必担心动态添加处理程序;只需执行一次,在已知 quiz
元素存在之后,您可以根据需要更新其内容,而不必担心将处理程序附加到其中的单选按钮。
一般来说,要进行事件委托,您通常必须从 e.target
开始循环并转到其 parentNode
以找到您感兴趣的元素(假设您感兴趣在 div
中,但点击是在其中的 span
上);当然,input
元素里面不能有任何元素,所以这里就简单了。
您可能想知道为什么要检查标签名称。如果您将单选按钮与 label
元素相关联(这通常是好的做法),可以将 input
放在 中 label
中,或者使用label
上的 for
属性,当您单击 label
时,您将看到 两次 次点击:一次在标签本身上,另一次在标签相关的 input
上。我们只对实际单选按钮上的那个感兴趣。
下面是上面委托的一个简单示例:
var quiz = document.getElementById("quiz");
quiz.addEventListener("click", function(e) {
if (e.target.tagName.toUpperCase() === "INPUT") {
var value = e.target.value; // The value of the clicked radio button
console.log("The value of that radio button is " + value);
}
});
for (var n = 0; n < 5; ++n) {
var div = document.createElement("div");
div.innerHTML = '<label><input type="radio" value="' + n + '" name="answer"> Radio ' + n + '</label>';
quiz.appendChild(div);
}
<div id="quiz"></div>
我想为每个单选输入点击附加一个事件侦听器,以便我可以检索该单选输入的值并将其分配为 allQuestions 数组中当前问题对象中的新 属性 的值.
我不确定为什么我在 choice.addEventListener
工作时遇到困难。
我的HTML:
<div id="quiz"></div>
<button id="button">Next</button>
我的JavaScript:
var allQuestions = [{question: "What is the capital of the Czech Republic?",
choices: ["Skopje", "Budapest", "Prague", "Bucharest"],
correctAnswer: 2},
{question: "When was the Declaration of Independence signed?",
choices: ["1492", "1776", "1812", "1791"],
correctAnswer: 1}];
var quiz = document.getElementById("quiz");
var index = -1;
var next = function() {
index += 1;
quiz.innerHTML = "";
for (var i = 0; i < allQuestions[index]['choices'].length; i++) {
var choice = document.createElement('input');
choice.type = 'radio';
choice.name = 'choices';
choice.value = i;
choice.addEventListener('click', function() {
alert('hi');
});
quiz.appendChild(choice);
quiz.innerHTML += allQuestions[index]['choices'][i] + '<br>';
}
};
var button = document.getElementById('button');
button.addEventListener('click', next);
您正在尝试同时使用标记和 DOM 元素。这是主要问题:
quiz.appendChild(choice);
quiz.innerHTML += allQuestions[index]['choices'][i] + '<br>';
第一行将带有附加事件处理程序的 DOM 元素附加到 quiz
元素。第二行将 quiz
的内容转换为 HTML 字符串,向该字符串附加一些进一步的文本(标记),然后解析 HTML 和 替换 quiz
的内容和解析后的结果。这会清除 HTML 中未表示的所有内容,包括 dynamically-added 事件处理程序。
解决方案是不做 innerHTML += ...
,这几乎总是一个坏主意。在这种特殊情况下,您可以这样做:
quiz.appendChild(choice);
quiz.appendChild(document.createTextNode(allQuestions[index]['choices'][i]));
quiz.appendChild(document.createElement('br'));
...这还有一个优点,即 HTML 中的任何特殊字符(如 <
)都按字面意思处理(因为那是 createTextNode
所做的)。
话虽如此,您不需要在每个单选按钮上都使用处理程序。相反,您可以通过在 quiz
元素上使用处理程序来使用 事件委托 ,然后在处理程序中使用 e.target
来了解单击了哪个单选按钮:
quiz.addEventListener("click", function(e) {
if (e.target.tagName.toUpperCase() === "INPUT") {
var value = e.target.value; // The value of the clicked radio button
}
});
这样,您就不必担心动态添加处理程序;只需执行一次,在已知 quiz
元素存在之后,您可以根据需要更新其内容,而不必担心将处理程序附加到其中的单选按钮。
一般来说,要进行事件委托,您通常必须从 e.target
开始循环并转到其 parentNode
以找到您感兴趣的元素(假设您感兴趣在 div
中,但点击是在其中的 span
上);当然,input
元素里面不能有任何元素,所以这里就简单了。
您可能想知道为什么要检查标签名称。如果您将单选按钮与 label
元素相关联(这通常是好的做法),可以将 input
放在 中 label
中,或者使用label
上的 for
属性,当您单击 label
时,您将看到 两次 次点击:一次在标签本身上,另一次在标签相关的 input
上。我们只对实际单选按钮上的那个感兴趣。
下面是上面委托的一个简单示例:
var quiz = document.getElementById("quiz");
quiz.addEventListener("click", function(e) {
if (e.target.tagName.toUpperCase() === "INPUT") {
var value = e.target.value; // The value of the clicked radio button
console.log("The value of that radio button is " + value);
}
});
for (var n = 0; n < 5; ++n) {
var div = document.createElement("div");
div.innerHTML = '<label><input type="radio" value="' + n + '" name="answer"> Radio ' + n + '</label>';
quiz.appendChild(div);
}
<div id="quiz"></div>