Vue3 + Element Plus 项目实战:用 ECharts 5 打造一个班级数据可视化大屏(附完整源码)

张开发
2026/4/16 13:47:35 15 分钟阅读

分享文章

Vue3 + Element Plus 项目实战:用 ECharts 5 打造一个班级数据可视化大屏(附完整源码)
Vue3 Element Plus 数据可视化实战班级数据大屏开发指南最近在重构学校管理系统时遇到了一个有趣的挑战——如何将枯燥的班级数据转化为直观的可视化大屏。经过多次迭代我总结出一套基于Vue3和Element Plus的高效开发方案今天就来分享这个实战过程。1. 环境搭建与工程配置现代前端开发已经告别了Webpack的缓慢构建时代。我们选择Vite作为构建工具它能带来闪电般的启动速度和热更新体验。先来看看基础环境的搭建npm create vitelatest class-dashboard --template vue-ts cd class-dashboard npm install element-plus echarts axios安装完成后需要在main.ts中进行基础配置。这里有个小技巧按需引入Element Plus组件可以显著减小打包体积。import { createApp } from vue import App from ./App.vue import ElementPlus from element-plus import element-plus/dist/index.css const app createApp(App) app.use(ElementPlus) app.mount(#app)对于ECharts的引入我推荐使用hooks方式封装而不是全局挂载。这样可以更好地利用Vue3的Composition API特性// src/hooks/useEcharts.ts import * as echarts from echarts/core import { BarChart, LineChart, PieChart } from echarts/charts import { TitleComponent, TooltipComponent, GridComponent, LegendComponent } from echarts/components import { CanvasRenderer } from echarts/renderers echarts.use([ TitleComponent, TooltipComponent, GridComponent, LegendComponent, BarChart, LineChart, PieChart, CanvasRenderer ]) export default function useEcharts(el: RefHTMLElement | null) { const chartInstance refecharts.ECharts | null(null) onMounted(() { if (el.value) { chartInstance.value echarts.init(el.value) } }) onBeforeUnmount(() { chartInstance.value?.dispose() }) return { chartInstance } }2. 大屏布局设计与响应式适配班级数据大屏通常需要展示多种图表合理的布局至关重要。Element Plus的Layout组件在这里大显身手template el-container classdashboard-container el-header班级数据可视化平台/el-header el-main el-row :gutter20 el-col :span12 div classchart-container refattendanceChart/div /el-col el-col :span12 div classchart-container refbehaviorChart/div /el-col /el-row el-row :gutter20 stylemargin-top: 20px el-col :span8 div classchart-container refscoreChart/div /el-col el-col :span16 div classchart-container reftrendChart/div /el-col /el-row /el-main /el-container /template style scoped .dashboard-container { height: 100vh; background-color: #f5f7fa; } .chart-container { width: 100%; height: 400px; background: white; border-radius: 4px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); } /style响应式处理是大屏开发的关键点之一。我封装了一个useResponsive hook来处理窗口大小变化时的图表重绘import { onMounted, onBeforeUnmount } from vue export default function useResponsive(chartInstance: Refecharts.ECharts | null) { const handleResize () { chartInstance.value?.resize() } onMounted(() { window.addEventListener(resize, handleResize) }) onBeforeUnmount(() { window.removeEventListener(resize, handleResize) }) }3. 核心图表实现与数据绑定3.1 学生出勤率环形图环形图非常适合展示比例数据比如班级出勤率。我们先定义数据类型interface AttendanceData { value: number name: string color: string } const attendanceData refAttendanceData[]([ { value: 92, name: 出勤, color: #36a3f7 }, { value: 5, name: 请假, color: #ffbf00 }, { value: 3, name: 缺勤, color: #f4516c } ])图表配置需要注意几个关键点设置radius控制环形大小使用rich文本增强标签显示添加动画效果提升用户体验const initAttendanceChart () { const option: echarts.EChartsOption { title: { text: 班级出勤率, left: center }, tooltip: { trigger: item }, legend: { orient: vertical, right: 10, top: center }, series: [{ name: 出勤情况, type: pie, radius: [50%, 70%], avoidLabelOverlap: false, itemStyle: { borderRadius: 10, borderColor: #fff, borderWidth: 2 }, label: { show: true, formatter: {b}: {d}%, rich: { b: { fontSize: 14, lineHeight: 20 }, d: { fontSize: 16, fontWeight: bold, color: #333 } } }, emphasis: { label: { show: true, fontSize: 18, fontWeight: bold } }, labelLine: { show: true }, data: attendanceData.value, animationType: scale, animationEasing: elasticOut, animationDelay: function (idx) { return Math.random() * 200 } }] } attendanceChartInstance.value?.setOption(option) }3.2 学生行为分析柱状图行为分析通常需要对比多个维度的数据柱状图是最佳选择。这里我们实现一个带渐变色效果的柱状图const behaviorOption: echarts.EChartsOption { title: { text: 学生行为分析, left: center }, tooltip: { trigger: axis, axisPointer: { type: shadow } }, grid: { left: 3%, right: 4%, bottom: 3%, containLabel: true }, xAxis: { type: category, data: [课堂参与, 作业完成, 小组合作, 遵守纪律], axisTick: { alignWithLabel: true } }, yAxis: { type: value, name: 评分, min: 0, max: 100 }, series: [{ name: 平均分, type: bar, barWidth: 40%, data: [ { value: 85, itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: #83bff6 }, { offset: 0.5, color: #188df0 }, { offset: 1, color: #188df0 } ]) } }, { value: 78, itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: #81eab9 }, { offset: 0.5, color: #1ab394 }, { offset: 1, color: #1ab394 } ]) } }, { value: 92, itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: #ffd66b }, { offset: 0.5, color: #f5a623 }, { offset: 1, color: #f5a623 } ]) } }, { value: 88, itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: #ff9e7d }, { offset: 0.5, color: #ff6e76 }, { offset: 1, color: #ff6e76 } ]) } } ], itemStyle: { borderRadius: [4, 4, 0, 0] } }] }4. 动态数据更新与性能优化真实项目中的数据通常是动态变化的。我们模拟API请求来实现数据的定时更新const fetchData async () { // 模拟API请求 const mockApi () new PromiseAttendanceData[](resolve { setTimeout(() { resolve([ { value: 90 Math.floor(Math.random() * 5), name: 出勤, color: #36a3f7 }, { value: 3 Math.floor(Math.random() * 3), name: 请假, color: #ffbf00 }, { value: 2 Math.floor(Math.random() * 3), name: 缺勤, color: #f4516c } ]) }, 500) }) attendanceData.value await mockApi() updateCharts() } onMounted(() { fetchData() // 每30秒更新一次数据 const timer setInterval(fetchData, 30000) onBeforeUnmount(() { clearInterval(timer) }) })对于性能优化我总结了几个实用技巧按需引入只引入需要的ECharts组件节流处理对resize事件进行节流缓存策略对不变的数据进行缓存虚拟滚动当图表数量很多时考虑使用import { throttle } from lodash-es const throttledResize throttle(() { chartInstances.forEach(instance instance.resize()) }, 200) window.addEventListener(resize, throttledResize)5. 主题定制与交互增强Element Plus和ECharts都支持主题定制我们可以创建统一的主题配置// theme.ts export const lightTheme { color: [#36a3f7, #ffbf00, #f4516c, #34bfa3, #716aca], backgroundColor: #ffffff, textColor: #333, axisLineColor: #eee } export const darkTheme { color: [#36a3f7, #ffbf00, #f4516c, #34bfa3, #716aca], backgroundColor: #1e1e2d, textColor: #eee, axisLineColor: #444 }对于交互增强我们可以添加图表联动功能const setupChartLinkage () { chartInstances.forEach(instance { instance.on(highlight, params { // 高亮联动逻辑 }) instance.on(downplay, params { // 取消高亮逻辑 }) }) }一个实用的技巧是添加图表下载功能const handleDownload (chartInstance: echarts.ECharts) { const url chartInstance.getDataURL({ type: png, pixelRatio: 2, backgroundColor: #fff }) const link document.createElement(a) link.href url link.download chart.png document.body.appendChild(link) link.click() document.body.removeChild(link) }6. 项目部署与持续集成完成开发后我们需要考虑部署方案。Vite项目部署非常简单npm run build生成的dist目录可以直接部署到任何静态文件服务器。对于自动化部署可以配置GitHub Actionsname: Deploy to GitHub Pages on: push: branches: [ main ] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkoutv2 - uses: actions/setup-nodev2 with: node-version: 16 - run: npm install - run: npm run build - uses: peaceiris/actions-gh-pagesv3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./dist对于需要后端API的项目可以考虑使用Docker容器化部署# Dockerfile FROM node:16 as builder WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build FROM nginx:alpine COPY --frombuilder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD [nginx, -g, daemon off;]

更多文章