10 分鐘上手 ECharts:從“能跑”到“生產級”的完整踩坑之旅

10 分鐘上手 ECharts:從“能跑”到“生產級”的完整踩坑筆記

如果你也曾 復制了官方 Demo 卻不知道怎么拆窗口一拉伸圖表就變形切換標簽頁后內存暴漲——這篇博客就是為你寫的。
我會用 6 個遞進版本 的源碼,帶你把一張 最簡柱狀圖 逐步進化成 可銷毀、可重建、零泄漏 的響應式組件,順便把 ECharts 的核心 API 一次性講透。


這里先附上 echart官網

請先耐心閱讀文章,文章末附上的有完整源碼

00 前言:為什么又寫一篇 ECharts 入門?

ECharts 的官方例子足夠漂亮,但大多數教程只停在 “hello world” 級別:

echarts.init(dom).setOption(option);

然而真實業務里,我們至少要回答三個問題:

  1. 窗口拉伸怎么辦?
  2. 彈窗/標簽頁切換后圖表不見了,再打開為何一片空白?
  3. 反復進出頁面,內存為何節節攀升?

今天用 不到 120 行代碼 把這三個坑填平,讓你 copy-paste 即可投產


01 最小可運行版本(Step-1)——先跑起來再說

文件:step1-hello.html

<!DOCTYPE html>
<html>
<head><meta charset="utf-8" /><title>ECharts Step1</title><script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script><style>#main{height:60vh;background:pink;}</style>
</head>
<body><div id="main"></div><script>// 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>
</html>

initsetOption 是 ECharts 的“開機鍵”和“遙控器”,一句話就能記住:

init 用于創建圖表實例,并指定渲染所需的 DOM 節點;
setOption 用于向該實例傳入配置項,以生成并更新圖表。
必須先執行 init 獲得實例,再調用 setOption,否則無法渲染。

此時打開瀏覽器,粉色區域出現柱狀圖——任務完成,但別急著提交代碼,因為拉伸窗口圖表不會跟著變


02 讓圖表“長”在窗口上(Step-2)——響應式 101

ECharts 暴露的唯一武器是:resize()
我們只需在窗口尺寸變化時調用它。

關鍵細節addEventListenerremoveEventListener 必須指向同一個函數引用,否則解綁失敗 → 內存泄漏。

文件:step2-resize.html

<!DOCTYPE html>
<html>
<head><meta charset="utf-8" /><title>ECharts Step2</title><script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script><style>#main{height:60vh;background:pink;}</style>
</head>
<body><div id="main"></div><script>const 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 DOM(Step-3)——銷毀實例

場景

  • 標簽頁切換、彈窗關閉、路由跳轉 → 容器節點被移除。
  • 用戶再次打開彈窗,發現圖表區域空白,控制臺報 Cannot read properties of null

原因
dispose() 沒調用,ECharts 實例還在舊 DOM 碎片里,內存沒釋放節點已不存在

官方原話

“在容器節點被銷毀時,總是應調用 echartsInstance.dispose 以銷毀實例釋放資源,避免內存泄漏。”

文件:step3-dispose.html

<!DOCTYPE html>
<html>
<head><meta charset="utf-8" /><title>ECharts Step3</title><script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script><style>#main{height:60vh;background:pink;}</style>
</head>
<body><div id="main"></div><button id="ctrl">銷毀</button><script>const 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,誰負責 dispose;Vue/React 在 beforeUnmountuseEffect cleanup 里統一銷毀。


04 一鍵“銷毀/重建”開關(Step-4)——完整切換邏輯

把銷毀/創建封裝成兩個純函數,再用按鈕模擬“標簽頁切換”:

文件:step4-toggle.html

<!DOCTYPE html>
<html>
<head><meta charset="utf-8" /><title>ECharts Step4</title><script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script><style>#main{height:60vh;background:pink;}</style>
</head>
<body><div id="main"></div><button id="ctrl">銷毀</button><script>const 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>
<head><meta charset="utf-8" /><title>ECharts Step-Final</title><script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script><style>#main{height:60vh;background:pink;}</style>
</head>
<body><div id="main"></div><button id="ctrl">銷毀</button><script>const 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(綁+解)×NO(1)多圖表、路由切換、彈窗堆疊場景下同樣適用。


06 直接投產:最終 120 行模板(up主寫的完整原生前端三劍客代碼)

<!DOCTYPE html>
<html><head><meta charset="utf-8" /><title>echart practice</title><script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script></head><style>#main,html,body {width: 100%;}#main {height: 400px;}
</style><body><!-- 準備的一個定義好寬高背景色的DOM容器 --><div id="main" style="background-color: pink;"></div><button id="ctrl">銷毀</button><!-- 為echart初始化實例 --><script type="text/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 換成數組或 Map,resize 監聽仍只需一次。

