前端

Vue项目中ECharts的集成与基础使用教程

TRAE AI 编程助手

前言:数据可视化的重要性

在当今数据驱动的时代,数据可视化已成为前端开发中不可或缺的一部分。无论是企业级应用还是个人项目,直观、美观的图表都能让数据"说话"。ECharts 作为百度开源的 JavaScript 可视化库,凭借其丰富的图表类型、灵活的配置选项和优秀的性能,成为了 Vue 项目中的首选图表解决方案。

TRAE IDE 提示:在 TRAE IDE 中,你可以通过智能代码补全功能快速生成 ECharts 的配置代码,大大提升开发效率。IDE 的实时预览功能还能让你即时看到图表效果,无需频繁切换浏览器窗口。

01|ECharts 集成:从零开始的项目搭建

1.1 安装依赖

在 Vue 项目中集成 ECharts 非常简单,首先我们需要安装必要的依赖包:

# 使用 npm 安装
npm install echarts vue-echarts
 
# 或者使用 yarn
yarn add echarts vue-echarts
 
# 使用 pnpm(推荐)
pnpm add echarts vue-echarts

依赖说明echarts 是核心图表库,vue-echarts 是 Vue 的封装组件,提供了更友好的 Vue 使用体验。

1.2 全局注册组件

在 Vue 3 项目中,推荐在 main.jsmain.ts 中进行全局注册:

import { createApp } from 'vue'
import App from './App.vue'
import ECharts from 'vue-echarts'
import { use } from 'echarts/core'
 
// 引入 ECharts 核心模块
import {
  CanvasRenderer
} from 'echarts/renderers'
import {
  BarChart,
  LineChart,
  PieChart,
  ScatterChart
} from 'echarts/charts'
import {
  GridComponent,
  TooltipComponent,
  TitleComponent,
  LegendComponent,
  ToolboxComponent
} from 'echarts/components'
 
// 注册必要的组件
use([
  CanvasRenderer,
  BarChart,
  LineChart,
  PieChart,
  ScatterChart,
  GridComponent,
  TooltipComponent,
  TitleComponent,
  LegendComponent,
  ToolboxComponent
])
 
const app = createApp(App)
 
// 全局注册 ECharts 组件
app.component('v-chart', ECharts)
 
app.mount('#app')

1.3 TypeScript 支持

如果你的项目使用 TypeScript,需要在 shims-vue.d.ts 中添加类型声明:

declare module 'vue-echarts' {
  import { DefineComponent } from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}

02|基础图表创建:第一个 ECharts 组件

2.1 创建基础柱状图组件

让我们创建一个简单的柱状图组件来展示销售数据:

<template>
  <div class="chart-container">
    <v-chart :option="chartOptions" :style="{ height: '400px', width: '100%' }" />
  </div>
</template>
 
<script setup>
import { ref } from 'vue'
 
const chartOptions = ref({
  title: {
    text: '月度销售统计',
    left: 'center'
  },
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: 'shadow'
    }
  },
  xAxis: {
    type: 'category',
    data: ['1月', '2月', '3月', '4月', '5月', '6月']
  },
  yAxis: {
    type: 'value',
    name: '销售额(万元)'
  },
  series: [{
    name: '销售额',
    type: 'bar',
    data: [120, 200, 150, 80, 70, 110],
    itemStyle: {
      color: '#5470c6'
    },
    emphasis: {
      itemStyle: {
        color: '#91cc75'
      }
    }
  }]
})
</script>
 
