jquery回调函数仅适用于最后一个循环

时间:2009-10-13 18:35:54

标签: jquery callback

    for(var i=0; i<barValues.length; i++) {


    actualBarHeight = Math.floor((barValues[i]/chartMaxY)*barchartHeight);

    var barChartID = "#barChart" + (i+1)
    $(barChartID + " .value span").css('background-color','transparent');
    $(barChartID + " img").animate({ 
            height: actualBarHeight
        }, 500, function(){$(barChartID + " .value span").css('background-color','white');}
    );

    $(barChartID + " .value span").html("$"+Math.floor(barValues[i]));
    $(barChartID + " .value").css("bottom",actualBarHeight+"px");
    $(barChartID + " .ylabel").html(chartMaxY);

};

上面的jQuery位于for循环中。循环的每次迭代都执行以下操作:

  • 设置范围的背景
  • 动画对象
  • 完成后,重置跨度的背景

我正在使用回调功能重置背景,因此在完成动画之前完成动画。但是,它最终只会影响for循环中引用的最后一个span。

如果我在回调之外移动那段代码,那么它会在for循环的每次迭代中影响每个跨度,但是在这种情况下不会等待动画。

我猜这个问题与构建选择器INSIDE函数INSIDE animate函数有关。我的标记中是否有一些错误的语法?

编辑(根据Russ的建议,我现在在上面的示例中包含完整的循环)

4 个答案:

答案 0 :(得分:16)

这是将闭包与循环组合时遇到的常见问题。 JavaScript是一种后期绑定语言,循环不会引入新的范围。所以:

for (var i= 0; i<5; i++) {
    $('#thing'+i).click(function() {
        alert(i);
    });
}

此代码中只有一个i变量。它从0开始,一旦完成赋值循环,就保留在5。 {/ 1}}元素上的click事件只有在循环执行完毕后才会被触发,此时#thing0的值将为i 。您将无法获得您可能期望的定义时间值5

这不仅适用于循环变量本身,也适用于每次循环时重新分配的任何其他变量。因此,在您的示例中,动画回调函数中0的值将始终是与循环中最后一个元素关联的id。

通常的解决方法是使用 引入新范围的结构,即在另一个函数中,在define-time获取循环变量值的副本:

barChartID

More on looped closures.

答案 1 :(得分:4)

这是因为你的回调函数有一个指向barChartID变量的隐式指针。这就是闭包的工作原理。您想要的是在每次迭代中创建barChartID的当前值的新副本。解决此问题的一种模式是在函数内运行for循环的主体。除了John Resig的推荐书 JavaScript Ninja的秘密之外,我看到了这种模式

for(var i=0; i<barValues.length; i++) function(i){
    ...
}(i);

答案 2 :(得分:3)

由于您使用的是jQuery,因此可以使用$ .each函数而不是for循环。使用回调而不是循环将创建一个新的闭包。

$.each(barValues, function(i, barValue){
    actualBarHeight = Math.floor((barValue/chartMaxY)*barchartHeight);

    var barChartID = "#barChart" + (i+1)
    $(barChartID + " .value span").css('background-color','transparent');
    $(barChartID + " img").animate({ 
                    height: actualBarHeight
            }, 500, function(){$(barChartID + " .value span").css('background-color','white');}
    );

    $(barChartID + " .value span").html("$"+Math.floor(barValue));
    $(barChartID + " .value").css("bottom",actualBarHeight+"px");
    $(barChartID + " .ylabel").html(chartMaxY);
});

答案 3 :(得分:0)

您可以尝试缓存范围选择器,如下所示:

var barChartID = "#barChart" + (i+1)
var span = $(barChartID + " .value span");
span.css('background-color','transparent');
$(barChartID + " img").animate({ 
    height: actualBarHeight
}, 500, function() {
    span.css('background-color','white');
});