【问题标题】:Adding addEventListener iteratively迭代添加 addEventListener
【发布时间】:2020-05-10 00:17:25
【问题描述】:

我正在尝试创建歌曲播放列表。为了创建播放列表,我创建了一个名为 checklist() 的更新函数。它接收一个名为playlist 的当前播放列表中歌曲的数组参数。我还想添加一个删除按钮,它指的是播放列表中的每首歌曲。但是,以迭代方式添加 addEventListener 只会将功能添加到最后迭代的项目。我猜事件监听器每次迭代都会被覆盖,这是一个常见的错误,但我似乎无法弄清楚如何修复它。感谢您的帮助!

function checklist(playlist){
    for (var i = 0; i < playlist.length; i++){
         var j = i+1;
         document.getElementById("list").innerHTML += '<button id="removebtn'+j+'"></button>'
         document.getElementById("removebtn"+j).addEventListener("click", function () {
              delete playlist[i];
              console.log("deleted");
         });
    };
}

我已经尝试过: 如下所述解决关闭问题:JavaScript closure inside loops – simple practical example

我还尝试通过以编程方式添加代码来解决问题:Adding code to a javascript function programmatically

【问题讨论】:

标签: javascript


【解决方案1】:

closure solutions you already tried 结合@random 关于不使用innerHTML 的建议应该适合您。例如,您可以使用let 来定义本地范围:

function checklist(playlist){
    for (let i = 0; i < playlist.length; i++){
        let button = document.createElement("button");
        button.innerHTML = `Remove item ${i+1} - ${playlist[i]}`;
        button.addEventListener("click", e => {
            playlist.splice(i, 1);
            console.log("deleted", i, "playlist:", playlist);
            button.remove();
        });
        document.getElementById('list').appendChild(button);
    };
}
checklist(['one', 'two', 'three']);
&lt;div id="list"&gt;&lt;/div&gt;

但是还有一个额外的问题是,在您从播放列表中删除一个项目后,后面项目的索引将被设置回一个并且您的按钮将不再引用正确的项目。要更正此问题,您可以改为使用某种 ID 来标识播放列表中的项目,或者您可以在函数中添加索引列表:

function checklist(playlist){
  let indices = [];
  for (let i = 0; i < playlist.length; i++){
        indices.push(i);
        let button = document.createElement("button");
        button.innerHTML = `Remove item ${i+1} - ${playlist[i]}`;
        button.addEventListener("click", e => {
            let j = indices.indexOf(i);
            playlist.splice(j, 1);
            indices.splice(j, 1);
            console.log("deleted", i, "playlist:", playlist, "indices:", indices);
            button.remove();
        });
        document.getElementById('list').appendChild(button);
    };
}
checklist(['one', 'two', 'three']);
&lt;div id="list"&gt;&lt;/div&gt;

【讨论】:

    【解决方案2】:

    每次更改 innerHTML 时,它都会重建后代或子元素(即使您附加它)。因此,之前添加的监听器将不复存在。

    改为使用appendChild

    const list = document.querySelector('#list');
    
    function checklist(playlist){
        for (var i = 0; i < playlist.length; i++){
             var j = i+1;
             const button = document.createElement('button');
             button.id = "removebtn"+j;
             button.textContent = "Button"+j;
             button.addEventListener('click', function() {
                this.remove();
             });
             list.appendChild(button);
        };
    }
    
    checklist(["a", "b"]);
    &lt;div id="list"&gt;&lt;/div&gt;

    【讨论】:

      【解决方案3】:

      您需要使用 jQuery.index() 之类的方法在数组中找到正确的元素。由于这被标记为纯js问题,我将演示如何做到这一点

      function getIndex(elem) {
        var parent = elem.parentNode;
        for (var x = 0; x < parent.childNodes; x++) {
          if (parent.childNodes[x] == elem) return x;
        }
        return -1; // shouldn't be possible, but good defensive coding
      }
      

      然后,在你的 removebtn 函数中

           document.getElementById("removebtn"+j).addEventListener("click", function (e) {
              var index = getIndex(e.target);
                delete playlist[index];
                console.log("deleted");
           });
      };
      

      e.target 可能不是从中获取索引的正确节点(您可能需要 e.target.parentNode),但想法是它为您提供了播放列表中的相对位置

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-18
        • 2020-08-09
        • 2016-01-29
        • 2012-08-27
        • 2015-05-14
        相关资源
        最近更新 更多