<style scoped>
.chart-container {
  padding: 20px;
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
</style>

2.2 动态数据更新

实际项目中,图表数据通常来自 API 请求。让我们实现一个支持动态数据更新的图表:

<template>
  <div class="dynamic-chart">
    <div class="chart-header">
      <h3>实时数据监控</h3>
      <button @click="refreshData" :disabled="loading">
        {{ loading ? '加载中...' : '刷新数据' }}
      </button>
    </div>
    <v-chart :option="chartOptions" :style="{ height: '350px', width: '100%' }" />
  </div>
</template>
 
<script setup>
import { ref, reactive, onMounted } from 'vue'
 
const loading = ref(false)
const chartOptions = reactive({
  title: {
    text: '用户访问趋势',
    left: 'center'
  },
  tooltip: {
    trigger: 'axis'
  },
  xAxis: {
    type: 'category',
    boundaryGap: false,
    data: []
  },
  yAxis: {
    type: 'value',
    name: '访问量'
  },
  series: [{
    name: '访问量',
    type: 'line',
    smooth: true,
    areaStyle: {
      opacity: 0.3
    },
    data: [],
    itemStyle: {
      color: '#5470c6'
    }
  }]
})
 
// 模拟 API 数据获取
const fetchData = async () => {
  loading.value = true
  try {
    // 模拟 API 调用延迟
    await new Promise(resolve => setTimeout(resolve, 1000))
    
    const hours = Array.from({ length: 24 }, (_, i) => `${i}:00`)
    const visits = Array.from({ length: 24 }, () => Math.floor(Math.random() * 1000) + 200)
    
    // 更新图表数据
    chartOptions.xAxis.data = hours
    chartOptions.series[0].data = visits
  } catch (error) {
    console.error('数据加载失败:', error)
  } finally {
    loading.value = false
  }
}
 
const refreshData = () => {
  fetchData()
}
 
onMounted(() => {
  fetchData()
})
</script>
 
## 03|响应式图表:适配不同屏幕尺寸
 
### 3.1 自动响应式实现
 
ECharts 天生支持响应式设计,但在 Vue 中我们需要额外处理容器尺寸变化:
 
```vue
<template>
  <div class="responsive-chart" ref="chartContainer">
    <v-chart 
      :option="chartOptions" 
      :autoresize="true"
      :style="{ height: containerHeight + 'px', width: '100%' }" 
    />
  </div>
</template>
 
<script setup>
import { ref, reactive, onMounted, onUnmounted } from 'vue'
 
const chartContainer = ref(null)
const containerHeight = ref(400)
 
const chartOptions = reactive({
  title: {
    text: '响应式图表示例',
    left: 'center'
  },
  tooltip: {
    trigger: 'axis'
  },
  legend: {
    data: ['销售额', '利润'],
    bottom: 10
  },
  grid: {
    left: '3%',
    right: '4%',
    bottom: '15%',
    containLabel: true
  },
  xAxis: {
    type: 'category',
    data: ['Q1', 'Q2', 'Q3', 'Q4']
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      name: '销售额',
      type: 'bar',
      data: [320, 332, 301, 334],
      itemStyle: { color: '#5470c6' }
    },
    {
      name: '利润',
      type: 'bar',
      data: [120, 132, 101, 134],
      itemStyle: { color: '#91cc75' }
    }
  ]
})
 
// 响应式处理
const handleResize = () => {
  if (chartContainer.value) {
    const width = chartContainer.value.clientWidth
    // 根据宽度调整图表高度
    containerHeight.value = width < 768 ? 300 : 400
    
    // 移动端优化
    if (width < 768) {
      chartOptions.legend.bottom = 5
      chartOptions.grid.bottom = '20%'
    } else {
      chartOptions.legend.bottom = 10
      chartOptions.grid.bottom = '15%'
    }
  }
}
 
let resizeObserver
 
onMounted(() => {
  handleResize()
  
  // 使用 ResizeObserver 监听容器尺寸变化
  if (window.ResizeObserver) {
    resizeObserver = new ResizeObserver(handleResize)
    resizeObserver.observe(chartContainer.value)
  } else {
    // 降级方案:监听 window resize
    window.addEventListener('resize', handleResize)
  }
})
 
onUnmounted(() => {
  if (resizeObserver) {
    resizeObserver.disconnect()
  } else {
    window.removeEventListener('resize', handleResize)
  }
})
</script>
 
<style scoped>
.responsive-chart {
  width: 100%;
  background: #fff;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
</style>

TRAE IDE 提示:TRAE IDE 的智能断点检测功能可以帮助你快速识别响应式设计中的断点问题,确保图表在各种设备上都能完美展示。

04|常用图表类型:丰富你的数据展示

4.1 饼图:占比分析利器

<template>
  <div class="pie-chart-container">
    <v-chart :option="pieOptions" :style="{ height: '400px', width: '100%' }" />
  </div>
</template>
 
<script setup>
import { ref } from 'vue'
 
const pieOptions = ref({
  title: {
    text: '产品销量占比',
    left: 'center'
  },
  tooltip: {
    trigger: 'item',
    formatter: '{a} <br/>{b}: {c} ({d}%)'
  },
  legend: {
    orient: 'vertical',
    left: 'left'
  },
  series: [
    {
      name: '销量',
      type: 'pie',
      radius: ['40%', '70%'],
      avoidLabelOverlap: false,
      itemStyle: {
        borderRadius: 10,
        borderColor: '#fff',
        borderWidth: 2
      },
      label: {
        show: false,
        position: 'center'
      },
      emphasis: {
        label: {
          show: true,
          fontSize: '20',
          fontWeight: 'bold'
        }
      },
      labelLine: {
        show: false
      },
      data: [
        { value: 1048, name: '电子产品' },
        { value: 735, name: '服装' },
        { value: 580, name: '食品' },
        { value: 484, name: '家居' },
        { value: 300, name: '其他' }
      ]
    }
  ]
})
</script>

4.2 散点图:相关性分析

<template>
  <div class="scatter-chart-container">
    <v-chart :option="scatterOptions" :style="{ height: '400px', width: '100%' }" />
  </div>
</template>
 
<script setup>
import { ref } from 'vue'
 
// 生成模拟数据
const generateScatterData = () => {
  const data = []
  for (let i = 0; i < 100; i++) {
    const x = Math.random() * 100
    const y = x * 0.8 + Math.random() * 20 + 10
    const size = Math.random() * 50 + 20
    data.push([x, y, size])
  }
  return data
}
 
const scatterOptions = ref({
  title: {
    text: '用户活跃度与消费金额关系',
    left: 'center'
  },
  tooltip: {
    trigger: 'item',
    formatter: function (params) {
      return `活跃度: ${params.data[0].toFixed(2)}<br/>消费金额: ${params.data[1].toFixed(2)}<br/>用户等级: ${params.data[2].toFixed(0)}`
    }
  },
  xAxis: {
    name: '用户活跃度',
    nameLocation: 'middle',
    nameGap: 30
  },
  yAxis: {
    name: '消费金额(元)',
    nameLocation: 'middle',
    nameGap: 30
  },
  series: [{
    name: '用户数据',
    type: 'scatter',
    symbolSize: function (data) {
      return data[2] / 2
    },
    data: generateScatterData(),
    itemStyle: {
      color: function(params) {
        const value = params.data[2]
        if (value > 60) return '#ee6666'
        if (value > 40) return '#fac858'
        return '#5470c6'
      },
      opacity: 0.8
    }
  }]
})
</script>

4.3 组合图表:多维度数据展示

<template>
  <div class="mixed-chart-container">
    <v-chart :option="mixedOptions" :style="{ height: '400px', width: '100%' }" />
  </div>
</template>
 
<script setup>
import { ref } from 'vue'
 
const mixedOptions = ref({
  title: {
    text: '销售与利润分析',
    left: 'center'
  },
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: 'cross'
    }
  },
  legend: {
    data: ['销售额', '利润', '利润率'],
    bottom: 10
  },
  grid: {
    left: '3%',
    right: '4%',
    bottom: '15%',
    containLabel: true
  },
  xAxis: {
    type: 'category',
    data: ['1月', '2月', '3月', '4月', '5月', '6月']
  },
  yAxis: [
    {
      type: 'value',
      name: '金额(万元)',
      position: 'left'
    },
    {
      type: 'value',
      name: '利润率(%)',
      position: 'right',
      axisLabel: {
        formatter: '{value}%'
      }
    }
  ],
  series: [
    {
      name: '销售额',
      type: 'bar',
      data: [120, 200, 150, 80, 70, 110],
      itemStyle: { color: '#5470c6' }
    },
    {
      name: '利润',
      type: 'bar',
      data: [30, 50, 35, 20, 18, 28],
      itemStyle: { color: '#91cc75' }
    },
    {
      name: '利润率',
      type: 'line',
      yAxisIndex: 1,
      data: [25, 25, 23, 25, 26, 25],
      itemStyle: { color: '#fac858' },
      lineStyle: {
        width: 3
      }
    }
  ]
})
</script>

05|性能优化:让图表飞起来

5.1 懒加载与按需加载

对于大型应用,我们应该按需加载 ECharts 模块,减少初始包体积:

// 创建 echarts.js 工具文件
import * as echarts from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { BarChart, LineChart, PieChart } from 'echarts/charts'
import {
  GridComponent,
  TooltipComponent,
  TitleComponent,
  LegendComponent
} from 'echarts/components'
 
// 只注册需要的组件
echarts.use([
  CanvasRenderer,
  BarChart,
  LineChart,
  PieChart,
  GridComponent,
  TooltipComponent,
  TitleComponent,
  LegendComponent
])
 
export default echarts

5.2 大数据量优化

当数据量很大时,我们需要采用一些优化策略:

<template>
  <div class="large-data-chart">
    <v-chart :option="largeDataOptions" :style="{ height: '400px', width: '100%' }" />
  </div>
</template>
 
<script setup>
import { ref, onMounted } from 'vue'
 
const largeDataOptions = ref({
  title: {
    text: '大数据量性能优化示例'
  },
  tooltip: {
    trigger: 'axis',
    // 大数据时禁用动画
    transitionDuration: 0
  },
  xAxis: {
    type: 'category',
    data: []
  },
  yAxis: {
    type: 'value'
  },
  series: [{
    type: 'line',
    data: [],
    // 优化大数据渲染
    large: true,
    largeThreshold: 2000,
    // 禁用动画
    animation: false,
    // 采样显示
    sampling: 'average'
  }]
})
 
// 生成大量数据
const generateLargeData = () => {
  const categories = []
  const data = []
  
  for (let i = 0; i < 10000; i++) {
    categories.push(`类别${i}`)
    data.push(Math.random() * 1000)
  }
  
  return { categories, data }
}
 
onMounted(() => {
  const { categories, data } = generateLargeData()
  largeDataOptions.value.xAxis.data = categories
  largeDataOptions.value.series[0].data = data
})
</script>

5.3 内存优化

及时销毁不需要的图表实例,避免内存泄漏:

<template>
  <div class="memory-optimized-chart">
    <v-chart 
      ref="chartRef"
      :option="chartOptions" 
      :style="{ height: '400px', width: '100%' }" 
    />
  </div>
</template>
 
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
 
const chartRef = ref(null)
const chartOptions = ref({
  // 图表配置...
})
 
let updateInterval
 
onMounted(() => {
  // 定期更新数据
  updateInterval = setInterval(() => {
    // 更新逻辑
  }, 5000)
})
 
onUnmounted(() => {
  // 清理定时器
  if (updateInterval) {
    clearInterval(updateInterval)
  }
  
  // 销毁图表实例
  if (chartRef.value) {
    chartRef.value.dispose()
  }
})
</script>

5.4 渲染优化技巧

// 批量更新数据
const batchUpdateChart = (chart, newData) => {
  // 使用 setOption 的 notMerge 参数
  chart.setOption({
    series: [{
      data: newData
    }]
  }, {
    notMerge: false,  // 不合并配置
    lazyUpdate: true  // 延迟更新
  })
}
 
// 防抖处理频繁更新
const debounceUpdate = (func, wait) => {
  let timeout
  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout)
      func(...args)
    }
    clearTimeout(timeout)
    timeout = setTimeout(later, wait)
  }
}
 
// 使用防抖
const updateChart = debounceUpdate((newData) => {
  chart.setOption({
    series: [{ data: newData }]
  })
}, 300)

06|TRAE IDE 集成:提升开发体验

6.1 智能代码补全

TRAE IDE 提供了强大的智能代码补全功能,在编写 ECharts 配置时特别有用:

// 输入 "title" 后,IDE 会自动提示完整的 title 配置结构
const chartOptions = {
  title: {
    text: '主标题',
    subtext: '副标题',  // IDE 自动提示
    left: 'center',     // IDE 提供枚举值提示
    textStyle: {        // IDE 自动补全嵌套结构
      fontSize: 18,
      fontWeight: 'bold'
    }
  }
}

6.2 实时预览与调试

TRAE IDE 的实时预览功能让你无需刷新浏览器就能看到图表变化:

开发建议

  1. 使用 TRAE IDE 的分屏功能,一边编写代码,一边查看图表效果
  2. 利用 IDE 的调试工具,可以实时查看 chartOptions 的数据变化
  3. 通过 IDE 的性能分析工具,监控图表渲染性能

6.3 代码片段与模板

在 TRAE IDE 中创建常用的 ECharts 代码片段:

{
  "ECharts Base Config": {
    "prefix": "echarts-base",
    "body": [
      "const chartOptions = {",
      "  title: {",
      "    text: '${1:图表标题}',",
      "    left: 'center'",
      "  },",
      "  tooltip: {",
      "    trigger: '${2:axis}'",
      "  },",
      "  xAxis: {",
      "    type: '${3:category}',",
      "    data: ${4:[]}",
      "  },",
      "  yAxis: {",
      "    type: '${5:value}'",
      "  },",
      "  series: [{",
      "    name: '${6:系列名称}',",
      "    type: '${7:bar}',",
      "    data: ${8:[]}",
      "  }]",
      "}"
    ]
  }
}

6.4 项目管理与协作

TRAE IDE 提供了优秀的项目管理功能:

# 使用 TRAE IDE 的终端快速创建组件
touch src/components/Charts/SalesChart.vue
 
# IDE 会自动识别 Vue 文件并提供相应的语法高亮
# 使用 Git 集成进行版本控制
git add .
git commit -m "feat: 添加销售数据图表组件"

TRAE IDE 亮点总结

  • 智能感知:自动识别 ECharts 配置项,提供精准的代码补全
  • 实时协作:多人同时编辑图表组件,实时同步变更
  • 性能监控:内置性能分析工具,帮助优化图表渲染
  • 一键部署:集成 CI/CD 流程,图表更新自动部署

07|最佳实践与常见问题

7.1 组件化最佳实践

<!-- ChartWrapper.vue - 通用图表包装组件 -->
<template>
  <div class="chart-wrapper" :class="{ 'is-loading': loading }">
    <div v-if="loading" class="chart-loading">
      <span>数据加载中...</span>
    </div>
    <div v-else-if="error" class="chart-error">
      <span>{{ error }}</span>
      <button @click="$emit('retry')">重试</button>
    </div>
    <v-chart
      v-else
      :option="options"
      :autoresize="autoresize"
      :style="{ height: height + 'px', width: '100%' }"
      @finished="handleChartFinished"
    />
  </div>
</template>
 
<script setup>
import { ref } from 'vue'
 
defineProps({
  options: {
    type: Object,
    required: true
  },
  loading: {
    type: Boolean,
    default: false
  },
  error: {
    type: String,
    default: ''
  },
  height: {
    type: Number,
    default: 400
  },
  autoresize: {
    type: Boolean,
    default: true
  }
})
 
defineEmits(['retry'])
 
const handleChartFinished = () => {
  console.log('图表渲染完成')
}
</script>

7.2 常见问题解决方案

问题 1:图表不显示

// 确保容器有明确的尺寸
const checkContainerSize = () => {
  const container = document.querySelector('.chart-container')
  if (container && container.clientWidth === 0) {
    console.warn('图表容器宽度为0,请检查CSS样式')
  }
}

问题 2:内存泄漏

// 正确的销毁方式
const disposeChart = (chart) => {
  if (chart && !chart.isDisposed()) {
    chart.dispose()
  }
}

问题 3:性能问题

// 使用防抖和节流
import { debounce, throttle } from 'lodash-es'
 
const optimizedResize = debounce(() => {
  chart.resize()
}, 300)
 
const optimizedUpdate = throttle((data) => {
  chart.setOption({ series: [{ data }] })
}, 100)

总结与展望

通过本文的学习,我们全面掌握了在 Vue 项目中集成和使用 ECharts 的方法:

  1. 基础集成:从安装依赖到全局注册,为项目添加图表能力
  2. 图表创建:学会创建各种类型的图表,满足不同数据展示需求
  3. 响应式设计:让图表在各种设备上都能完美展示
  4. 性能优化:掌握大数据量和复杂场景下的优化技巧
  5. 开发工具:利用 TRAE IDE 提升开发效率和代码质量

思考题

  1. 在你的项目中,哪种图表类型最适合展示你的业务数据?
  2. 如何结合 TRAE IDE 的智能提示功能,快速构建复杂的图表配置?
  3. 面对海量数据,你会采用哪些性能优化策略?

ECharts 的强大功能远不止于此,结合 Vue 的响应式特性和 TRAE IDE 的智能开发体验,我们可以构建出更加专业、高效的数据可视化应用。希望本文能帮助你在数据可视化的道路上走得更远!

03|响应式图表:适配不同屏幕尺寸

3.1 自动响应式实现

ECharts 天生支持响应式设计,但在 Vue 中我们需要额外处理容器尺寸变化:

<template>
  <div class="responsive-chart" ref="chartContainer">
    <v-chart 
      :option="chartOptions" 
      :autoresize="true"
      :style="{ height: containerHeight + 'px', width: '100%' }" 
    />
  </div>
</template>
 
<script setup>
import { ref, reactive, onMounted, onUnmounted } from 'vue'
 
const chartContainer = ref(null)
const containerHeight = ref(400)
 
const chartOptions = reactive({
  title: {
    text: '响应式图表示例',
    left: 'center'
  },
  tooltip: {
    trigger: 'axis'
  },
  legend: {
    data: ['销售额', '利润'],
    bottom: 10
  },
  grid: {
    left: '3%',
    right: '4%',
    bottom: '15%',
    containLabel: true
  },
  xAxis: {
    type: 'category',
    data: ['Q1', 'Q2', 'Q3', 'Q4']
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      name: '销售额',
      type: 'bar',
      data: [320, 332, 301, 334],
      itemStyle: { color: '#5470c6' }
    },
    {
      name: '利润',
      type: 'bar',
      data: [120, 132, 101, 134],
      itemStyle: { color: '#91cc75' }
    }
  ]
})
 
// 响应式处理
const handleResize = () => {
  if (chartContainer.value) {
    const width = chartContainer.value.clientWidth
    // 根据宽度调整图表高度
    containerHeight.value = width < 768 ? 300 : 400
    
    // 移动端优化
    if (width < 768) {
      chartOptions.legend.bottom = 5
      chartOptions.grid.bottom = '20%'
    } else {
      chartOptions.legend.bottom = 10
      chartOptions.grid.bottom = '15%'
    }
  }
}
 
let resizeObserver
 
onMounted(() => {
  handleResize()
  
  // 使用 ResizeObserver 监听容器尺寸变化
  if (window.ResizeObserver) {
    resizeObserver = new ResizeObserver(handleResize)
    resizeObserver.observe(chartContainer.value)
  } else {
    // 降级方案:监听 window resize
    window.addEventListener('resize', handleResize)
  }
})
 
onUnmounted(() => {
  if (resizeObserver) {
    resizeObserver.disconnect()
  } else {
    window.removeEventListener('resize', handleResize)
  }
})
</script>
 
<style scoped>
.responsive-chart {
  width: 100%;
  background: #fff;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
</style>

TRAE IDE 提示:TRAE IDE 的智能断点检测功能可以帮助你快速识别响应式设计中的断点问题,确保图表在各种设备上都能完美展示。

04|常用图表类型:丰富你的数据展示

4.1 饼图:占比分析利器

<template>
  <div class="pie-chart-container">
    <v-chart :option="pieOptions" :style="{ height: '400px', width: '100%' }" />
  </div>
</template>
 
<script setup>
import { ref } from 'vue'
 
const pieOptions = ref({
  title: {
    text: '产品销量占比',
    left: 'center'
  },
  tooltip: {
    trigger: 'item',
    formatter: '{a} <br/>{b}: {c} ({d}%)'
  },
  legend: {
    orient: 'vertical',
    left: 'left'
  },
  series: [
    {
      name: '销量',
      type: 'pie',
      radius: ['40%', '70%'],
      avoidLabelOverlap: false,
      itemStyle: {
        borderRadius: 10,
        borderColor: '#fff',
        borderWidth: 2
      },
      label: {
        show: false,
        position: 'center'
      },
      emphasis: {
        label: {
          show: true,
          fontSize: '20',
          fontWeight: 'bold'
        }
      },
      labelLine: {
        show: false
      },
      data: [
        { value: 1048, name: '电子产品' },
        { value: 735, name: '服装' },
        { value: 580, name: '食品' },
        { value: 484, name: '家居' },
        { value: 300, name: '其他' }
      ]
    }
  ]
})
</script>

4.2 散点图:相关性分析

<template>
  <div class="scatter-chart-container">
    <v-chart :option="scatterOptions" :style="{ height: '400px', width: '100%' }" />
  </div>
</template>
 
<script setup>
import { ref } from 'vue'
 
// 生成模拟数据
const generateScatterData = () => {
  const data = []
  for (let i = 0; i < 100; i++) {
    const x = Math.random() * 100
    const y = x * 0.8 + Math.random() * 20 + 10
    const size = Math.random() * 50 + 20
    data.push([x, y, size])
  }
  return data
}
 
const scatterOptions = ref({
  title: {
    text: '用户活跃度与消费金额关系',
    left: 'center'
  },
  tooltip: {
    trigger: 'item',
    formatter: function (params) {
      return `活跃度: ${params.data[0].toFixed(2)}<br/>消费金额: ${params.data[1].toFixed(2)}<br/>用户等级: ${params.data[2].toFixed(0)}`
    }
  },
  xAxis: {
    name: '用户活跃度',
    nameLocation: 'middle',
    nameGap: 30
  },
  yAxis: {
    name: '消费金额(元)',
    nameLocation: 'middle',
    nameGap: 30
  },
  series: [{
    name: '用户数据',
    type: 'scatter',
    symbolSize: function (data) {
      return data[2] / 2
    },
    data: generateScatterData(),
    itemStyle: {
      color: function(params) {
        const value = params.data[2]
        if (value > 60) return '#ee6666'
        if (value > 40) return '#fac858'
        return '#5470c6'
      },
      opacity: 0.8
    }
  }]
})
</script>

4.3 组合图表:多维度数据展示

<template>
  <div class="mixed-chart-container">
    <v-chart :option="mixedOptions" :style="{ height: '400px', width: '100%' }" />
  </div>
</template>
 
<script setup>
import { ref } from 'vue'
 
const mixedOptions = ref({
  title: {
    text: '销售与利润分析',
    left: 'center'
  },
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: 'cross'
    }
  },
  legend: {
    data: ['销售额', '利润', '利润率'],
    bottom: 10
  },
  grid: {
    left: '3%',
    right: '4%',
    bottom: '15%',
    containLabel: true
  },
  xAxis: {
    type: 'category',
    data: ['1月', '2月', '3月', '4月', '5月', '6月']
  },
  yAxis: [
    {
      type: 'value',
      name: '金额(万元)',
      position: 'left'
    },
    {
      type: 'value',
      name: '利润率(%)',
      position: 'right',
      axisLabel: {
        formatter: '{value}%'
      }
    }
  ],
  series: [
    {
      name: '销售额',
      type: 'bar',
      data: [120, 200, 150, 80, 70, 110],
      itemStyle: { color: '#5470c6' }
    },
    {
      name: '利润',
      type: 'bar',
      data: [30, 50, 35, 20, 18, 28],
      itemStyle: { color: '#91cc75' }
    },
    {
      name: '利润率',
      type: 'line',
      yAxisIndex: 1,
      data: [25, 25, 23, 25, 26, 25],
      itemStyle: { color: '#fac858' },
      lineStyle: {
        width: 3
      }
    }
  ]
})
</script>

(此内容由 AI 辅助生成,仅供参考)