jquery callback function only working on last loop

前端 未结 4 1114
我寻月下人不归
我寻月下人不归 2020-11-29 08:39
for (var i = 0; i < barValues.length; i++) {


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

    var barChartID = \"#barChart\"          


        
相关标签:
4条回答
  • 2020-11-29 09:21

    You could try caching the span selector, like so:

    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');
    });
    
    0 讨论(0)
  • 2020-11-29 09:23

    Since you are using jQuery you can use the $.each function instead of a for loop. The callback used instead of the loop will create a new closure.

    $.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);
    });
    
    0 讨论(0)
  • 2020-11-29 09:27

    This is a common problem experienced when combining closures with loops. JavaScript is a late-binding language and loops do not introduce a new scope. So:

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

    There is only one i variable in this code. It starts at 0 and once the assignment-loop is finished is left at 5. The click event on the #thing0 element is only ever going to be fired after the loop has finished executing, by which point the value of i will be 5. You will not get the define-time value 0 which you might have expected.

    This applies not only to the loop variable itself but to any other variables you are re-assigning for each time round the loop too. So in your example the value of barChartID inside the animation callback function will always be the id associated with the last element in your loop.

    The usual workaround is to take a copy of the loop variable's value at define-time by using a structure that does introduce a new scope, namely another function:

    $(barChartID + " img").animate({height: actualBarHeight}, 500, function(barChartID) {
        return function() {
            $(barChartID + " .value span").css('background-color','white');
        };
    }(barChartID));
    

    More on looped closures.

    0 讨论(0)
  • 2020-11-29 09:27

    This is because your callback function has an implicit pointer to the barChartID variable. This is just how closures work. What you want is to create a new copy of the current value of barChartID in each iteration. One pattern for fixing this is to run the body of the for loop inside a function. I saw this pattern in an except from John Resig's upcomming book Secrets of the JavaScript Ninja

    for(var i=0; i<barValues.length; i++) function(i){
        ...
    }(i);
    
    0 讨论(0)
提交回复
热议问题