我正在克隆一个元素,该元素将有一个onclick处理程序。该事件处理程序将作为参数发送ID。 我的问题是当我点击元素时,他会发送cicle的最后一个ID。
这是我的javascript代码:
function cloneActions(idRoutine){ //clone elements
var actionDiv = document.getElementById("actionsImages-"+idRoutine).getElementsByClassName("actionImage"); //parent with content that must be cloned
var allActions = document.getElementById("actions"); //parent div
while (allActions.firstChild) { //remove all existing imgs
allActions.removeChild(allActions.firstChild);
}
for(var i=0; i < actionDiv.length; i++){ //set all images and handlers
var image = actionDiv[i].cloneNode(true);
var id = image.id;
image.onclick = function() { selectAction(id);};
allActions.appendChild(image);
}
}
function selectAction(id){ //handler function
///jquery
}
和html代码:
<div id="actionsImages-«id»" class="tile__list actionsImages">
<img src='sortable/st/foo.jpg' class='actionImage' id=«id» title='foo'/>
</div>
我做错了什么?
答案 0 :(得分:1)
这是您在javascript中for
循环,变量提升和异步事件的教训。别担心,我们都经历过这一课。这是:
这是你的for
循环:
for(var i=0; i < actionDiv.length; i++) {
var image = actionDiv[i].cloneNode(true);
var id = image.id;
image.onclick = function() { selectAction(id);};
allActions.appendChild(image);
}
这与执行此操作相同:
var image;
var id;
for(var i=0; i < actionDiv.length; i++) {
image = actionDiv[i].cloneNode(true);
id = image.id;
image.onclick = function() { selectAction(id);};
allActions.appendChild(image);
}
这是因为variables in javascript are hoisted to the the top of their scope在运行时。这意味着您的for
循环运行,您的变量image
和id
在循环的每次迭代中都设置为新值,并且当循环完成时,变量是保持循环最后一次迭代的值。
(再次以粗体显示最后一部分)
然后,在将来的某个时间,您的用户点击图片,您的点击处理程序调用函数selectAction
并传递id
。好吧,如果您再次以粗体读取该文本,那么您的id
变量将保留for
循环的最后一次迭代中的值强>
(再次以粗体显示最后一部分)
为了说明问题,我们将它剥离到裸骨。将此代码复制到您的控制台:
for (var i = 0; i < 5; i++) {
var someVar = i;
setTimeout(function () {
console.log("The value of 'someVar' is " + someVar);
}, i * 300);
}
每次查看someVar
如何等于4。这是你问题的症结所在。
要解决您的问题,您可以使用“绑定”功能,如下所示:
var image, id, i;
for(i=0; i < actionDiv.length; i++) {
image = actionDiv[i].cloneNode(true);
id = image.id;
image.onclick = selectAction.bind(image, id)
allActions.appendChild(image);
}
我将让您了解函数绑定的工作原理here。
另一个解决方案是让你在for
循环中调用一个函数:
function doCoolStuff (i) {
var image = actionDiv[i].cloneNode(true);
var id = image.id;
image.onclick = function () { selectAction(id); };
allActions.appendChild(image);
}
for(var i=0; i < actionDiv.length; i++) {
doCoolStuff(i);
}