【问题标题】:javascript adding click events to buttons in a loopjavascript在循环中向按钮添加点击事件
【发布时间】:2015-12-31 00:29:35
【问题描述】:

下面的代码从 xml 文件中获取信息。 我成功地用一个按钮显示了每个行星的 id 和名称。

我想在按钮上添加一个 onclick 事件。 现在的问题是:它确实添加了 onclick 事件,但仅在循环中创建的最后一个按钮上。

我做错了什么?为什么它不为每个按钮创建一个onclick 事件,而只为循环中的最后一个按钮创建一个?

function updatePlaneten() {
    var valDiv, planets, valButton, textNode;
    // Get xml files
    planets = this.responseXML.getElementsByTagName("planeet");
    // loop through the <planet> tags 
    for (var i = 0; i < planets.length; i++) {
        valDiv = ''; // clear valDiv each time loop starts

        // Get the id and the name from the xml info in current <planet> tag
        valDiv += planets[i].getElementsByTagName("id")[0].childNodes[0].nodeValue + "<br>";
        valDiv += planets[i].getElementsByTagName("name")[0].childNodes[0].nodeValue + "<br>";
        document.getElementById("planetenID").innerHTML += valDiv + "<br>";

        // Create button with a value and pass in this object for later reference use (valButton.object=this)
        valButton = document.createElement("input");
        //  valButton.setAttribute("planeetID", planets[i].getElementsByTagName("id")[0].childNodes[0].nodeValue);
        valButton.setAttribute("value", 'Meer info');
        valButton.setAttribute("type", 'button');
        valButton.id = (i + 1);
        valButton.object = this;    
        //
        // Here is the problem i cant get fixed
        //    
        //valButton.onclick = function(){ showinfo(); }
        valButton.addEventListener('click', showinfo);
        // Place the button on screen
        document.getElementById("planetenID").appendChild(valButton);
    }
}

// simple function to check if it works
function showinfo() {
    console.log(this.object);
    console.log(this.id);
}

【问题讨论】:

  • @Andreas,这不是重复的,因为问题是 OP 在每次设置 innerHTML 时都会破坏按钮,从而有效地破坏先前设置的事件侦听器
  • @PatrickEvans 你说得对。我应该更仔细地阅读代码... :(

标签: javascript loops events onclick


【解决方案1】:

麻烦的是这一行:

document.getElementById("planetenID").innerHTML += valDiv + "<br>";

当您设置 innerHTML 时,当前其中的内容将被销毁并替换为新的 html,这意味着您的所有旧按钮现在都被销毁并创建了新按钮。之前附加的事件侦听器不会附加到新按钮。

相反,只需创建一个 div/span 或任何最有帮助的容器,添加您的星球文本或其他任何内容,然后使用 appendChild

valDiv = document.createElement("div");
var id = planets[i].getElementsByTagName("id")[0].childNodes[0].nodeValue;
var name = planets[i].getElementsByTagName("name")[0].childNodes[0].nodeValue;
valDiv.innerHTML = id+"<br>"+name+"<br>";
document.getElementById("planetenID").appendChild(valDiv);

你也可以使用insertAdjacentHTML

var id = planets[i].getElementsByTagName("id")[0].childNodes[0].nodeValue;
var name = planets[i].getElementsByTagName("name")[0].childNodes[0].nodeValue;
valDiv = id+"<br>"+name+"<br>";
document.getElementById("planetenID").insertAdjacentHTML("beforeend",valDiv);

【讨论】:

    【解决方案2】:
    function updatePlaneten() {
        var valDiv, planets, valButton, textNode;
        // Get xml files
        planets = this.responseXML.getElementsByTagName("planeet");
        // loop through the <planet> tags 
        for (var i = 0; i < planets.length; i++) {
    
            (function(num){
    
                valDiv = document.createElement("div");
    
                // Get the id and the name from the xml info in current <planet> tag
                var id = planets[num].getElementsByTagName("id")[0].childNodes[0].nodeValue + "<br>";
                var name = planets[num].getElementsByTagName("name")[0].childNodes[0].nodeValue + "<br>";
                valDiv.innerHTML = id+"<br>"+name+"<br>";
               document.getElementById("planetenID").appendChild(valDiv);
    
                // Create button with a value and pass in this object for later reference use (valButton.object=this)
                valButton = document.createElement("input");
                //  valButton.setAttribute("planeetID", planets[i].getElementsByTagName("id")[0].childNodes[0].nodeValue);
                valButton.setAttribute("value", 'Meer info');
                valButton.setAttribute("type", 'button');
                valButton.id = (num + 1);
                valButton.object = this;    
                // FIX: PASS showinfo TO AN ANONYMOUS FUNCTION CONTAINING THE OBJECT
                valButton.addEventListener('click', function(){
                 showinfo(valButton);   
                });
                // Place the button on screen
                document.getElementById("planetenID").appendChild(valButton);
    
            }(i));
    
    
        }
    }
    
    // simple function to check if it works
    function showinfo(valButton) {
        console.log(valButton.object);
        console.log(valButton.id);
    }
    

    【讨论】:

    • 一个 IIFE 通常是解决这个问题的方法,但 showinfo 已经在作用域内,他没有在他的监听器中使用 i。你能解释一下为什么 IIFE 是这里的解决方案吗?
    • 这仍然不能解决OP的问题,问题是OP每次设置planetenID元素innerHTML时都会有效地破坏事件监听器
    • 非常感谢,这解决了问题。
    • 我在哪里可以找到更多关于 (function(num){ ... }(i)); 的信息你在这里使用的方法或函数,它解决了我的问题,但我还不明白这里发生了什么。
    • 这称为IIFE。我想,更清楚的是这个post here
    猜你喜欢
    • 2019-11-17
    • 1970-01-01
    • 2017-02-20
    • 1970-01-01
    • 2013-12-08
    • 1970-01-01
    • 1970-01-01
    • 2012-02-13
    • 2019-03-18
    相关资源
    最近更新 更多