我正在尝试通过循环创建一堆按钮,并将循环迭代器用作每个按钮 onclick 函数的参数。
我的代码:
var testFnc = function(i) { alert("Arg: " + i); }
mainDiv.append(create_button(name, "buttonCSS", testFnc(i)));
然而,这些功能会在页面加载和按钮放置时自动调用(即我立即看到警报)。
我确信这有一些共同的设计模式。
谢谢!
我正在尝试通过循环创建一堆按钮,并将循环迭代器用作每个按钮 onclick 函数的参数。
我的代码:
var testFnc = function(i) { alert("Arg: " + i); }
mainDiv.append(create_button(name, "buttonCSS", testFnc(i)));
然而,这些功能会在页面加载和按钮放置时自动调用(即我立即看到警报)。
我确信这有一些共同的设计模式。
谢谢!
一种方法是,对于每个按钮,调用一个“自执行”函数来创建一个单独的函数。
mainDiv.append(create_button(name, "buttonCSS", (function(i) {
// For the function below, i comes from
// this function's scope, not the outside scope.
return function() {
testFnc(i);
};
})(i) ));
这将允许您更改i
函数外部的值并使现有按钮不受影响。
(如果您要创建很多按钮(可能有数千个),最好更改create_button
函数以将属性添加到按钮元素本身并让您的函数进行检查。或者如果您的代码不需要在 Internet Explorer 中工作8 或以下,您可以使用bind()
函数代替上面的代码。)
注意:有关此问题的非常详细的解释,请参阅我之前对相同问题的回答。
create_button
函数,因此它当然会立即发出警报。相反,您需要传入一个实际的函数对象而不调用它。通过包装testFnc
一个匿名函数 ala来做到这一点function() { testFunc(i); }
。你能看到 this 如何返回一个稍后而不是立即运行的函数吗?这本身仍然不起作用,因为i
参与了围绕它的闭包 ,因此当点击事件运行时,它使用i 的最新值(它在循环结束时的值),而不是在绑定的时间。为了解决这个问题,围绕一个不同的变量创建一个新的闭包——只定位在你的回调的直接范围内,而不是更高的——这将被赋予valuei
以便 click 事件具有绑定时的值,而不是绑定函数的执行时间。
以下是如何执行此操作:
for (i = 0; i < len; i++) {
mainDiv.append(
create_button(name, "buttonCSS", (function(val) {
return function() {
testFnc(val);
};
}(i)))
);
}
我敢肯定这看起来有点令人困惑,但关键是将被调用的函数(返回的函数)包装在另一个函数中会创建一个新的范围,其中包含一个val
未在任何外部函数中使用的变量。这使得闭包仅覆盖直接值,将其与 分离i
,这就是你想要的。这里有更深入的解释。
请注意,此页面上的另一个答案会重复使用i
,这可能会造成混淆。i
这会起作用,但是在被引用的内部函数内部并不清楚!我认为通过使用不同的变量名来避免任何混淆是更好的做法。
你在使用 jQuery 吗?您可以引用按钮的类
<button class='my-custom-class' data-index='0'>This button</button>
并在document.ready
:
$(document).ready(function () {
buildButtons();
$('.my-custom-class').on('click', function () {
var index = $(this).attr('data-index');
alert('Arg: ' + index);
});
});
我建议使用自定义data-*
属性,因为您可以使用attr
jQuery 中的属性来访问自定义属性。这是您可以实现它的一种方式。