我将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元素)。我在这里做错了什么?
答案 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);
};
});
}