Vue3(Options API)中Vue-ChartJS柱状图无法更新的问题
Vue3 Options API中vue-chartjs柱状图数据更新不显示的解决方法
问题根源分析
- 响应式检测失效:直接修改
this.data.datasets的元素(如push、filter赋值),Vue对对象/数组的深层变更检测存在限制,导致组件无法感知数据变化。 - ref调用错误:
this.$refs.chart获取的是Vue组件实例,而非ChartJS的图表实例,直接调用update()自然会报错。
具体修复步骤
1. 确保数据变更触发Vue响应式更新
修改setData方法,通过创建新对象/数组的方式更新数据,让Vue能准确检测到变化:
setData(value) { let newDatasets = [...this.data.datasets]; // 复制原数组,避免直接修改原引用 if (value.length > 0 && value.length < 5) { value.forEach(val => { if (val.selected) { const exist = newDatasets.find(el => el.label === val.label); if (!exist) { const obj = { label: val.label, data: graphData.data[this.text][val.label], backgroundColor: this.generateColor() }; newDatasets.push(obj); } } else { newDatasets = newDatasets.filter(dataset => dataset.label !== val.label); } }); } else { newDatasets = []; } // 重新赋值data对象,触发响应式更新 this.data = { ...this.data, datasets: newDatasets }; // 可选:手动触发图表更新(确保Chart实例存在) if (this.$refs.chart?.chart) { this.$refs.chart.chart.update(); } }
2. 正确调用ChartJS的update方法
如果需要手动触发图表更新,必须通过Vue组件实例的chart属性获取ChartJS实例:
// 先判断组件和chart实例是否存在,避免报错 if (this.$refs.chart && this.$refs.chart.chart) { this.$refs.chart.chart.update(); }
3. 优化key强制刷新(可选)
若上述方法仍不生效,可利用:key属性强制组件重新渲染。在setData末尾更新value的值:
this.value += 1;
4. 移除冗余计算属性
newData计算属性仅直接返回this.data,无实际作用,直接在模板中使用:data="data"即可:
<Bar ref="chart" :key="value" :data="data" :options="options" />
完整修复后的代码示例
Template部分
<template> <div> <div> <Bar ref="chart" :key="value" :data="data" :options="options" /> </div> </div> </template>
Script部分
<script> import { Bar } from 'vue-chartjs' import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, Title, Tooltip, BarElement, Legend } from 'chart.js' ChartJS.register( CategoryScale, LinearScale, PointElement, BarElement, Title, Tooltip, Legend ) import graphData from '../../data/GraphData.json' export default { components: { Bar }, data() { return { value: 1, text: 'Multikills', data: { labels: [ 'Romex Fortrex', 'OBG BotGapped', 'Hou Max', 'OBG Logic', 'OBG Thanagor' ], datasets: [ { label: 'Two', data: [15, 20, 5, 8, 15], backgroundColor: '#ADD8E6' } ] }, options: { responsive: true, maintainAspectRatio: false, elements: { line: { borderColor: 'white' } }, scales: { y: { ticks: { color: 'white', font: { family: 'MarkPro', weight: 'bold' } }, title: { display: true, color: 'white', text: 'Winrate', font: { family: 'MarkPro', size: 14, weight: 'bold' } } }, x: { ticks: { color: 'white', font: { family: 'MarkPro', weight: 'bold' } }, title: { display: true, color: 'white', text: 'Number of games', font: { family: 'MarkPro', size: 14, weight: 'bold' } } } }, plugins: { legend: { labels: { color: 'white', font: { family: 'MarkPro', weight: 'bold' } } } } } } }, methods: { setData(value) { let newDatasets = [...this.data.datasets]; if (value.length > 0 && value.length < 5) { value.forEach(val => { if (val.selected) { const exist = newDatasets.find(el => el.label === val.label); if (!exist) { const obj = { label: val.label, data: graphData.data[this.text][val.label], backgroundColor: this.generateColor() }; newDatasets.push(obj); } } else { newDatasets = newDatasets.filter(dataset => dataset.label !== val.label); } }); } else { newDatasets = []; } this.data = { ...this.data, datasets: newDatasets }; if (this.$refs.chart?.chart) { this.$refs.chart.chart.update(); } // 若仍不更新,取消注释以下代码强制刷新组件 // this.value += 1; }, generateColor() { const red = Math.floor(Math.random() * 101) + 100; const green = Math.floor(Math.random() * 101) + 100; const blue = Math.floor(Math.random() * 101) + 100; return `#${red.toString(16)}${green.toString(16)}${blue.toString(16)}`; } } } </script>
内容的提问来源于stack exchange,提问作者Ghost
相关产品推荐
相关产品推荐

