0

我正在尝试通过循环创建一堆按钮,并将循环迭代器用作每个按钮 onclick 函数的参数。

我的代码:

var testFnc = function(i) { alert("Arg: " + i); }

mainDiv.append(create_button(name, "buttonCSS", testFnc(i)));

然而,这些功能会在页面加载和按钮放置时自动调用(即我立即看到警报)。

我确信这有一些共同的设计模式。

谢谢!

4

3 回答 3

3

一种方法是,对于每个按钮,调用一个“自执行”函数来创建一个单独的函数。

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()函数代替上面的代码。)

于 2012-07-31T20:48:10.137 回答
2

注意:有关此问题的非常详细的解释,请参阅我之前对相同问题的回答

  1. 通过使用括号,您正在调用testFnc 并将其返回值传递给create_button函数,因此它当然会立即发出警报。相反,您需要传入一个实际的函数对象而不调用它。通过包装testFnc一个匿名函数 ala来做到这一点function() { testFunc(i); }。你能看到 this 如何返回一个稍后而不是立即运行的函数吗?
  2. 这本身仍然不起作用,因为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这会起作用,但是在被引用的内部函数内部并不清楚!我认为通过使用不同的变量名来避免任何混淆是更好的做法。

于 2012-07-31T20:48:32.443 回答
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-*属性,因为您可以使用attrjQuery 中的属性来访问自定义属性。这是您可以实现它的一种方式。

于 2012-07-31T20:50:03.120 回答