在循环中使用闭包添加事件无法正常工作

时间:2015-12-22 02:32:46

标签: javascript

我遇到的实际问题就像下面的测试代码一样

我需要在一个函数中包含一堆事件加法器,并多次调用它

它生成相同的结果,即不适用于每个元素的事件

window.onload = function() {
  var body = document.body;
  var elText = '<input id="randId" type="text"/>';
  var elTmp;
  var ids = [];
  var times = 3;
  var randId = function(){
    return Math.random().toString(36).substr(2,9);
  };
  var setEvent = function(el, text) {
    el.addEventListener('click', function(e) {
      el.value = text;
    });
  };
  for (var i = 0; i < times; i++) {
    ids.push(randId());
    body.innerHTML += elText.replace('randId', ids[ids.length - 1]);
    elTmp = document.getElementById(ids[ids.length - 1]);
    setEvent(elTmp, 'this is ' + (i+1));
  }
};

甚至将这些代码包装在一个闭包中,该事件仅适用于最后创建的元素,前两个不是

请参阅此topic

  for (var i = 0; i < times; i++) {
    ids.push(randId());
    body.innerHTML += elText.replace('randId', ids[ids.length - 1]);
    elTmp = document.getElementById(ids[ids.length - 1]);
    (function(_i) {
      setEvent(elTmp, 'this is ' + (_i+1));
    })(i);
  }

3 个答案:

答案 0 :(得分:1)

问题在于每次迭代都会改变所有内部HTML。发生这种情况时,将删除所有先前的事件侦听器(因为元素已从DOM中删除)。我刚刚回答了similar question

根据MDN

  

.innerHTML - 删除所有元素的子节点,解析内容字符串并将结果节点指定为元素的子节点。

要解决此问题,您可以使用.insertAdjacentHTML() method来插入元素。在这样做时,没有触及/删除其他HTML,因为这只是插入 HTML。

Updated Example

for (var i = 0; i < times; i++) {
  ids.push(randId());
  body.insertAdjacentHTML('beforeend', elText.replace('randId', ids[ids.length - 1]));
  elTmp = document.getElementById(ids[ids.length - 1]);
  setEvent(elTmp, 'this is ' + (i+1));
}

当然,您也可以使用.appendChild() method

答案 1 :(得分:0)

当您再次呼叫innerHTML时,正文内容已被强制Event Listener会一次又一次被删除。
我认为您应该使用$('').append()中的Jquery方法添加Element

答案 2 :(得分:0)

对于解决方案,Josh Crozier answer已经存在。我只想解释一下为什么JS正在使用+=附加html时保留之前的html时删除以前的事件处理程序。仔细看看这个:

body.innerHTML += elText.replace('randId', ids[ids.length - 1]);

它实际上是以下的捷径:

body.innerHTML = body.innerHTML + elText.replace('randId', ids[ids.length - 1]);

所以,首先你得到的body.innerHTML只是一个文本字符串,没有绑定到它的事件处理程序,你用它附加新文本,之后你将其设置为{{1 }}。在那段时间,它以Josh Crozier突出显示:

  

body.innerHTML - 删除所有元素的子节点,解析内容字符串并将结果节点指定为元素的子节点。