首页 > 解决方案 > 如何在 vue 中更新 chart.js

问题描述

我创建了一个 chart.js vue 组件,它使用一些通过道具传递给它的数据进行渲染。现在我希望能够在数据发生变化时调用图表上的 update() 方法。我的问题是,由于我的代码的结构方式我无法执行通常的 chart.update() 方法,因为我无法从创建它的函数外部访问图表变量。我该如何重组我的代码以便我可以调用图表上的更新方法?

在数据发生变化的那一刻,我只调用初始渲染函数,这会导致图表彼此分层。当您更改数据然后将鼠标悬停在图表上时,可以看到这一点。

Vue.component('chart', {
    template: '<canvas id="chart"></canvas>',
    props: {
        savings: Object,
    },
    watch: { 
        savings: {
            deep: true,
            handler() {
                console.log('Update Chart');
                this.createChart();
            }
        }
    },
    methods: {
        createChart() {
            new Chart(document.getElementById("chart"), {
                type: 'bar',
                data: {
                    datasets: [{
                        label: 'Bar Dataset',
                        data: [
                        	this.savings.annual[0], 
                            this.savings.annual[1], 
                            this.savings.annual[2], 
                            this.savings.annual[3],
                            this.savings.annual[4]
                        ]
                    }, {
                        label: 'Line Dataset',
                        data: [
                        	this.savings.cumulative[0], 
                            this.savings.cumulative[1], 
                            this.savings.cumulative[2], 
                            this.savings.cumulative[3],
                            this.savings.cumulative[4]
                        ],
                        type: 'line'
                    }],
                    labels: ['Year One', 'Year Two', 'Year Three', 'Year Four', 'Year Five']
                }
            });
        }
    },
    mounted() {
        this.createChart();
        console.log(this.totals);
    }
});

var app1 = new Vue({
    el: '#savings_calculator',
    data: {
        savings: {
        	annual: [123,345,234,234,523],
            cumulative: [234,523,234,423,100],
        }
    },
    methods: {
    	changeData() {
        	for(let i = 0; i < 5; i++) {
            	Vue.set(this.savings.annual, i, Math.floor((Math.random() * 1000) + 1));
                Vue.set(this.savings.cumulative, i, Math.floor((Math.random() * 1000) + 1));
            }
        	
        }
	}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="savings_calculator">
    <div class="input container">
        <button v-on:click="changeData">Change Data</button>
        <chart 
            v-bind:savings="savings"
        />
    </div>
</div>

我在 WordPress 中工作,我通过将代码复制到我的一个 js 文件中包含了 chart.js 库,这些文件都被 gulp 缩小并压缩到一个文件中。我之所以提到这一点,是因为我见过人们使用 import 来包含库的示例。我确实将库下载到我的 node_modules 中,但我无法让导入在我的 js 文件中工作。它给了我以下错误:

“Uncaught SyntaxError: Cannot use import statement outside a module” 

标签: javascriptvue.jschart.js

解决方案


发生此问题主要是因为您canvas在调用该createChart()方法时在同一个图表上绘制了多个图表。您只需要调用该.destroy()方法来销毁任何已创建的图表实例。这将清除存储在 Chart.js 中的图表对象的所有引用,以及 Chart.js 附加的任何关联事件侦听器。这必须在画布重新用于新图表之前调用。

因此,只需添加一个新的数据选项来存储当前图表实例,例如:

data(){
  return{
    chart: null
  }
},

然后存储图表实例,如:

 createChart() {
    this.chart = new Chart(document.getElementById("chart"), {
    ...

watch在调用this.createChart();使用之前在里面:

  this.chart.destroy();
  this.createChart();

工作演示:

Vue.component('chart', {
  template: '<canvas id="chart"></canvas>',
  props: {
    savings: Object,
  },
  data(){
    return{
      chart: null
    }
  },
  watch: {
    savings: {
      deep: true,
      handler() {
        console.clear();
        console.log('Update Chart');
        this.chart.destroy();
        this.createChart();
      }
    }
  },
  methods: {
    createChart() {
      this.chart = new Chart(document.getElementById("chart"), {
        type: 'bar',
        data: {
          datasets: [{
            label: 'Bar Dataset',
            data: [...this.savings.annual]
          }, {
            label: 'Line Dataset',
            data: [...this.savings.cumulative],
            type: 'line'
          }],
          labels: ['Year One', 'Year Two', 'Year Three', 'Year Four', 'Year Five']
        }
      });
    }
  },
  mounted() {
    this.createChart();
    //console.log(this.totals);
  }
});

var app1 = new Vue({
  el: '#savings_calculator',
  data: {
    savings: {
      annual: [123, 345, 234, 234, 523],
      cumulative: [234, 523, 234, 423, 100],
    }
  },
  methods: {
    changeData() {
      for (let i = 0; i < 5; i++) {
        Vue.set(this.savings.annual, i, Math.floor((Math.random() * 1000) + 1));
        Vue.set(this.savings.cumulative, i, Math.floor((Math.random() * 1000) + 1));
      }

    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="savings_calculator">
  <div class="input container">
    <button v-on:click="changeData">Change Data</button>
    <chart v-bind:savings="savings" />
  </div>
</div>


推荐阅读