至此,內存泄漏、響應式、銷毀重建 三大痛點全部解決;
剩下的,就是去 ECharts 官方示例 里復制更炫的 option 了!

Happy charting! 🎉


如果有任何疑問,歡迎在評論區留言討論!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/921993.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/921993.shtml
英文地址,請注明出處:http://en.pswp.cn/news/921993.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

二級緩存在實際項目中的應用

二級緩存在項目中的應用 目錄 1. 二級緩存簡介2. 應用場景3. 重難點分析4. 結合SpringBoot使用5. 最佳實踐與案例6. 總結 1. 二級緩存簡介 1.1 什么是二級緩存 二級緩存&#xff08;Second-Level Cache&#xff09; 是Hibernate框架中的一個重要特性&#xff0c;它提供了應…

深入淺出CRC校驗:從數學原理到單周期硬件實現 (2)CRC數學多項式基礎

數學的優雅&#xff1a;剖開CRC的多項式除法核心看似復雜的CRC校驗&#xff0c;其核心建立在優雅的數學基礎之上。本文將為您揭開CRC算法的數學面紗&#xff0c;讓您真正理解多項式除法的精妙之處。模2運算&#xff1a;CRC世界的特殊算術 CRC計算建立在一種特殊的代數系統上——…

軟考初級有沒有必要考?

對正在學習相關專業的學生或者是行業新人&#xff0c;這篇文章從軟考初級的含義、適合哪些人考、考試難度等方面解答&#xff0c;幫助你判斷要不要報考。一、軟考初級是什么&#xff1f; 軟考初級是軟考體系里面的基礎級別&#xff0c;主要面向在校大學生或是IT行業新人&#x…

11 Prompt 工程進階:Few-shot 與 Chain-of-Thought

11 Prompt 工程進階&#xff1a;Few-shot 與 Chain-of-Thought 前10節總結 & 后10節展望 在前 10 節&#xff0c;我們已經完成了 AI 產品經理的入門階段&#xff1a; 1–3&#xff1a;理解了大模型的基本概念、Token、Prompt 基礎&#xff1b;4–5&#xff1a;體驗了本地部…

ARM1.(ARM體系結構)

1.基本概念嵌入式:以應用為心&#xff0c;以計算機技術為礎&#xff0c;軟便件可被的專用計算機系統。計算機系統的軟件基本組成: 系統軟件、應用軟件。計算機系統的硬件基本組成&#xff1a;運算器、控制器、存諸器、輸入設備、輸出設備日常生活中遇到的專業術語&#xff1a…

Django全棧班v1.01 Python簡介與特點 20250910

從零開始的Python編程之旅 “人生苦短&#xff0c;我用Python。”這不僅僅是Python程序員的口頭禪&#xff0c;更是對Python強大能力的最好詮釋&#xff01;&#xff01;&#xff01; 為什么全世界有超過1500萬開發者選擇Python&#xff1f; 為什么Python連續多年蟬聯最受歡…

【WebApi】什么情況開啟如何開啟緩存

在 ASP.NET Core WebAPI 中開啟緩存是優化性能、減少服務器負載和提升用戶體驗的非常重要的手段。但并非所有情況都適合開啟緩存。 下面我將從 “什么情況下開啟” 和 “如何開啟” 兩個方面為你詳細解釋。 一、什么情況下應該開啟緩存? 總的來說,緩存適用于 “變化不頻繁但…

Go語言類型斷言全解析

類型斷言的基本概念類型斷言(Type Assertion)是Go語言中用于檢查接口值底層具體類型的機制。它本質上是一種運行時類型檢查的操作&#xff0c;允許程序在運行時判斷接口變量是否持有特定的類型值&#xff0c;并提取該類型的值。這是Go語言類型系統中的一個重要特性&#xff0c;…

大模型在題目生成中的安全研究:攻擊方法與防御機制

大模型在題目生成中的安全研究&#xff1a;攻擊方法與防御機制 文章目錄大模型在題目生成中的安全研究&#xff1a;攻擊方法與防御機制一、引言二、大模型在題目生成中的安全漏洞與攻擊方法2.1 大模型在題目生成中的安全漏洞分析2.1.1 訓練數據相關漏洞2.1.2 模型架構與特性相關…

跟做springboot尚品甄選項目(二)

登錄功能的書寫 后端接口的書寫 &#xff08;1&#xff09;創建配置文件 粘貼這兩個文件&#xff08;E:\project\AllProJect\Shangpin Selection\項目材料素材\資料\資料\03-配置文件&#xff09; 在spzx-manager服務的src/resources目錄下創建application.yml、application-…

