Javascript 变量坚持使用最后一个值覆盖第一个值

Javascript variable sticks with the last value overriding the first ones

我有显示 google 图表的功能。我想显示存储在数据库中的每一年的图表。 几个小时以来我一直困扰的问题是,例如,变量

var year

始终将最后一年作为值。

例如,如果我想显示每年(2013 年和 2014 年)的图表,它只会显示 2014 年的图表,而忽略第一年。如果我只得到2013年的数据,它显示的是2013年的数据。

好像覆盖了所有数据,只保留最后一个值

我的代码如下:

<?php 
    foreach ($anios as $anio) 
    {
        ?>
            <script type="text/javascript">
                google.load("visualization", "1", {packages:["corechart"]});
                google.setOnLoadCallback(drawChart);
        <?php

        $datos=$difusion_stats->notas_stats_anio($anio->Año);
        ?>
          var year=<?=$anio->Año?>; console.log('First, the year value is '+year);
          var data=<?=$datos?>;
          var id_chart = 'chart_'+<?=$anio->Año?>;

            function drawChart() {
                console.log('Inside the drawChart() function. Current year value is: '+year);
                console.log('Php current year value is: '+<?=$anio->Año?>);
            var data = google.visualization.arrayToDataTable(<?=$datos?>);

            var options = {
                    title: 'Distribución de notas y entrevistas en el año '+<?=$anio->Año?>,
                    legend: 'Porcentaje de los distintos tipos de eventos',
                    pieSliceText: 'texto',
                    slices : {
                        0 : {offset: 0.1}
                    },
                    /*sliceVisibilityThreshold: .2,//Para contraer el resto y poner "otro"*/
                    pieHole: 0.4,
                    backgroundColor: { fill:'transparent'},
                    tooltip: {showColorCode: true},
                    tooltip: {isHtml: true},
                    height: 400,
                    titleTextStyle: {
                        color: '#FFFFFF'
                    },
                    legendTextStyle: {
                        color: '#FFFFFF'
                    }          
                };                      

                var chart = new google.visualization.PieChart(document.getElementById(id_chart));

                chart.draw(data, options);
                /*Para hacerlo responsive: 
                function resizeHandler () {
                    chart.draw(data, options);
                }
                if (window.addEventListener) {
                    window.addEventListener('resize', resizeHandler, false);
                }
                else if (window.attachEvent) {
                    window.attachEvent('onresize', resizeHandler);
                }  

            }/*Fin de la función drawChart()*/
    </script>
        <?php
    }/*Fin del foreach PHP*/
?>

在这种情况下,生成的 javascript 代码是每年的两个代码:2013 年和 2014 年:

<script type="text/javascript">
                    google.load("visualization", "1", {packages:["corechart"]});
                    google.setOnLoadCallback(drawChart);
                          var year=2013; console.log('First, the year value is '+year);
              var data=[['tipo','Cantidad'],['nota',14],['entrevista',3]];
              var id_chart = 'chart_'+2013;

                function drawChart() {
                    console.log('Inside the drawChart() function. Current year value is: '+year);
                    console.log('Php current year value is: '+2013);
                var data = google.visualization.arrayToDataTable([['tipo','Cantidad'],['nota',14],['entrevista',3]]);

                var options = {
                        title: 'Distribución de notas y entrevistas en el año '+2013,
                        legend: 'Porcentaje de los distintos tipos de eventos',
                        pieSliceText: 'texto',
                        slices : {
                            0 : {offset: 0.1}
                        },
                        /*sliceVisibilityThreshold: .2,//Para contraer el resto y poner "otro"*/
                        pieHole: 0.4,
                        backgroundColor: { fill:'transparent'},
                        tooltip: {showColorCode: true},
                        tooltip: {isHtml: true},
                        height: 400,
                        titleTextStyle: {
                            color: '#FFFFFF'
                        },
                        legendTextStyle: {
                            color: '#FFFFFF'
                        }          
                    };                      

                    var chart = new google.visualization.PieChart(document.getElementById(id_chart));

                    chart.draw(data, options);
                    /*Para hacerlo responsive: 
                    function resizeHandler () {
                        chart.draw(data, options);
                    }
                    if (window.addEventListener) {
                        window.addEventListener('resize', resizeHandler, false);
                    }
                    else if (window.attachEvent) {
                        window.attachEvent('onresize', resizeHandler);
                    }  

                }/*Fin de la función drawChart()*/
        </script>
                            <script type="text/javascript">
                    google.load("visualization", "1", {packages:["corechart"]});
                    google.setOnLoadCallback(drawChart);
                          var year=2014; console.log('First, the year value is '+year);
              var data=[['tipo','Cantidad'],['nota',43],['entrevista',12]];
              var id_chart = 'chart_'+2014;

                function drawChart() {
                    console.log('Inside the drawChart() function. Current year value is: '+year);
                    console.log('Php current year value is: '+2014);
                var data = google.visualization.arrayToDataTable([['tipo','Cantidad'],['nota',43],['entrevista',12]]);

                var options = {
                        title: 'Distribución de notas y entrevistas en el año '+2014,
                        legend: 'Porcentaje de los distintos tipos de eventos',
                        pieSliceText: 'texto',
                        slices : {
                            0 : {offset: 0.1}
                        },
                        /*sliceVisibilityThreshold: .2,//Para contraer el resto y poner "otro"*/
                        pieHole: 0.4,
                        backgroundColor: { fill:'transparent'},
                        tooltip: {showColorCode: true},
                        tooltip: {isHtml: true},
                        height: 400,
                        titleTextStyle: {
                            color: '#FFFFFF'
                        },
                        legendTextStyle: {
                            color: '#FFFFFF'
                        }          
                    };                      

                    var chart = new google.visualization.PieChart(document.getElementById(id_chart));

                    chart.draw(data, options);
                    /*Para hacerlo responsive: 
                    function resizeHandler () {
                        chart.draw(data, options);
                    }
                    if (window.addEventListener) {
                        window.addEventListener('resize', resizeHandler, false);
                    }
                    else if (window.attachEvent) {
                        window.attachEvent('onresize', resizeHandler);
                    }  

                }/*Fin de la función drawChart()*/
        </script>

但从未显示 2013 年的图表。 :/

在这种情况下,我得到两年:2013 年和 2014 年。但是,在控制台日志消息中,我看到它通过替换为去年来覆盖 2013 年,因此消息是:

First, the year value is 2013
stats:273 After calling the setOnLoadCallback() function, the year value is 2013
stats:274 we are about to call the drawChart() function ... YEAR: 2013
stats:280 First, the year value is 2014
stats:286 After calling the setOnLoadCallback() function, the year value is 2014
stats:287 we are about to call the drawChart() function ... YEAR: 2014
**stats:290 Inside the function. Current year value is: 2014**
stats:290 Inside the function. Current year value is: 2014

2013的值被2014覆盖了,为什么会这样? 我该如何解决这个问题?

在您的代码中,您已经定义了函数 draw_chart twice.Instead 您应该定义它一次,并在 2013 年和 2014 年使用不同的参数调用它两次。

您的第二个脚本标签包含 2014 年图表的代码,覆盖 2013 年,因此它只显示 2014 年

我不知道 PHP 但问题可能出在这一行 var id_chart = 'chart_'+<?=$anio->Año?>;。所以试试 console.log(id_chart);。如果每次都打印不同,那么它应该绘制两个不同的图表,具体取决于该元素是否存在于 DOM 中。否则

尝试改变

var chart = new google.visualization.PieChart(document.getElementById(id_chart));

var span=document.createElement('span');
document.getElementById(id_chart).appendChild(span);
var chart = new google.visualization.PieChart(span);

var year 在这两种情况下都被写入全局 JS 范围。当 drawChart 函数为 运行 时,两个 var year 命令都已为 运行,因此使用 2014 年。

它将帮助您将问题减少到更小的代码集,您将看到会发生什么:

<script type="text/javascript">
google.setOnLoadCallback(drawChart);
var year=2013; console.log('First, the year value is '+year);

function drawChart() {
    console.log('Inside the drawChart() function. Current year value is: '+year);
    console.log('Php current year value is: '+2013);
}
script>
<script type="text/javascript">
google.setOnLoadCallback(drawChart);
var year=2014; console.log('First, the year value is '+year);

function drawChart() {
    console.log('Inside the drawChart() function. Current year value is: '+year);
    console.log('Php current year value is: '+2014);
}/*Fin de la función drawChart()*/
</script>
  1. 它为一个名为drawChart的函数调用了setOnLoadCallback,这个函数还不存在(但是JavaScript中的声明是"hoisted",换句话说,后面的function drawChart 被认为存在于范围的顶部,因此它有效。)
  2. 然后设置year = 2013.
  3. 然后定义了drawChart的日志语句说PHP年是2013年(因为这段代码变成了静态JS代码)以及JS的current值是多少var year 是.
  4. 然后它再次为 drawChart 调用 setOnLoadCallback。
  5. 然后设置year = 2014。这在技术上是不正确的 JS,因为它使用 var 作为一个已经存在的变量,但它仍然改变了值。
  6. 然后它用日志语句定义 drawChart,说明 PHP 年份是 2014(再次静态)。
  7. 当"callback"设置为onLoadCallback运行s(既运行after以上所有定义,向上到 #6,已完成),它使用 drawChart 的预期值(因为它是在 setOnLoadCallback 运行s 时计算的)。但是当那个函数是运行时,它使用year.
  8. 最新

要解决此问题,您需要确保每个回调都有一个 永久 引用您想要 运行 的年份。

解决方案 1: 删除 "year" 变量并将值直接嵌入(来自 PHP)每个 "drawChart" 函数:

google.setOnLoadCallback(function() {
    var id_chart = 'chart_'+<?=$anio->Año?>;
    var year=<?=$anio->Año?>; console.log('First, the year value is '+year);
    var data = <?= $difusion_stats->notas_stats_anio($anio->Año); ?>;
    console.log('Inside the drawChart() function. Current year value is: '+year);
    console.log('Php current year value is: '+<?=$anio->Año?>);
    // ...
}

这使用 "anonymous function" 来确保 每个设置为回调的函数都是唯一的

它还确保 JS var 声明在函数范围内,因此它们不会相互影响。

解决方案 2: 创建单个 drawChart 函数并使用参数调用它。

<script type="text/javascript">
    google.load("visualization", "1", {packages:["corechart"]});
    function getDrawChartFunction(year, data) {
        return function() {
            console.log('Inside the drawChart() function. Current year value is: '+year);
            var data = google.visualization.arrayToDataTable(data);

            var options = {
                title: 'Distribución de notas y entrevistas en el año '+ year
                //, ...
            };

            var chart = new google.visualization.PieChart(document.getElementById('chart_'+year));

            chart.draw(data, options);
        }; // End of return of *anonymous function closure*
    }

<?php 
    foreach ($anios as $anio) 
    {
        $datos=$difusion_stats->notas_stats_anio($anio->Año);
        ?>
        <script type="text/javascript">
            google.load("visualization", "1", {packages:["corechart"]});
            google.setOnLoadCallback(getDrawChartFunction(
               <?=$anio->Año?>,
               <?=$datos?>
            ));
        </script>
    <?
    }
?>

这个解决方案也使用了一个匿名函数,但是这次,它returns一个匿名闭包,每次使用不同的参数叫.

有关“What is a closure?

的帮助,请参阅我在程序员上的回答

记住:

无论哪种情况,您都需要确保调用 "google.setOnLoadCallback" 的 运行 代码是 运行 之后的 ("asynchronously",在图书馆 and/or 页的 "load" 之后 运行。

这意味着您在 运行 时更改了值。

要解决此类问题,您需要确保以某种方式绘制图表的函数 "remembers" 设置它们时需要的值。

您可以通过将值直接嵌入到一个独特的函数中,或创建一个指向正确值的 JavaScript 函数(闭包所做的)来实现这一点。