我正在尝试通过循环创建一组按钮,并使用循环迭代器作为每个按钮onclick函数的参数。
我的代码:
var testFnc = function(i) { alert("Arg: " + i); }
mainDiv.append(create_button(name, "buttonCSS", testFnc(i)));
然而,当页面加载并放置按钮时,会自动调用这些函数(即我立即看到警报)。
我确信这有一些常见的设计模式。
谢谢!
答案 0 :(得分:3)
一种方法是,对于每个按钮,调用一个“self-executing”函数来创建一个单独的函数。
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()
function代替上述代码。)
答案 1 :(得分:2)
注意:有关此问题的详细说明,请参阅我的previous answer to an identical question。
create_button
函数,因此它当然会立即发出警报。相反,您需要传入一个实际的函数对象而不调用它。通过将testFnc
包装在匿名函数ala function() { testFunc(i); }
中来完成此操作。你能看到这是如何返回一个稍后运行而不是立即运行的函数吗?由于i
参与了围绕它的闭包,因此它本身仍然无法正常工作,因此当点击事件运行时,它使用 i的最新值(它在循环结束时的值),而不是绑定时的值。要解决这个问题,请在另一个变量周围创建一个新的闭包 - 仅在回调的直接范围内定位,而不是更高 - 这将被赋予i
的值以便点击事件具有绑定时的值,而不是绑定函数的执行时间。
以下是如何做到这一点:
for (i = 0; i < len; i++) {
mainDiv.append(
create_button(name, "buttonCSS", (function(val) {
return function() {
testFnc(val);
};
}(i)))
);
}
我确信这看起来有点令人困惑,但关键是在另一个函数中包装被调用的函数(返回的函数)会创建一个带有变量val
的新范围。 #39; t用于任何外部功能。这使闭包仅超过立即值,将其从i
中分离出来,这就是你想要的。对此here进行了更深入的解释。
请注意,此页面上的另一个答案重复使用i
,这可能令人困惑。这将起作用,但是内部函数内部i
被引用的内部不清楚!我认为最好通过使用不同的变量名来避免混淆。
答案 2 :(得分:0)
您使用的是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-*
属性,因为您可以使用jQuery中的attr
属性来访问自定义属性。这是您可以实现它的一种方式。