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

Vue3 + vue-chartjs/chart.js服务端编译报错:无法读取labels属性

问题

本地环境运行一切正常,但项目在服务端编译时,vue-chartjs与chart.js库出现报错:TypeError: Cannot read properties of undefined (reading 'labels')。经测试错误出现在组件层面,所有Props(包括服务端环境下)均已正确传入组件,进入库之前所有内容都正常,但组件无法构建,图表无法正常渲染。

组件代码如下:

<template>
    <Line v-if="chartType === 0"
        :chart-options="chartOptions"
        :chart-data="chartData"
        :chart-id="chartId"
        :dataset-id-key="datasetIdKey"
        :plugins="plugins"                
        :css-classes="cssClasses"
        :styles="styles"
        :height="height"
    />
    <Bar v-else
        :chart-options="chartOptions"
        :chart-data="chartData"
        :chart-id="chartId"
        :dataset-id-key="datasetIdKey"
        :plugins="plugins"                
        :css-classes="cssClasses"
        :styles="styles"
        :height="height"
    />    
</template>
  
<script>
import { Bar, Line } from 'vue-chartjs'
import { Chart as
    ChartJS,
    Title,
    Tooltip,
    Legend,
    BarElement,
    CategoryScale,
    LinearScale,
    LineElement,
    PointElement
} from 'chart.js'

ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, LineElement, PointElement)

export default {
    name: 'BarChart',
    components: {Bar, Line},

    props: {
        chartType: {
            type: Number,
            default: 0
        },
        chartData: {
            type: Object,
            default: {
                labels: [
                    '100',
                    '200',
                    '300'
                ],
                datasets: [
                {
                    label: 'Your text',
                    data: [100, 100, 100],
                    backgroundColor: [
                        'rgb(255, 99, 132)',
                        'rgb(54, 162, 235)',
                        'rgb(155, 155, 155)'
                    ],
                    hoverOffset: 4
                },
                {
                    label: 'text1',
                    data: [150, 150, 150],
                    backgroundColor: [
                        'rgb(255, 99, 132)',
                        'rgb(54, 162, 235)',
                        'rgb(155, 155, 155)'
                    ],
                    hoverOffset: 4
                },
                {
                    label: 'text2',
                    data: [200, 200, 200],
                    backgroundColor: [
                        'rgb(255, 99, 132)',
                        'rgb(54, 162, 235)',
                        'rgb(155, 155, 155)'
                    ],
                    hoverOffset: 4
                }]
            },
        },
        chartOptions: {
            type: Object,
            default: {
                responsive: true,
                maintainAspectRatio: false,
            }
        },
        chartId: {
            type: String,
            default: 'bar-chart'
        },
        datasetIdKey: {
            type: String,
            default: 'label'
        },
        width: {
            type: Number,
            default: 400
        },
        height: {
            type: Number,
            default: 300
        },
        cssClasses: {
            default: '',
            type: String
        },
        styles: {
            type: Object,
            default: () => {}
        },
        plugins: {
            type: Array,
            default: () => []
        }
    }
}
</script>
解决方案

这个问题核心是服务端编译时没有浏览器DOM环境,而chart.js依赖DOM才能初始化图表,vue-chartjs的基础组件在服务端尝试渲染时会触发错误。以下是几种可行的解决办法:

1. 仅在客户端渲染图表组件

方法A:使用框架自带的客户端专属组件(如Nuxt的<client-only>)

直接用<client-only>包裹图表组件,让服务端跳过这部分的渲染,只在客户端执行:

<template>
  <client-only>
    <Line v-if="chartType === 0" ... />
    <Bar v-else ... />
  </client-only>
</template>

方法B:手动判断浏览器环境

如果不是Nuxt这类自带客户端组件的框架,可以通过判断window对象是否存在来控制渲染:

<template>
  <Line v-if="isClient && chartType === 0" ... />
  <Bar v-else-if="isClient" ... />
</template>

<script>
// ... 其他代码不变
export default {
  // ...
  data() {
    return {
      isClient: typeof window !== 'undefined'
    }
  }
}
</script>

2. 修正Props默认值的写法(最佳实践)

Vue中对象/数组类型的Props默认值应该用函数返回,避免多个组件实例共享同一个对象引用,同时也能确保服务端编译时默认值正确初始化:

// 修改chartData的default为函数
chartData: {
  type: Object,
  default: () => ({
    labels: ['100', '200', '300'],
    datasets: [
      // ... 原数据集内容
    ]
  })
},
// 同样修改chartOptions的default
chartOptions: {
  type: Object,
  default: () => ({
    responsive: true,
    maintainAspectRatio: false,
  })
}

3. 自定义扩展vue-chartjs组件,手动控制渲染时机

放弃直接使用vue-chartjs提供的基础Bar/Line组件,改为自己扩展组件,在客户端的mounted钩子中手动初始化图表:

// 新建LineChart.vue组件
import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins

export default {
  extends: Line,
  mixins: [reactiveProp],
  props: ['chartOptions'],
  mounted() {
    // 仅在客户端执行mounted,这里初始化图表
    this.renderChart(this.chartData, this.chartOptions)
  }
}
// 新建BarChart.vue组件
import { Bar, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins

export default {
  extends: Bar,
  mixins: [reactiveProp],
  props: ['chartOptions'],
  mounted() {
    this.renderChart(this.chartData, this.chartOptions)
  }
}

然后在父组件中引入这两个自定义组件,替换原来的Bar/Line:

<template>
  <LineChart v-if="chartType === 0" :chart-data="chartData" :chart-options="chartOptions" />
  <BarChart v-else :chart-data="chartData" :chart-options="chartOptions" />
</template>

<script>
import LineChart from './LineChart.vue'
import BarChart from './BarChart.vue'
// ... 其他注册ChartJS的代码不变

export default {
  components: { LineChart, BarChart },
  // ... 其他Props代码不变
}
</script>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 03:25:07