
简介一套基于Vue.js与ECharts的数据可视化大屏源码面向前端开发者、数据可视化爱好者及有监控大屏需求的项目团队。项目以Vue为框架核心结合vue-echarts插件完成图表渲染配合JavaScript实现交互逻辑CSS与HTML构建页面结构与样式可广泛应用于运营监控、数据展示等场景。资源共28个文件包含11个Vue组件、8个JavaScript脚本、2个JSON配置文件以及browserslistrc、ico、css等辅助文件压缩包约531KB结构清晰便于拆解学习。目前已有1845人浏览学习。源码中涵盖TopView、TodayUsers、MapView等可视化模块涉及ECharts初始化的完整写法、Vue组件化开发思路、全局样式与路由配置适合用于理解大屏类项目从布局到数据绑定的全流程也可作为二次开发的基础模板。1. Vue.js ECharts 的数据可视化大屏源码先别急着改先拆骨架很多搞运维和前端的朋友下载完基于Vue.js与ECharts的数据可视化大屏源码第一件事就是 npm install然后发现报错一堆图也不显示。我一般拿到这样的源码会先花 20 分钟把项目结构、依赖版本和启动脚本读明白。Vue.js 负责页面状态与组件生命周期ECharts 负责把数据变成可交互图表大屏源码真正值钱的地方往往在组件封装、数据刷新、适配缩放这三层。下面我按跑通-封装-适配-接数据-改造成自己的这个顺序把一套能落地的大屏方案拆开讲清楚适合需要做企业级数据可视化大屏或 3D 数据大屏二次开发的人。2. 从源码结构看 Vue.js 与 ECharts 大屏的骨架依赖、目录与跑通大屏项目和普通后台管理系统最大的区别是单页内图表多、定时器多、容器尺寸随时在变。如果一开始目录结构没理清后面改接口和换图表时会非常痛苦。所以我建议把源码当成一份前端架构样例来看而不是直接在上面堆代码。先弄明白 ECharts 是怎么挂进 Vue.js 的再顺着目录找到配置和接口最后把项目跑起来这一步走完大屏源码的骨架才算真正握在手里。2.1 ECharts 在 Vue.js 中的挂载时机全局注册、按需引入还是封装指令ECharts 本身不依赖 Vue.js它只负责在拿到 DOM 容器后创建实例并渲染。常见做法是在 Vue 的mounted生命周期里初始化在beforeUnmount里调用dispose。根据大屏源码对 ECharts 的引用方式可以分成三种全局引入、按需引入、用自定义指令封装。全局引入import * as echarts from echarts然后挂到 Vue 原型上写起来最方便打包体积最大。按需引入从echarts/core里只注册用到的图表和组件对加载体积敏感的大屏项目更友好。指令封装写一个v-chart指令在inserted钩子里初始化在unbind钩子里销毁适合模板里大量使用div v-chartoption的场景。三者的差别需要结合package.json里的依赖体积来判断。按需引入是企业级数据可视化项目里比较推荐的方式因为大屏页面通常只用到柱状图、折线图、饼图和地图没必要把 ECharts 全家桶带进来。下面这段代码是 Vue3 项目里常见的按需注册方式。// echarts.setup.js import * as echarts from echarts/core; import { BarChart, LineChart, PieChart, MapChart } from echarts/charts; import { GridComponent, TooltipComponent, LegendComponent, DataZoomComponent, GeoComponent } from echarts/components; import { CanvasRenderer } from echarts/renderers; echarts.use([ BarChart, LineChart, PieChart, MapChart, GridComponent, TooltipComponent, LegendComponent, DataZoomComponent, GeoComponent, CanvasRenderer ]); export default echarts;这段代码的关键是把 ECharts 的charts和components分开注册。MapChart和GeoComponent是地图相关需要的不用地图时可以去掉。renderers里CanvasRenderer是默认渲染器如果大屏上有大量实时刷新的折线图可以换成SVGRenderer但要注意动态数据量很大时 SVG 的 DOM 节点更多性能反而不如 Canvas。这个参数直接决定了图表最终的渲染方式。引用方式打包体积推荐场景全局引入大快速原型、单屏图表种类很多按需引入小企业级大屏、需要控制首屏加载指令封装中模板中图表容器很多想复用初始化逻辑2.2 一份大屏源码常见的 src 目录设计我见过的大多数 Vue.js ECharts 大屏源码src下都会把请求、组件、配置、页面分开。下面是一个经过整理后的常见目录树src/ api/ dashboard.js // 大屏接口请求 modules/ realtime.js // 实时数据 components/ DashboardChart/ // ECharts 基础组件 BorderBox/ // 大屏边框组件 CarouselPanel/ // 轮播面板 DigitalFlop/ // 数字翻牌器 config/ theme.js // 主题颜色 pointerTime.js // 轮询间隔 utils/ request.js // axios 实例 resize.js // 大屏适配 views/ Dashboard.vue // 大屏主页面 main.js拿到源码后不要急着删东西先把config和api这两个目录读透。大屏的标题、轮播速度、刷新间隔、接口前缀通常都写在这两个目录里。很多可视化大屏适配问题其实不是 CSS 写不出来而是config里的基准尺寸没找到。比如有的源码会把标准屏幕宽度放在theme.js的designWidth字段里适配逻辑全依赖这个常量。2.3 把源码跑通npm install 之后最常遇到的四个问题第一步自然是安装依赖但不同源码用的 Vue 版本不一样Node 版本对不上时会报node-sass或Cant resolve fs之类的错。我一般会先看package.json里的engines字段或者直接按以下命令启动npm install npm run dev如果提示Node Sass does not support your current environment说明 Node 版本和node-sass不匹配。常见做法是卸载node-sass换成dart-sass也就是在package.json里把node-sass改成sass再重新安装。如果报错是Cant resolve echarts那就是 ECharts 没有装单独执行npm install echarts --save即可。npm 安装太慢时可以把镜像源切到国内镜像速度会改善很多。报错信息可能原因处理方式Node Sass does not supportNode 版本与 node-sass 不匹配换成 dart-sassCant resolve echartsECharts 未安装npm install echarts -SParsing error: Unexpected token缺少 Babel 配置检查 .babelrc 或安装 babel/preset-envResizeObserver is not defined老浏览器不支持安装 ResizeObserver polyfill项目跑起来后先确认控制台没有红色报错再打开 Network 面板看看数据请求是否 404。很多大屏源码默认连的是演示环境接口没有真实后端时需要到src/api里把 baseURL 改成自己的地址或者临时在src/data目录下放 mock 数据。这一步不做后面图表就会一直空白。先把静态数据跑出画面再接接口这是排错成本最低的顺序。3. 封装 Vue.js ECharts 大屏图表组件初始化、配置合并与自适应大屏页面通常有十几个图表如果每个图表都在页面里直接写echarts.init代码会非常散而且页面销毁时容易漏掉实例。更好的做法是把 ECharts 初始化逻辑收敛到一个公共组件里页面只负责传 option 和接收事件。这样无论源码里有 5 个图表还是 50 个图表改动逻辑都只集中在BaseChart.vue一行。3.1 一个能撑住大屏场景的 BaseChart 组件我习惯把图表基础组件命名为BaseChart.vue只做四件事初始化、更新配置、跟随容器尺寸变化、销毁实例。用 Vue3 的script setup写的话核心代码是这样的template div refchartRef classbase-chart/div /template script setup import * as echarts from echarts; import { ref, onMounted, onBeforeUnmount, watch } from vue; const props defineProps({ option: { type: Object, required: true }, theme: { type: String, default: }, autoresize: { type: Boolean, default: true } }); const emit defineEmits([click]); const chartRef ref(null); let chartInstance null; let resizeObserver null; onMounted(() { chartInstance echarts.init(chartRef.value, props.theme); chartInstance.setOption(props.option); chartInstance.on(click, (params) emit(click, params)); if (props.autoresize typeof ResizeObserver ! undefined) { resizeObserver new ResizeObserver(() { chartInstance chartInstance.resize(); }); resizeObserver.observe(chartRef.value); } else { window.addEventListener(resize, handleWindowResize); } }); function handleWindowResize() { chartInstance chartInstance.resize(); } watch(() props.option, (val) { chartInstance chartInstance.setOption(val, { notMerge: false }); }, { deep: true }); onBeforeUnmount(() { if (resizeObserver) { resizeObserver.disconnect(); } else { window.removeEventListener(resize, handleWindowResize); } chartInstance chartInstance.dispose(); }); /script这段代码里的几个参数值得说明。echarts.init的第二个参数是主题名不传就是用默认主题。setOption的第二个参数notMerge设成false意思是在原有配置基础上做增量合并适合大屏上某个图表的数据定时刷新时只更新series.data而不会把xAxis的配置重置掉。如果你希望在切换页面时整个配置都重新计算才需要设成true。用ResizeObserver是比window.resize更稳的方案。大屏的图表容器经常是 flex 布局窗口变化时容器尺寸可能不变window事件会白白触发 resize而ResizeObserver只在容器尺寸真正变化时回调还能避免多个图表实例互相干扰。需要在老浏览器兼容时再退回window事件。事件绑定在mounted里完成组件实例销毁时从onBeforeUnmount里移除这就是标准的生命周期管理。3.2 把 option 拆成数据映射和组件配置两层大屏源码里最难看懂的部分就是 option。一个常见的问题是接口字段名变了但配置里还写死data[i].value。我会在src/config里放一个转换函数专门把接口数据映射成 ECharts 需要的结构// src/config/barOption.js export function buildBarOption(rawData) { const categories rawData.map((item) item.categoryName); const values rawData.map((item) item.num); return { tooltip: { trigger: axis }, grid: { left: 3%, right: 4%, bottom: 3%, containLabel: true }, xAxis: { type: category, data: categories }, yAxis: { type: value }, series: [ { name: 当前值, type: bar, data: values, itemStyle: { color: #36cbcb } } ] }; }这个函数的输入是原始数据输出是一个完整的 ECharts option。页面里拿到接口数据后先调用它再把结果传给BaseChart :optionoption。这样做的好处是后端换字段时只需要改这一层映射不用去动组件。大屏里的数据可视化本质上就是不断做原始数据 - 图表配置的转换。如果项目里用了 TypeScript还可以给rawData定义一个接口类型这样字段拼错时编译阶段就会报错。3.3 大屏适配vw/vh、rem 与 transform: scale 三种方案的取舍可视化大屏适配是大屏源码里被问得最多的点。三种常见方案的区别可以看这张表方案核心思路优点缺点vw/vh宽高全部用视口单位代码直观字体和间距跟着视口走文字会变得过大或过小设计稿还原度不够rem用 html 的 font-size 做基准前端习惯移动端成熟大屏上需要自己计算根字号图表内部坐标系还是 pxtransform: scale按设计稿整体缩放还原度最高图表不重绘适配后留白或被裁剪交互坐标需要换算我一般建议大屏采用vw/vh 布局 transform scale 兜底的组合页面骨架用100vw和100vh撑满屏幕内部所有模块用百分比或 vw 布局这样保证没有滚动条如果项目要求严格按 1920x1080 设计稿还原就用一个固定尺寸的容器计算实际视口与设计稿的宽高比再整体scale。下面是 vw/vh 布局的基础样式.dashboard { width: 100vw; height: 100vh; overflow: hidden; background: #0a1a2f; }这个例子里的width: 100vw指的是视口宽度注意滚动条出现时vw会把滚动条宽度也算进去所以大屏项目里通常还要给body设置overflow: hidden。图表组件里的BaseChart因为是接在容器上的容器被 vw/vh 撑开后ECharts 自带的resize()就能自动适配。如果页面里需要表格element表格也要给外层容器设置固定高度避免内部滚动条把大屏布局挤乱。4. 在大屏源码里处理真实数据请求、地图、轮播与内存清理跑通静态页面之后下一步就是接真实数据。大屏和普通后台的关键差异在于数据要反复刷新容器的尺寸要反复变化图表实例要反复创建。这三件事加起来最容易出现数据请求重复、地图数据格式不对、轮播卡顿、内存泄漏。这一章我按请求封装 - 地图映射 - 轮播 - 排查的顺序逐个拆。4.1 用 axios 封装一个带取消机制的数据请求模块大屏页面里通常有多个模块每个模块按自己的频率轮询。如果页面已经切换走了上一个模块的请求还在返回就会在 Vue 实例卸载后触发 setState 警告。常见做法是给每个模块建一个AbortController在组件销毁前取消请求。// src/utils/request.js import axios from axios; const service axios.create({ baseURL: /api, timeout: 10000 }); service.interceptors.response.use( (response) response.data, (error) { if (error.code ERR_CANCELED) { console.log(request canceled); return Promise.reject(error); } return Promise.reject(error); } ); export function getRealtimeData(signal) { return service.get(/realtime, { signal }); }在组件里这样用const controller new AbortController(); async function load() { try { const data await getRealtimeData(controller.signal); // 更新图表 option } catch (e) { // 超时或取消时不做处理 } }AbortController是浏览器原生的请求取消能力axios 在配置项里认signal字段。调到controller.abort()时请求会被标记为ERR_CANCELED这样就不会再有回包去更新已经销毁的图表。注意signal只能取消一次如果模块要多次复用需要每次重新创建AbortController。轮询的场景还要配合setInterval使用每次轮询开始前先取消上一次请求防止接口响应慢时多个请求堆积。4.2 ECharts 地图的注册与数据映射先注册 geoJSON再匹配 name大屏上带中国地图或省份地图时最容易踩的坑是地图不显示或数据全为 0。原因往往是地图没有注册。ECharts 从 5.x 开始不再内置地图数据需要自己引入 geoJSON。import { MapChart } from echarts/charts; import * as echarts from echarts/core; import chinaGeoJson from /assets/map/china.json; echarts.use([MapChart]); echarts.registerMap(china, chinaGeoJson); const option { tooltip: { trigger: item }, geo: { map: china, roam: true, itemStyle: { areaColor: #0d2a4a, borderColor: #4a9eff } }, series: [ { type: map, map: china, data: [ { name: 广东省, value: 120 }, { name: 江苏省, value: 80 } ] } ] };代码里的关键是registerMap(china, geoJson)的第一个参数要和后面map: china保持一致。geoJSON 里的name必须是省份全称比如广东省不能写成广东或粤。ECharts 的series.data是通过name字段去匹配地图块颜色的匹配不上时不会报错只是那一块不变色。提示地图数据文件尽量放在src/assets/map下而不是public里。放在src里会被打包器当成模块解析路径错误时构建阶段就能发现放在public里运行时请求不到会静默失败排查起来更费时间。如果地图显示正常但项目打包后找不到 geoJSON检查一下文件路径。地图热力效果可以叠加一个visualMap组件控制颜色渐变区间。需要立体效果时可以再引入echarts-gl但这会加大打包体积建议只在大屏的某一两个模块里用。4.3 大屏轮播切换用一个 currentIndex 加定时器大屏看板上经常需要多个图表轮播展示。实现时没必要引入复杂的轮播插件用一个currentIndex加定时器就够了。const panels ref([{ title: 面板1 }, { title: 面板2 }, { title: 面板3 }]); const currentIndex ref(0); let timer null; function startCarousel() { timer setInterval(() { currentIndex.value (currentIndex.value 1) % panels.value.length; }, 5000); } onMounted(startCarousel); onBeforeUnmount(() clearInterval(timer));这里的setInterval间隔 5000 毫秒切换一个面板用取模运算保证下标回到 0。模板里可以用v-show配合currentIndex控制面板显隐或者用过渡组件实现淡入淡出效果。关键点是定时器一定要在onBeforeUnmount里清掉否则切换路由后定时器还在跑会继续更新已经卸载的组件。如果轮播过程中有用户鼠标悬停还需要在mouseenter时clearIntervalmouseleave时重新启动避免按着设计好的节奏硬切。4.4 大屏卡顿与内存泄漏的排查点如果大屏运行一段时间后内存越来越大优先检查四个地方见下表检查点现象验证方式ECharts 实例未 dispose内存持续上涨Memory 面板对比快照setInterval 未清除多个定时器叠加Console 里 count 定时器数量resize 监听未移除图表多次 resizePerformance 里观察 resize 事件请求未取消Network 里请求堆积切换路由后看请求是否 pending验证内存泄漏最朴素的方法是在浏览器 Performance 面板里录制一段大屏运行过程看 JS Heap 曲线是否不断上升。如果曲线有规律的下降说明有 GC 回收持续上升说明有引用没释放。这类问题通常不是某一个组件导致的而是多个定时器和多个chart.resize叠加后的结果。排查时先全局搜索setInterval再搜索addEventListener(resize把没有对应清理动作的地方逐个清掉。5. 把 Vue.js 与 ECharts 大屏源码改造成自己的三个必调配置、调试技巧与性能验证拿到源码后我一般不会急着改页面而是先改配置文件。大屏的标题、主题色、刷新间隔、接口前缀通常都汇总在配置里。下表是常见位置文件/位置字段说明src/config/theme.jsprimaryColor主色调决定图表边框、标题装饰src/api/dashboard.jsbaseURL后端接口地址通常需要替换src/config/pointerTime.jsrefreshInterval数据轮询间隔单位毫秒改的时候注意颜色值用同一个变量避免每个图表写死的#36cbcb和主题不一致。刷新间隔不要低于 1 秒否则会打爆后端接口。免费的数据可视化大屏源码大多会带一个mock目录先用 mock 数据把图表调好再切真实接口能省下大量联调时间。调试图表时最痛苦的是改一个 option 就要重新编译。我一般会在浏览器 Console 里直接拿当前图表实例改配置// 通过 Vue 组件的 DOM 元素拿实例仅用于开发调试 const chart document.querySelector(.base-chart).__echarts_instance__; chart.setOption({ series: [ { data: [120, 200, 150, 80, 70] } ] });__echarts_instance__是 ECharts 在 DOM 元素上挂的实例属性属于内部约定不适合写进业务代码。用这个命令可以快速验证新数据是否会使图表超出边界也可以把修改后的option对象copy到剪贴板再贴回源码里。Vue Devtools 里则可以直接看props.option的深拷贝值配合watch的调试断点能更快定位是数据变了还是配置没合并上。大屏图表卡顿不一定出在 JS 逻辑也可能在绘制阶段。打开 DevTools 的 Performance录制页面滚动或数据刷新过程然后看 Main 标签页里Render和Painting的耗时。如果发现Canvas的绘制时间很长可以把 ECharts 的renderer切换成SVG用同一个数据源分别跑一遍对比帧率const chart echarts.init(el, null, { renderer: svg });观察哪个方案的帧率更稳定。大屏上图表数量多时我会更倾向 Canvas因为 SVG 的 DOM 节点数量会拖慢首屏渲染。本文还有配套的精品资源点击获取