You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue调用Chart.js的update()出现栈溢出错误:原因与解决方法

Vue中Chart.js图表update触发栈溢出的问题解决

错误原因

你遇到的栈溢出是因为无限循环触发watch监听:

  1. 创建Chart时直接传入了props的this.data(对象是引用类型),Chart调用update()时会修改这个对象的内部属性;
  2. 由于Vue单向数据流的特性,子组件修改props对象的属性会同步到父组件的数据源,父组件随即把更新后的data重新传给子组件;
  3. 这又触发了watch的监听回调,再次调用this.myChart.update(),循环往复直到调用栈耗尽。

修复方法

方法1:切断Chart与props数据的引用关系

创建Chart时传入this.data的深拷贝,让Chart内部操作的是独立副本,不会影响原props数据:

mounted() {
  const progressChart = new Chart(document.getElementById("progress-chart"), {
    type: 'line',
    // 深拷贝props的data,切断引用
    data: JSON.parse(JSON.stringify(this.data)),
    options: { /* 你的配置项 */ }
  });
  this.myChart = progressChart;
}

方法2:在watch中手动更新Chart数据

监听props数据变化时,先将新数据深拷贝后赋值给Chart的data,再调用update,避免修改原props:

watch: {
  data(newData) {
    // 更新Chart的数据源为新数据的副本
    this.myChart.data = JSON.parse(JSON.stringify(newData));
    this.myChart.update();
  }
}

方法3:配置watch的深度监听与执行时机

如果props的data是多层嵌套对象,需要开启深度监听,同时确保回调在DOM更新后执行,避免重复触发:

watch: {
  data: {
    deep: true,
    flush: 'post',
    handler(newData) {
      this.myChart.data = JSON.parse(JSON.stringify(newData));
      this.myChart.update();
    }
  }
}

从watch/methods访问mounted内图表实例的其他方案

除了把实例存在data里,还有几种更灵活的方式:

  • 挂载到组件实例自定义属性:不用把实例放在响应式的data中,直接挂载到this上,减少Vue响应式处理的开销:

    mounted() {
      const progressChart = new Chart(/* 配置 */);
      this.$chartInstance = progressChart; // 自定义属性存储实例
    }
    // watch中调用
    watch: {
      data() {
        this.$chartInstance.update();
      }
    }
    
  • 封装初始化方法,销毁重建图表:数据变化时销毁旧实例,重新创建新图表,避免引用问题:

    methods: {
      createChart() {
        // 先销毁旧实例,避免内存泄漏
        if (this.myChart) {
          this.myChart.destroy();
        }
        this.myChart = new Chart(document.getElementById("progress-chart"), {
          type: 'line',
          data: JSON.parse(JSON.stringify(this.data)),
          options: { /* 配置项 */ }
        });
      }
    },
    mounted() {
      this.createChart();
    },
    watch: {
      data: {
        deep: true,
        handler() {
          this.createChart();
        }
      }
    }
    
  • 使用Vue的$refs获取DOM元素(可选):如果需要更灵活的DOM控制,可以用$refs代替document.getElementById,同时存储实例:

    <canvas ref="progressChart"></canvas>
    
    mounted() {
      const progressChart = new Chart(this.$refs.progressChart, { /* 配置 */ });
      this.myChart = progressChart;
    }
    

完整修复后的代码示例

<script>
import Chart from 'chart.js/auto';
export default {
  name: 'ChartTest',
  props: {
    data: Object,
    title: String,
  },
  data() {
    return {
      myChart: null // 初始化为null更合理
    }
  },
  watch: {
    data: {
      deep: true,
      handler(newData) {
        this.myChart.data = JSON.parse(JSON.stringify(newData));
        this.myChart.update();
      }
    }
  },       
  mounted() {
    const progressChart = new Chart(document.getElementById("progress-chart"), {
      type: 'line',
      data: JSON.parse(JSON.stringify(this.data)),
      options: {
        plugins: {
          title: {
            display: true,
            text: this.title
          }
        },
        scales: {
          y: {
            display: true,
            stacked: true,
            max: 0,
            min: 100,
            title: {
              display: true,
              text: 'Your Score (%)'
            }
          }
        }
      }
    });
    this.myChart = progressChart;
  }     
}
</script>

内容的提问来源于stack exchange,提问作者user121443

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 07:05:52