Vue调用Chart.js的update()出现栈溢出错误:原因与解决方法
Vue中Chart.js图表update触发栈溢出的问题解决
错误原因
你遇到的栈溢出是因为无限循环触发watch监听:
- 创建Chart时直接传入了props的
this.data(对象是引用类型),Chart调用update()时会修改这个对象的内部属性; - 由于Vue单向数据流的特性,子组件修改props对象的属性会同步到父组件的数据源,父组件随即把更新后的
data重新传给子组件; - 这又触发了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
相关产品推荐
相关产品推荐

