Vue-chartjs 传入chartData作为prop时首次加载不渲染,仅窗口resize后正常显示
问题产生原因
- 时序错位:子组件
mounted钩子执行渲染逻辑时,父组件的setChartsTimesheets数据填充方法还未执行完成,此时传入的chartData是空结构,首次渲染没有有效内容。 - 深层属性修改无法触发响应式重绘:父组件更新
chartData时,是直接修改对象内部嵌套数组的元素(如push操作修改labels、datasets[0].data等属性),而vue-chartjs自带的reactiveProp混入默认仅做浅层监听,无法捕获到深层属性的变更,因此数据更新后图表不会主动刷新。 - 调整窗口时触发了Chart.js内置的
resize重绘逻辑,此时chartData已经填充完成,所以图表会正常显示。
解决方案
方案1(优先推荐):父组件控制子组件渲染时机
等chartData数据填充完成后再渲染子组件,避免空数据渲染的问题:
- 父组件新增加载状态标识:
data() { return { chartLoaded: false, // 其余原有属性不变 } }
- 父组件
setChartsTimesheets方法执行完成后修改加载状态:
setChartsTimesheets() { // 原有逻辑不变 this.chartLoaded = true }
- 父组件模板中通过
v-if控制子组件渲染:
<v-container> <ProjectDoughnutChart v-if="chartLoaded" :chart-data="chartData" /> </v-container>
方案2:子组件开启深层监听主动重绘
在子组件中新增watch深层监听chartData变化,主动触发图表更新:
// 子组件新增watch配置 export default { extends: Doughnut, mixins: [reactiveProp], mounted() { this.render(); }, watch: { chartData: { deep: true, handler() { // 图表已实例化则调用update,否则执行首次渲染 if (this.$data._chart) { this.$data._chart.update() } else { this.render() } } } }, methods: { // 原有render方法不变 } }
方案3:父组件替换整个chartData对象触发响应式
修改父组件的数据更新逻辑,不直接修改原chartData的内部属性,而是构造全新的chartData对象再赋值,触发reactiveProp的浅层监听:
setChartsTimesheets() { // 构造全新的chartData对象 const newChartData = { labels: [], datasets: [ { backgroundColor: [], hoverBackgroundColor: [], data: [], }, ], } this.timesheets.forEach((timesheet) => { let typeTotal = 0; this.timesheets .filter((timesheet1) => timesheet1.type==timesheet.type) .forEach((timesheet1) => { typeTotal+=timesheet1.billableAmount; }); if (newChartData.labels.indexOf(timesheet.type) === -1) { let colors = this.getTaskColors(timesheet.type); newChartData.labels.push(timesheet.type); newChartData.datasets[0].data.push(typeTotal); newChartData.datasets[0].backgroundColor.push(colors.color); newChartData.datasets[0].hoverBackgroundColor.push(colors.hover); } }); // 替换整个对象触发响应式更新 this.chartData = newChartData },
内容的提问来源于stack exchange,提问作者MVT KVM
相关产品推荐
相关产品推荐

