关于javascript:在循环中添加addEventListener()仅适用于最后一个按钮

Adding addEventListener() in loop only works for last button

我从dynamodb获得了一个json数组,并在遍历它时向一个按钮添加了一个addEventListener()。 但只有最后一个按钮才能响应。

之前已经在SO上询问过这是谷歌的第一次打击所以我改变了循环以使用闭包。 但我仍然无法将addEventListener()附加到最后一个按钮以外的其他按钮。

我最初尝试过这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for (var i = 0; i < array_length; ++i) {
    (function(j) {
        var obj = data.Items[j];

        adiv.innerHTML = adiv.innerHTML +"" + obj.Event +"," + obj.Location +"";
        adiv.innerHTML = adiv.innerHTML +"" + obj.Date +"," + obj.Time +"";
        adiv.innerHTML = adiv.innerHTML +"<button id='yay_button_" + i +"' class='button-primary'>Deltag</button>";

        var elem = document.getElementById('yay_button_' + j);
        elem.addEventListener('click', function() {
            alert('id: ' + j);
        });
    })(i);
}

然后是这个较短的版本:

1
2
3
4
5
(function(j) {
    document.getElementById('yay_button_' + j).addEventListener('click', function() {
        alert('id: ' + j);
    });
}(i));

我尝试的另一个变体是使用new创建一个按钮:

1
2
3
4
5
6
7
function Button(id, number) {
    document.getElementById(id + number).addEventListener('click', function() {
        alert('click: ' + id + number);
    });
}

new Button('yay_button_', i);

我在el capitan上尝试了safari和chrome,没有错误。 当我检查它时,按钮具有正确的id,yay_button_0和_1。


主要问题是每次迭代时都会重新定义adiv的HTML。 这意味着您已经绑定到adiv的子元素的任何事件处理程序在您执行adviv.innerHTML = ...时都会丢失。 虽然您分配了相同的HTML加上一些新的HTML,但您不会分配先前定义的事件处理程序。 所以他们迷路了。

只有在最后一次迭代时分配的事件处理程序才会以这种方式销毁。

一个快速的解决方案是首先循环创建所有HTML,然后执行单独的循环来分配事件处理程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// First add all the new content:
var html = adiv.innerHTML;
for (var i = 0; i < array_length; ++i) {
    var obj = data.Items[i];

    html +="" + obj.Event +"," + obj.Location +"";
    html +="" + obj.Date +"," + obj.Time +"";
    html +="<button id='yay_button_" + i +"' class='button-primary'>Deltag</button>";
}
adiv.innerHTML = html;

// Now bind the event handlers
// By using"let" instead of"var" the right value is retained
// in the handlers
for (let i = 0; i < array_length; ++i) {
    var elem = document.getElementById('yay_button_' + i);
    elem.addEventListener('click', function() {
        alert('id: ' + i);
    });
}

如果您的浏览器不支持ES2015(let),那么您可以使用bind

1
2
3
4
5
6
for (var i = 0; i < array_length; ++i) {
    var elem = document.getElementById('yay_button_' + i);
    elem.addEventListener('click', function(i) {
        alert('id: ' + i);
    }.bind(null, i));
}


通过trincot的善意建议我遍历阵列两次。 首先生成html然后应用addEventListener()。 第二次使用闭包来包含对addEventListener()的调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
for (var i = 0; i < array_length; ++i) {
    var obj = data.Items[i];

    adiv.innerHTML = adiv.innerHTML +"" + obj.Event +"," + obj.Location +"";
    adiv.innerHTML = adiv.innerHTML +"" + obj.Date +"," + obj.Time +"";
    adiv.innerHTML = adiv.innerHTML +"<button id='yay_button_" + i +"' class='button-primary'>Deltag</button>";

}

for (var i = 0; i < array_length; ++i) {
    var obj = data.Items[i];
    (function(j, event) {
        document.getElementById('yay_button_' + j).addEventListener('click', function() {
            alert('id: ' + j + ', ' + event);
        });
    }(i, obj.Event));
}