简体   繁体   English

如何将 eventListeners 附加到动态生成的单选按钮?

[英]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.

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