前后端接口調試提效:Postman + Mock Server 的工作流

前后端接口調試提效&#xff1a;Postman Mock Server 的工作流 &#x1f31f; Hello&#xff0c;我是摘星&#xff01; &#x1f308; 在彩虹般絢爛的技術棧中&#xff0c;我是那個永不停歇的色彩收集者。 &#x1f98b; 每一個優化都是我培育的花朵&#xff0c;每一個特性都是…

大帶寬香港云服務器在數據傳輸速度上有何優勢?

為方便站長快速部署網站、優化用戶訪問體驗&#xff0c;當下眾多實力強勁的香港數據中心&#xff0c;均推出了大帶寬云服務器產品。不過&#xff0c;市面上不少數據中心雖宣稱提供 “專屬大帶寬”&#xff0c;但其線路配置中&#xff0c;國際線路占比高、繞行鏈路多&#xff0c…

HT862 智能音頻功率放大器:為便攜音頻設備打造高效穩定的音質解決方案

在藍牙音箱、智能手機、便攜式游戲機等設備的設計中&#xff0c;音頻功率放大器是決定音質表現、續航能力與使用穩定性的關鍵部件。一款優質的音頻功放&#xff0c;不僅需要輸出足夠的功率以滿足清晰響亮的聽覺需求&#xff0c;還需在能效、溫控、適配性上達到平衡&#xff0c;…

HarmonyOS-ArkUI Web控件基礎鋪墊7-HTTP SSL認證圖解 及 Charles抓包原理 及您為什么配置對了也抓不到數據

HarmonyOS-ArkUI Web控件基礎鋪墊6--TCP協議- 流量控制算法與擁塞控制算法 HarmonyOS-ArkUI Web控件基礎鋪墊5--TCP協議- 動畫展示超時重傳&#xff0c;滑動窗口&#xff0c;快速重傳 HarmonyOS-ArkUI Web控件基礎鋪墊4--TCP協議- 斷聯-四次揮手解析 HarmonyOS-ArkUI Web控件…

【qt】通過TCP傳輸json,json里包含圖像

主要是使用協議頭 發送方connect(m_pDetectWorker, &DetectionWorker::sig_detectImg, this, [](const QJsonObject &json){// 轉換為JSON數據QJsonDocument doc(json);QByteArray jsonData doc.toJson(QJsonDocument::Compact);// 構建增強協議頭struct EnhancedHead…

四,基礎開發工具(下)

4.5自動構建make/Makefile4.5.1基本使用1示例2進一步解釋3實踐4最佳實踐4.6練習&#xff1a;進度條4.6.1倒計時4.6.2進度條version14.6.2進度條version24.7版本控制器Git4.7.1git操作1操作一次&#xff0c;以后不愁2經典"三件套"3常用4版本回退4.7.2小結4.5自動構建m…

C++基本數據類型的范圍

文章目錄不同位數的系統下各個類型所占字節數如何存儲的我發現我能搜到的相關文章都只講了這些數據類型的范圍是這樣的&#xff0c;不說實際的存儲情況&#xff0c;當你了解了類型實際是如何存儲的&#xff0c;再去記憶這些范圍就簡單了&#xff0c;所以就有了這篇文章不同位數…

基于社交媒體數據的公眾情緒指數構建與重大事件影響分析

一、引言在信息爆炸的時代&#xff0c;社交媒體&#xff08;如微博、Twitter&#xff09;已成為公眾表達情緒、討論熱點事件的主要平臺。通過分析社交媒體數據&#xff0c;可以構建公眾情緒指數&#xff0c;并進一步研究其與股市波動、政策發布等重大事件的關聯性。本文將介紹如…

OpenLayers數據源集成 -- 章節七:高德地圖集成詳解

前言在前面的文章中&#xff0c;我們學習了OpenLayers的瓦片調試&#xff08;VectorTileDebug&#xff09;技術。本文將深入探討OpenLayers中高德地圖的集成方法&#xff0c;這是WebGIS開發中接入商業地圖服務的重要技術。高德地圖作為國內領先的地圖服務提供商&#xff0c;提供…

海外代理IP平臺Top3評測:LoongProxy、神龍動態IP、IPIPGO哪家更適合你?

在當今互聯網環境中&#xff0c;代理IP服務已成為許多企業和個人用戶的剛需。無論是數據采集、市場調研還是賬號管理&#xff0c;優質的代理IP都能大幅提升工作效率。本文將針對LoongProxy、神龍海外動態IP和IPIPGO這三家主流代理IP服務商進行橫向評測&#xff0c;幫助你根據自…