使用for循环附加onclick方法

时间:2014-01-06 16:03:38

标签: javascript object onclick apply

我将onclick事件附加到我正在动态创建的元素上。我正在使用下面的代码,这只是重要的部分。

Test.prototype.Show= function (contents) {
    for (i = 0; i <= contents.length - 1; i++) {
         var menulink = document.createElement('a');
         menulink.href = "javascript:;";
         menulink.onclick = function () { return that.ClickContent.apply(that, [contents[i]]); };
    }
}

首先它说它未定义。然后我改变并添加:

var content = content[i];
menulink.onclick = function () { return that.ClickContent.apply(that, [content]); };

现在发生的事情是它总是将最后一个元素附加到所有onclick事件(aka元素)。我在这里做错了什么?

1 个答案:

答案 0 :(得分:2)

这是一个经典问题。调用回调时,循环结束,因此i的值为content.length

以此为例:

Test.prototype.Show= function (contents) {
    for (var i = 0; i < contents.length; i++) { // no need to have <= and -1
         (function(i){ // creates a new variable i
           var menulink = document.createElement('a');
           menulink.href = "javascript:;";
           menulink.onclick = function () { return that.ClickContent.apply(that, [contents[i]]); };
         })(i);
    }
}

这个立即调用的函数为新变量i创建一个范围,其值因此受到保护。

更好的是,将处理程序的代码分离成一个函数,既清晰又避免不必要地创建和丢弃构建器函数:

Test.prototype.Show = function (contents) {
    for (var i = 0; i <= contents.length - 1; i++) {
        var menulink = document.createElement('a');
        menulink.href = "javascript:;";
        menulink.onclick = makeHandler(i);
    }

    function makeHandler(index) {
        return function () {
            return that.ClickContent.apply(that, [contents[index]]);
        };
    }
};

如果您不需要compatibility with IE8,完全避免此问题的方法是使用forEach引入范围,而不是使用for循环:

Test.prototype.Show = function (contents) {
  contents.forEach(function(content) {
    var menulink = document.createElement('a');
    menulink.href = "javascript:;";
    menulink.onclick = function() {
      return that.ClickContent.call(that, content);
    };
  });
}