我尝试将 Chart.js 作为 vue 组件嵌入到我的应用程序中。
一旦我尝试向图表数据集添加新数据,我就会收到错误:
Uncaught InternalError: too much recursion
push reactivity.esm-bundler.js:798
value helpers.collection.ts:138
noTracking reactivity.esm-bundler.js:901
push reactivity.esm-bundler.js:799
value helpers.collection.ts:138
noTracking reactivity.esm-bundler.js:901
push reactivity.esm-bundler.js:799
value helpers.collection.ts:138
noTracking reactivity.esm-bundler.js:901
push reactivity.esm-bundler.js:799
value helpers.collection.ts:138
noTracking reactivity.esm-bundler.js:901
应用程序.vue
<script>
import Chart from "./Chart.vue";
export default {
name: "Chart Demo",
components: {
Chart
},
data() {
return {};
}
};
</script>
<template>
<div>
<h1>Hello World</h1>
<Chart></Chart>
</div>
</template>
图表.vue
<template>
<canvas ref="canvas"></canvas>
</template>
<script>
import { defineComponent } from "vue";
import { Chart } from "chart.js/auto";
export default defineComponent({
data() {
return {
chart: null,
chartData: {
labels: [
"Januar",
"Februar",
"März",
"April",
"Mai",
"Juni",
"Juli",
"August"
],
datasets: [{
label: "Verkäufe",
data: [60, 65, 67, 65, 66, 69, 72, 70]
}]
}
};
},
mounted() {
console.log("mounted create")
this.chart = new Chart(this.$refs.canvas, {
type: "line",
data: this.chartData
});
setInterval(() => {
console.log("Add chart data")
let d = 90
this.chartData.labels.push(d);
this.chartData.datasets[0].data.push(d);
}, 3000);
}
});
</script>
没有这部分:
setInterval(() => {
console.log("Add chart data")
let d = 90
this.chartData.labels.push(d);
this.chartData.datasets[0].data.push(d);
}, 3000);
它工作得很好。
但我想创建一个值的历史记录,我需要在图表中添加新数据并重新渲染它。
操作图表数据并重新渲染的正确方法是什么?
最小可重现示例游乐场
这是 Chart.js 的已知问题。它修补数据数组以跟踪更改,类似于 Vue(特别是 2.x)的做法,这会干扰 Vue 反应性。除了修补或扩展内置 Chart.js 控制器之外,没有其他方法可以克服这个问题。或者提供只读密封数组,但这会阻止 Vue 反应性工作。
复制并冻结整个反应数据以禁用 Chart.js 自身的反应性是无效的。如果
data
对象引用在组件生命周期中发生变化,则需要额外处理。假设 data
是一个在父组件中发生变异的 prop,并且 chart
不是反应式的,那么它将是:
created() {
this.chart = null;
},
watch: {
data: {
deep: true,
handler(newVal, oldVal) {
if (newVal !== oldVal)
this chart.data = newVal;
this.chart.update();
},
},
},
mounted() {
this.chart = new Chart(this.$refs.canvas, {
type: 'line',
data: toRaw(this.data),
});
}