在处理事件侦听器时,如何让 IIFE 记住变量的**每个**实例?
How do you make an IIFE remember **each** instance of a variable when dealing with event listeners?
我正在处理数量可能会发生变化的图像列表,因此固定 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 的全部目的。
如有任何帮助,我们将不胜感激。
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);
}
请务必添加您需要的条件。
每次执行 innerHTML +=
时,您都在替换整个 HTML,这会删除所有以前安装的事件处理程序。这是不将 HTML 视为您 innerHTML
到页面上的一堆字符串的一个很好的理由。正如在另一个答案中那样,而不是字符串,而是考虑元素。那么你也不需要像穷人的"variable name"一样使用ID来引用元素;您可以只使用元素本身。
您不需要笨拙的 IIFE。这就是 let
的目的。
这是您的代码的 cleaned-up 版本:
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
returns 附加的 child 和链:
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,google 可以帮助您找到,搜索 "javascript templating languages".
我正在处理数量可能会发生变化的图像列表,因此固定 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 的全部目的。
如有任何帮助,我们将不胜感激。
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);
}
请务必添加您需要的条件。
每次执行 innerHTML +=
时,您都在替换整个 HTML,这会删除所有以前安装的事件处理程序。这是不将 HTML 视为您 innerHTML
到页面上的一堆字符串的一个很好的理由。正如在另一个答案中那样,而不是字符串,而是考虑元素。那么你也不需要像穷人的"variable name"一样使用ID来引用元素;您可以只使用元素本身。
您不需要笨拙的 IIFE。这就是 let
的目的。
这是您的代码的 cleaned-up 版本:
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
returns 附加的 child 和链:
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,google 可以帮助您找到,搜索 "javascript templating languages".