在处理事件监听器时,如何使IIFE记住**变量的每个**实例?

时间:2017-01-14 03:21:39

标签: javascript iife

我正在处理可能会更改数量的图像列表,因此固定ID和事件侦听器不实用。下面的代码生成具有正确ID的正确数量的按钮,但只有最后一个具有功能事件监听器。

for (var i = 0; i < amount; i++) {
    !function(index) {

        if (items[index].classList.contains('current')) {
            document.getElementById('selectButtons').innerHTML += '<button id=\"bitems' + index + '\"> ⬤ <span class=\"offscreen\">Item ' + i + '</span></button>';
        } 
        else
        {
            document.getElementById('selectButtons').innerHTML += '<button id=\"bitems' + index + '\"> ◯ <span class=\"offscreen\">Item ' + i + '</span></button>';
        }

        document.getElementById('bitems' + index).addEventListener("click", function(ev) {
        alert("clicked");
        });

    }(i);
}

显然,IIFE并没有按照预期存储个别变量,但我无法弄清楚原因。毕竟,这就是循环中IIFE的全部目的。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:2)

IIFE工作正常。实际上,每次更新selectButtons的innerHTML时,都会重新创建DOM,并且附加到它的所有事件都会消失!

您可以将按钮添加到其中,而不是在每次迭代中更新innerHTML,而不是:

for (var i = 0; i < 10; i++) {
  !function(index) {
    var button = document.createElement("BUTTON");
    var t = document.createTextNode("Button" + index);
    button.appendChild(t);
    document.getElementById('selectButtons').appendChild(button);

    button.addEventListener("click", function(ev) {
      alert("clicked +" +index);
    });

  }(i);
}

请添加您需要的条件。

答案 1 :(得分:1)

每次执行innerHTML +=时,您将替换整个HTML,从而删除以前安装的所有事件处理程序。这是一个很好的理由,不将HTML视为您innerHTML到页面上的一串字符串。而不是字符串,从元素的角度思考,如在另一个答案中。那么你也不需要将ID用作穷人的变量名&#34;参考元素;你可以使用元素本身。

你不需要笨拙的IIFE。这是let的用途。

以下是您的代码的清理版本:

var buttons = document.getElementById('selectButtons');

for (let i = 0; i < amount; i++) {
  var current = items[i].classList.contains('current');
  var button = document.createElement("BUTTON");
  var bullet = document.createTextNode(current ? '◯' : '⬤')
  var span = document.createElement('span');
  van spanText = `Item ${i}`;

  span.className = 'offscreen';
  span.appendChild(spanText);
  button.appendChild(bullet);
  button.appendChild(span);
  buttons.appendChild(button);

  button.addEventListener('click', () => alert(`clicked ${i}`));
}

如果你想保存一两行,你可以利用appendChild返回附加子项和链的事实:

buttons.appendChild(button).appendChild(span).appendChild(spanText);

如果您要做很​​多事情,最好创建一些微小的实用程序:

function createElementWithText(tag, text) {
  var b = document.createElement(tag);
  var t = document.createTextNode(text);

  b.appendChild(t);
  return b;
}

function button(text) { return createElementWithText('button', text); }
function span(text)   { return createElementWithText('span', text); }

现在,您可以更简洁地编写代码:

var buttons = document.getElementById('selectButtons');

for (let i = 0; i < amount; i++) {
  var current = items[i].classList.contains('current');
  var button  = button(current ? '◯' : '⬤');
  var span    = span(`Item ${i}`);

  span.className = 'offscreen';
  buttons.appendChild(button).appendChild(span);

  button.addEventListener('click', () => alert(`clicked ${i}`));
}

实际上,创建一个文档片段,提前添加所有按钮,然后将其一次插入DOM中,会更为合适。

然而,在实践中,你最好使用某种模板语言,你可以写下这样的语言:

<div id="selectButtons">
  {{for i upto amount}}
    <button {{listen 'click' clicked}}>
      {{if items[i] hasClass 'current'}}◯{{else}}⬤{{endIf}}
      <span class="offscreen">Index {{i}}</span>
    </button>
  {{endFor}}
</div>

推荐特定的模板语言超出了本答案的范围。有很多很好的,比如Mustache,谷歌可以帮助你找到,通过搜索,例如&#34; javascript模板语言&#34;。