[英]How do I attach eventListeners to dynamically generated radio buttons?
I want to attach an event listener to each radio input click, so that I can retrieve that radio input's value and assign it as the value of a new property in the current question object in the allQuestions array.我想为每个单选输入点击附加一个事件侦听器,以便我可以检索该单选输入的值并将其分配为 allQuestions 数组中当前问题对象中的新属性的值。
I'm not sure why I'm having difficulty making
choice.addEventListener
work.我不确定为什么我很难让
choice.addEventListener
工作。
My HTML:我的HTML:
<div id="quiz"></div>
<button id="button">Next</button>
My 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);
You're trying to use markup and DOM elements at the same time.您正在尝试同时使用标记和 DOM 元素。 Here's the main problem:
这是主要问题:
quiz.appendChild(choice);
quiz.innerHTML += allQuestions[index]['choices'][i] + '<br>';
The first line appends a DOM element with an attached event handler to the quiz
element.第一行将带有附加事件处理程序的 DOM 元素附加到
quiz
元素。 The second line converts the contents of quiz
to an HTML string, appends some further text (markup) to that string, and then parses that HTML and replaces the content of quiz
with the parsed result.第二行将
quiz
的内容转换为 HTML 字符串,向该字符串附加一些进一步的文本(标记),然后解析该 HTML 并用解析的结果替换quiz
的内容。 That wipes out anything not represented in the HTML, including the dynamically-added event handler.这会清除 HTML 中未表示的所有内容,包括动态添加的事件处理程序。
The solution is not to do innerHTML +=...
, which is almost always a bad idea.解决方案是不执行
innerHTML +=...
,这几乎总是一个坏主意。 In this particular case, you can do this:在这种特殊情况下,您可以这样做:
quiz.appendChild(choice);
quiz.appendChild(document.createTextNode(allQuestions[index]['choices'][i]));
quiz.appendChild(document.createElement('br'));
...which also has the advantage that any characters that are special in HTML (like <
) are treated literally (because that's what createTextNode
does). ...这还有一个优点,即 HTML 中的任何特殊字符(如
<
)都按字面意思处理(因为这就是createTextNode
所做的)。
Now, having said that, you don't need handlers on every radio button.现在,话虽如此,您不需要每个单选按钮上的处理程序。 Instead, you can use event delegation by using a handler on your
quiz
element, and then using e.target
within the handler to know which radio button was clicked:相反,您可以通过在
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
}
});
That way, you don't have to worry about adding handlers dynamically;这样,您就不必担心动态添加处理程序; just do it once, after the
quiz
element is known to exist, and you can update its content all you want without having to worry about attaching handlers to the radio buttons within.只需执行一次,在已知
quiz
元素存在之后,您可以根据需要更新其内容,而不必担心将处理程序附加到其中的单选按钮。
To do event delegation in general, you usually have to loop starting from e.target
and going to its parentNode
in order to find the element you're interested in (say you're interested in a div
, but the click was on a span
inside it);一般来说,要进行事件委托,您通常必须从
e.target
开始循环并转到其parentNode
以找到您感兴趣的元素(假设您对div
感兴趣,但点击是在span
上在里面); but of course, input
elements can't have any elements inside them, so it's simple here.但是当然,
input
元素里面不能有任何元素,所以这里很简单。
You're probably wondering why the check on the tag name.您可能想知道为什么要检查标签名称。 If you associate your radio buttons with
label
elements (as is usually good practice), either by putting the input
inside the label
or using the for
attribute on the label
, you'll see two clicks when you click the label
: One on the label itself, and a second one on the input
that the label relates to.如果将单选按钮与
label
元素相关联(这通常是一种好的做法),无论是通过将input
放在label
内还是在标签上使用for
属性,当您单击label
时,您将看到两次点击:一次在label
上本身,第二个在标签相关的input
上。 We're only interested in the one on the actual radio button.我们只对实际单选按钮上的那个感兴趣。
Here's a simple example of the delegation above:这是上面委托的一个简单示例:
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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.