昌平网站制作开发公司,什么程序做教育网站好,网站建设策略,广东省建设发展深圳公司10 分钟上手 ECharts#xff1a;从“能跑”到“生产级”的完整踩坑笔记 如果你也曾 复制了官方 Demo 却不知道怎么拆、窗口一拉伸图表就变形、切换标签页后内存暴涨——这篇博客就是为你写的。 我会用 6 个递进版本 的源码#xff0c;带你把一张 最简柱状图 逐步进化成 可销毁…10 分钟上手 ECharts从“能跑”到“生产级”的完整踩坑笔记 如果你也曾 复制了官方 Demo 却不知道怎么拆、窗口一拉伸图表就变形、切换标签页后内存暴涨——这篇博客就是为你写的。 我会用 6 个递进版本 的源码带你把一张 最简柱状图 逐步进化成 可销毁、可重建、零泄漏 的响应式组件顺便把 ECharts 的核心 API 一次性讲透。 这里先附上 echart官网
请先耐心阅读文章文章末附上的有完整源码
00 前言为什么又写一篇 ECharts 入门
ECharts 的官方例子足够漂亮但大多数教程只停在 “hello world” 级别
echarts.init(dom).setOption(option);然而真实业务里我们至少要回答三个问题
窗口拉伸怎么办弹窗/标签页切换后图表不见了再打开为何一片空白反复进出页面内存为何节节攀升
今天用 不到 120 行代码 把这三个坑填平让你 copy-paste 即可投产。 01 最小可运行版本Step-1——先跑起来再说
文件step1-hello.html
!DOCTYPE html
html
headmeta charsetutf-8 /titleECharts Step1/titlescript srchttps://cdn.jsdelivr.net/npm/echarts5.4.3/dist/echarts.min.js/scriptstyle#main{height:60vh;background:pink;}/style
/head
bodydiv idmain/divscript// 1. 描述你要画什么const option {title: { text: First ECharts },tooltip: {},legend: { data: [销量] },xAxis: { data: [衬衫,羊毛衫,裤子,袜子,高跟鞋] },yAxis: {},series: [{ name: 销量, type: bar, data: [5,20,36,10,10] }]};// 2. init → setOption 两行经典 APIconst myChart echarts.init(document.getElementById(main));myChart.setOption(option);/script
/body
/htmlinit 和 setOption 是 ECharts 的“开机键”和“遥控器”一句话就能记住
init 用于创建图表实例并指定渲染所需的 DOM 节点 setOption 用于向该实例传入配置项以生成并更新图表。 必须先执行 init 获得实例再调用 setOption否则无法渲染。
此时打开浏览器粉色区域出现柱状图——任务完成但别急着提交代码因为拉伸窗口图表不会跟着变。 02 让图表“长”在窗口上Step-2——响应式 101
ECharts 暴露的唯一武器是resize() 我们只需在窗口尺寸变化时调用它。
关键细节addEventListener 与 removeEventListener 必须指向同一个函数引用否则解绑失败 → 内存泄漏。
文件step2-resize.html
!DOCTYPE html
html
headmeta charsetutf-8 /titleECharts Step2/titlescript srchttps://cdn.jsdelivr.net/npm/echarts5.4.3/dist/echarts.min.js/scriptstyle#main{height:60vh;background:pink;}/style
/head
bodydiv idmain/divscriptconst option {title: { text: First ECharts },tooltip: {},legend: { data: [销量] },xAxis: { data: [衬衫,羊毛衫,裤子,袜子,高跟鞋] },yAxis: {},series: [{ name: 销量, type: bar, data: [5,20,36,10,10] }]};const myChart echarts.init(document.getElementById(main));myChart.setOption(option);/* 统一句柄后面销毁时还要用 */const handleResize () myChart myChart.resize();window.addEventListener(resize, handleResize);/script
/body
/html为什么这个匿名函数要这样写 const handleResize () myChart myChart.resize();
JavaScript 的 运算符具备短路特性左侧表达式为真时才继续执行右侧左侧为假时整个表达式立即返回假右侧代码不会被执行。
在 resize 场景下左侧的 myChart 若因销毁而变为 null右侧的 resize() 调用就会被自动跳过从而避免空指针错误实现**一行代码完成“存在判断 方法调用”**的防御式逻辑。
现在拉伸窗口柱子实时重排响应式闭环达成。 03 弹窗关闭 ≠ 直接 remove DOMStep-3——销毁实例
场景
标签页切换、弹窗关闭、路由跳转 → 容器节点被移除。用户再次打开弹窗发现图表区域空白控制台报 Cannot read properties of null。
原因 dispose() 没调用ECharts 实例还在旧 DOM 碎片里内存没释放节点已不存在。
官方原话 “在容器节点被销毁时总是应调用 echartsInstance.dispose 以销毁实例释放资源避免内存泄漏。” 文件step3-dispose.html
!DOCTYPE html
html
headmeta charsetutf-8 /titleECharts Step3/titlescript srchttps://cdn.jsdelivr.net/npm/echarts5.4.3/dist/echarts.min.js/scriptstyle#main{height:60vh;background:pink;}/style
/head
bodydiv idmain/divbutton idctrl销毁/buttonscriptconst option { ... }; // 同上const myChart echarts.init(document.getElementById(main));myChart.setOption(option);const handleResize () myChart myChart.resize();window.addEventListener(resize, handleResize);/* 释放内存的逻辑 */const destroyChart () {if (myChart) {myChart.dispose(); // 释放 WebGL/Canvas 资源myChart null; // 告诉垃圾回收器“我清空了”window.removeEventListener(resize, handleResize);}};document.getElementById(ctrl).addEventListener(click, destroyChart);/script
/body
/html最佳实践 谁先删 DOM谁负责 disposeVue/React 在 beforeUnmount 或 useEffect cleanup 里统一销毁。 04 一键“销毁/重建”开关Step-4——完整切换逻辑
把销毁/创建封装成两个纯函数再用按钮模拟“标签页切换”
文件step4-toggle.html
!DOCTYPE html
html
headmeta charsetutf-8 /titleECharts Step4/titlescript srchttps://cdn.jsdelivr.net/npm/echarts5.4.3/dist/echarts.min.js/scriptstyle#main{height:60vh;background:pink;}/style
/head
bodydiv idmain/divbutton idctrl销毁/buttonscriptconst option { ... }; // 同上let myChart null;let exist true; // 当前是否存在const btn document.getElementById(ctrl);const createChart () {myChart echarts.init(document.getElementById(main));myChart.setOption(option);window.addEventListener(resize, handleResize);};const destroyChart () {if (myChart) {myChart.dispose();myChart null;window.removeEventListener(resize, handleResize);}};btn.addEventListener(click, () {exist ? destroyChart() : createChart();exist !exist;btn.innerText exist ? 销毁 : 创建;});createChart(); // 首次自动创建/script
/body
/html第一次点击 → 销毁按钮文字变“创建”第二次点击 → 重建按钮文字变“销毁”
内存监控Chrome DevTools → Memory → Heap snapshot反复切换节点数不再上涨。 05 算法级优化Step-Final——终身只绑一次 resize
大体写完了但细节和性能上我们还可以进行优化比如通过引入三元运算符或者封装函数等方式来优化性能
问题 每次重建都 addEventListener → 理论上会重复绑定同一类型事件虽然浏览器会去重但仍不优雅。
思路 resize 监听与图表生命周期脱钩只要全局存在一次即可内部用“懒调度”判断实例是否存在。
文件step-final.html
!DOCTYPE html
html
headmeta charsetutf-8 /titleECharts Step-Final/titlescript srchttps://cdn.jsdelivr.net/npm/echarts5.4.3/dist/echarts.min.js/scriptstyle#main{height:60vh;background:pink;}/style
/head
bodydiv idmain/divbutton idctrl销毁/buttonscriptconst option { ... }; // 同上let myChart null;let exist true;const btn document.getElementById(ctrl);/* 终身只绑一次 resize无论有多少图表 */window.addEventListener(resize, () myChart myChart.resize());const createChart () {myChart echarts.init(document.getElementById(main));myChart.setOption(option);};const destroyChart () {myChart myChart.dispose();myChart null;};btn.addEventListener(click, () {exist ? destroyChart() : createChart(); // 表格存在就执行销毁不存在就执行创建exist !exist;btn.innerText exist ? 销毁 : 创建;});createChart(); // 首次自动创建/script
/body
/html复杂度从 O(绑解)×N → O(1)多图表、路由切换、弹窗堆叠场景下同样适用。 06 直接投产最终 120 行模板up主写的完整原生前端三剑客代码
!DOCTYPE html
htmlheadmeta charsetutf-8 /titleechart practice/titlescript srchttps://cdn.jsdelivr.net/npm/echarts5.4.3/dist/echarts.min.js/script/headstyle#main,html,body {width: 100%;}#main {height: 400px;}
/stylebody!-- 准备的一个定义好宽高背景色的DOM容器 --div idmain stylebackground-color: pink;/divbutton idctrl销毁/button!-- 为echart初始化实例 --script typetext/javascript// type后面那一坨都是老版html需要写的用于指定脚本语言现在HTML5可以省略了// TODO.1 相关变量配置// 表格let myChart null// 配置项let option {// 标题组件title: {text: First Echart Practice, // 主标题文本subtext: 副标题, // 副标题// left right center 用来控制水平位置// top 用于控制垂直位置}, // 提示框组件鼠标悬停时弹出tooltip: {trigger: item, // 触发方式item(单点) | axis(坐标轴) | none// formatter: {b}br/{a}: {c} // 自定义浮层内容模板或回调函数},// 图例组件点击可控制系列显隐legend: {data: [销量], // 必须与 series[i].name 保持一致才能对应// orient: horizontal, // 排列方向horizontal|vertical// left: right, // 位置同 title},// X 轴xAxis: {data: [衬衫, 羊毛衫, 裤子, 袜子, 高跟鞋]},// Y 轴yAxis: {},// 系列列表真正决定“画什么图”series: [{name: 销量, // 与 legend.data 对应悬停提示也会用 type: bar, data: [5, 20, 36, 10, 10,20]}],}// TODO.2 监听页面大小变化事件const handleResize () myChart myChart.resize() // 防御式写法如果myChart已被销毁就短路返回不会执行 resize()如果myChart存在正常调resize()让图表随窗口大小重绘。// TODO.3 表格创建初始化函数const createChart () {myChart echarts.init(document.getElementById(main))console.log(表格对象实例化完成)myChart.setOption(option)console.log(表格对象展示完成)window.addEventListener(resize, handleResize) // 浏览器原生事件当窗口(window)大小发生变化 时触发console.log(表格已建立)}// TODO.4 销毁实例const destroyChart () {myChart.dispose(); // 释放内存myChart null; // 垃圾回收将变量制空window.removeEventListener(resize, handleResize);console.log(图表已销毁);}createChart()// TODO.5 销毁和创建实例let ctrlFactor true // 为true时表格存在const btn document.getElementById(ctrl)console.log(初始化创建成功)btn.addEventListener(click, () {btn.innerText ctrlFactor ? 创建 : 销毁 // 通过控制因子判断按钮文字内容ctrlFactor ? destroyChart() : createChart() // 通过控制因子去判断表格操作ctrlFactor !ctrlFactor})/script/body
/html复制→保存→打开浏览器你就拥有了一个
响应式可销毁/重建零内存泄漏
的 ECharts 基准模板后续只需替换 option 即可快速出图 07 结语把模板塞进你的脚手架
Vue在 onMounted 调用 createChartonUnmounted 调用 destroyChart。React在 useEffect(() { createChart(); return destroyChart; }, []); 即可。多图表把 myChart 换成数组或 Mapresize 监听仍只需一次。
至此内存泄漏、响应式、销毁重建 三大痛点全部解决 剩下的就是去 ECharts 官方示例 里复制更炫的 option 了
Happy charting! 如果有任何疑问欢迎在评论区留言讨论