使用带有 args 的 onclick 处理程序克隆

clone with onclick handler with args

我正在克隆一个元素,该元素将有一个 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>

我做错了什么??

这是您在 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 循环 运行s,你的变量 imageid 在循环的每次迭代中被设置为一个新值,当循环是完成后,变量将保存循环 .

最后一次迭代的值

(再读一遍粗体部分)

然后,在未来的某个时间,您的用户点击图像,您的点击处理程序调用函数 selectAction 并传递 id。好吧,如果你再次阅读 粗体 中的文本,你的 id 变量将保存你的 [=15] 的最后一次迭代的 值=]循环.

(再读一遍粗体部分)

为了说明这个问题,让我们把它分解到最简单的部分。将此代码复制到您的控制台:

for (var i = 0; i < 5; i++) {
    var someVar = i;
    setTimeout(function () {
        console.log("The value of 'someVar' is " + someVar);
    }, i * 300);
}

看看someVar怎么每次都等于4。这就是你问题的症结所在。

要解决您的问题,您可以像这样使用 "bind" 函数:

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);
}