React+TS前臺項目實戰(二十六)-- 高性能可配置Echarts圖表組件封裝

文章目錄

  • 前言
  • CommonChart組件
    • 1. 功能分析
    • 2. 代碼+詳細注釋
    • 3. 使用到的全局hook代碼
    • 4. 使用方式
    • 5. 效果展示
  • 總結


前言

Echarts圖表在項目中經常用到,然而,重復編寫初始化,更新,以及清除實例等動作對于開發人員來說是一種浪費時間和精力。因此,在這篇文章中,將封裝一個 “高性能可配置Echarts組件” ,簡化開發的工作流程,提高數據可視化的效率和質量。

CommonChart組件

1. 功能分析

(1)可以渲染多種類型的圖表,包括折線圖、柱狀圖、餅圖、地圖和散點圖
(2)通過傳入的 option 屬性,配置圖表的各種參數和樣式
(4)通過傳入的 onClick 屬性,處理圖表元素的點擊事件
(5)通過傳入的 notMerge 屬性,控制是否合并圖表配置
(6)通過傳入的 lazyUpdate 屬性,控制是否懶渲染圖表
(7)通過傳入的 style 屬性,設置圖表容器的樣式
(8)通過傳入的 className 屬性,自定義圖表容器的額外類名
(9)通過監聽窗口大小變化,自動調整圖表的大小
(10)使用 usePrevious、useWindowResize 和 useEffect 等鉤子來提高組件性能并避免不必要的渲染

2. 代碼+詳細注釋

// @/components/Echarts/commom/index.tsx
import { useRef, useEffect, CSSProperties } from "react";
// 引入 Echarts 的各種圖表組件和組件配置,后續備用
import "echarts/lib/chart/line"; // 折線圖
import "echarts/lib/chart/bar"; // 柱狀圖
import "echarts/lib/chart/pie"; // 餅圖
import "echarts/lib/chart/map"; // 地圖
import "echarts/lib/chart/scatter"; // 散點圖
import "echarts/lib/component/tooltip"; // 提示框組件
import "echarts/lib/component/title"; // 標題組件
import "echarts/lib/component/legend"; // 圖例組件
import "echarts/lib/component/markLine"; // 標線組件
import "echarts/lib/component/dataZoom"; // 數據區域縮放組件
import "echarts/lib/component/brush"; // 刷選組件
// 引入 Echarts 的類型聲明
import * as echarts from "echarts";
import { ECharts, EChartOption } from "echarts";
// 引入自定義的鉤子函數和公共函數
import { useWindowResize, usePrevious } from "@/hooks";
import { isDeepEqual } from "@/utils";
/*** 公共 Echarts 業務靈巧組件,可在項目中重復使用** @param {Object} props - 組件屬性* @param {EChartOption} props.option - Echarts 配置項* @param {Function} [props.onClick] - 點擊事件處理函數* @param {boolean} [props.notMerge=false] - 是否不合并數據* @param {boolean} [props.lazyUpdate=false] - 是否懶渲染* @param {CSSProperties} [props.style] - 組件樣式* @param {string} [props.className] - 組件類名* @returns {JSX.Element} - React 組件*/
type Props = {option: EChartOption;onClick?: (param: echarts.CallbackDataParams) => void;notMerge?: boolean;lazyUpdate?: boolean;style?: CSSProperties;className?: string;
};
const CommonChart = (props: Props) => {// 解構屬性,并設置默認值const {option,onClick, // 點擊事件處理函數notMerge = false, // 是否不合并數據,默認為 falselazyUpdate = false, // 是否懶渲染,默認為 falsestyle, // 組件樣式className = "", // 組件類名,默認為空字符串} = props;// 創建 ref 來引用 div 元素,并初始化 chartInstanceRef 為 nullconst chartRef = useRef<HTMLDivElement>(null);const chartInstanceRef = useRef<ECharts | null>(null);// 使用 usePrevious 鉤子函數來記錄上一次的 option 和 onClick 值const prevOption = usePrevious(option);const prevClickEvent = usePrevious(onClick);useEffect(() => {// 定義一個變量來存儲圖表實例let chartInstance: ECharts | null = null;if (chartRef.current) {// 如果圖表實例不存在,則初始化if (!chartInstanceRef.current) {const hasRenderInstance = echarts.getInstanceByDom(chartRef.current);if (hasRenderInstance) {hasRenderInstance.dispose();}chartInstanceRef.current = echarts.init(chartRef.current);}// 暫存當前的圖表實例chartInstance = chartInstanceRef.current;// 如果 option 或 onClick 值發生變化,則重新渲染try {if (!isDeepEqual(prevOption, option, ["formatter"])) {chartInstance.setOption(option, { notMerge, lazyUpdate });}if (onClick && typeof onClick === "function" && onClick !== prevClickEvent) {chartInstance.on("click", onClick);}} catch (error) {chartInstance && chartInstance.dispose();}}}, [option, onClick, notMerge, lazyUpdate, prevOption, prevClickEvent]);// 監聽窗口大小變化,當窗口大小變化時,重新渲染圖表useWindowResize(() => {if (chartInstanceRef.current) {chartInstanceRef.current?.resize();}});return <div style={{ ...style }} className={className} ref={chartRef}></div>;
};export { CommonChart };

3. 使用到的全局hook代碼

// @/utils/index
// 深度判斷兩個對象某個屬性的值是否相等
export const isDeepEqual = (left: any, right: any, ignoredKeys?: string[]): boolean => {const equal = (a: any, b: any): boolean => {if (a === b) return trueif (a && b && typeof a === 'object' && typeof b === 'object') {if (a.constructor !== b.constructor) return falselet lengthlet iif (Array.isArray(a)) {length = a.lengthif (length !== b.length) return falsefor (i = length; i-- !== 0;) {if (!equal(a[i], b[i])) return false}return true}if (a instanceof Map && b instanceof Map) {if (a.size !== b.size) return falsefor (i of a.entries()) {if (!b.has(i[0])) return false}for (i of a.entries()) {if (!equal(i[1], b.get(i[0]))) return false}return true}if (a instanceof Set && b instanceof Set) {if (a.size !== b.size) return falsefor (i of a.entries()) if (!b.has(i[0])) return falsereturn true}if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flagsif (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf()if (a.toString !== Object.prototype.toString) return a.toString() === b.toString()const keys = Object.keys(a)length = keys.lengthif (length !== Object.keys(b).length) return falsefor (i = length; i-- !== 0;) {if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false}for (i = length; i-- !== 0;) {const key = keys[i]if (key === '_owner' && a.$$typeof) {// Reactcontinue}if (ignoredKeys && ignoredKeys.includes(key)) {continue}if (!equal(a[key], b[key])) return false}return true}// eslint-disable-next-line no-self-comparereturn a !== a && b !== b}return equal(left, right)
}
--------------------------------------------------------------------------
// @/hooks/index.ts
/*** Returns the value of the argument from the previous render* @param {T} value* @returns {T | undefined} previous value* @see https://react-hooks-library.vercel.app/core/usePrevious*/
export function usePrevious<T>(value: T): T | undefined {const ref = useRef<T>()useEffect(() => {ref.current = value}, [value])return ref.current
}export function useWindowResize(callback: (event: UIEvent) => void) {useEffect(() => {window.addEventListener('resize', callback)return () => window.removeEventListener('resize', callback)}, [callback])
}

4. 使用方式

// 引入組件和echarts
import { CommonChart } from "@/components/Echarts/common";
import echarts from "echarts/lib/echarts";
// 使用
const useOption = () => {return (data: any): echarts.EChartOption => {return {color: ["#ffffff"],title: {text: "圖表y軸時間",textAlign: "left",textStyle: {color: "#ffffff",fontSize: 12,fontWeight: "lighter",fontFamily: "Lato",},},grid: {left: "2%",right: "3%",top: "15%",bottom: "2%",containLabel: true,},xAxis: [{axisLine: {lineStyle: {color: "#ffffff",width: 1,},},data: data.map((item: any) => item.xTime),axisLabel: {formatter: (value: string) => value,},boundaryGap: false,},],yAxis: [{position: "left",type: "value",scale: true,axisLine: {lineStyle: {color: "#ffffff",width: 1,},},splitLine: {lineStyle: {color: "#ffffff",width: 0.5,opacity: 0.2,},},axisLabel: {formatter: (value: string) => new BigNumber(value),},boundaryGap: ["5%", "2%"],},{position: "right",type: "value",axisLine: {lineStyle: {color: "#ffffff",width: 1,},},},],series: [{name: t("block.hash_rate"),type: "line",yAxisIndex: 0,lineStyle: {color: "#ffffff",width: 1,},symbol: "none",data: data.map((item: any) => new BigNumber(item.yValue).toNumber()),},],};};
};
const echartData = [{ xTime: "2020-01-01", yValue: "1500" },{ xTime: "2020-01-02", yValue: "5220" },{ xTime: "2020-01-03", yValue: "4000" },{ xTime: "2020-01-04", yValue: "3500" },{ xTime: "2020-01-05", yValue: "7800" },
];
const parseOption = useOption();
<CommonChartoption={parseOption(echartData, true)}notMergelazyUpdatestyle={{height: "180px",}}
></ChartBlock>

5. 效果展示

在這里插入圖片描述


總結

下一篇講【首頁響應式搭建以及真實數據渲染】。關注本欄目,將實時更新。

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

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

相關文章

LVS-DR負載均衡

LVS-DR負載均衡 LVS—DR工作模式 原理 客戶端訪問調度器的VIP地址&#xff0c;在路由器上應該設置VIP跟調度器的一對一的映射關系&#xff0c;調度器根據調度算法將該請求“調度“到后端真實服務器&#xff0c;真實服務器處理完畢后直接將處理后的應答報文發送給路由器&#xf…

EDI安全:如何在2024年保護您的數據免受安全和隱私威脅

電子數據交換&#xff08;EDI&#xff09;支持使用標準化格式在組織之間自動交換業務文檔。這種數字化轉型徹底改變了業務通信&#xff0c;消除了對紙質交易的需求并加速了交易。然而&#xff0c;隨著越來越依賴 EDI 來傳輸發票、采購訂單和發貨通知等敏感數據&#xff0c;EDI …

【跨境分享】中國商家如何卷到國外?電商獨立站和電商平臺的優勢對比

為什么要選擇獨立站而不是電商平臺 對于跨境電商經營者而言&#xff0c;采取多平臺、多站點的運營策略是至關重要的戰略布局。這一做法不僅有助于分散風險&#xff0c;避免將所有投資集中于單一市場&#xff0c;從而降低“所有雞蛋置于同一籃子”的隱患&#xff0c;而且有利于拓…

【友邦保險-注冊安全分析報告】

前言 由于網站注冊入口容易被黑客攻擊&#xff0c;存在如下安全問題&#xff1a; 暴力破解密碼&#xff0c;造成用戶信息泄露短信盜刷的安全問題&#xff0c;影響業務及導致用戶投訴帶來經濟損失&#xff0c;尤其是后付費客戶&#xff0c;風險巨大&#xff0c;造成虧損無底洞…

華為od相關信息分享

2024年OD統一考試&#xff08;D卷&#xff09;完整題庫&#xff1a;華為OD機試2024年最新題庫&#xff08;Python、JAVA、C合集&#xff09; 問 1.什么是華為od&#xff1f; 答&#xff1a;OD全稱是Outsourcing Dispacth&#xff0c;即外包派遣&#xff0c;是華為和外企德科…

金蝶云蒼穹-插件開發(三)關于基礎資料/單據實體的id

基礎資料/單據實體的id 每個基礎資料和單據的實體&#xff0c;都有一個id字段&#xff0c;這個id是其一個唯一性標識&#xff0c;就類似于這個實體的身份證號一樣。通常&#xff0c;這個id用來找到指定的實體。這個id在代碼中都是long類型接收的。 如果基礎資料/單據里面有字…

Kafka日志處理:深入了解偏移量查找與切分文件

我是小米,一個喜歡分享技術的29歲程序員。如果你喜歡我的文章,歡迎關注我的微信公眾號“軟件求生”,獲取更多技術干貨! Hello, 大家好!我是你們的技術小伙伴小米,今天要和大家分享一些關于Kafka日志處理的深入知識。我們將討論如何查看偏移量為23的消息,以及Kafka日志分…

重載、覆蓋(重寫)、重定義(同名隱藏)的區別 (超詳解)

&#x1f4da; 重載&#xff08;Overloading&#xff09;、覆蓋&#xff08;Overriding&#xff09;、重定義&#xff08;Hiding&#xff09;是面向對象編程中常見的概念&#xff0c;它們分別用于描述不同情況下函數或方法的行為。 目錄 重載&#xff08;Overloading&#xff…

ST7789 linux4.x驅動

文章目錄 ST7789 linux4.x驅動設備樹配置驅動程序編譯驅動測試驅動 ST7789 linux4.x驅動 設備樹配置 pinctrl_ecspi2_cs_1: ecspi2_cs_grp-1 {fsl,pins <MX6UL_PAD_CSI_DATA01__GPIO4_IO22 0x40017059>; };pinctrl_ecspi2_1: escpi2grp {fsl,pins <MX6UL_PAD_CSI_…

RocketMQ快速入門:主從、集群模式原理及搭建實操(十一)

目錄 0. 引言1. 前備知識1.1 namesrv集群模式1.2 broker集群模式1.2 broker主從復制原理 2. 集群部署2.1 環境準備2.2 配置講解2.3 一主多從模式部署2.4 多主無從模式部署2.5 多主多從模式部署 3. 總結 0. 引言 在學習完rocketmq的基礎知識后&#xff0c;我們進入rocketmq高可…

痙攣性斜頸對生活有哪些影響?

痙攣性斜頸&#xff0c;這個名字聽起來可能并不熟悉&#xff0c;但它實際上是一種神經系統疾病&#xff0c;影響著全球數百萬人的生活質量。它以一種無法控制的方式&#xff0c;使患者的頸部肌肉發生不自主的收縮&#xff0c;導致頭部姿勢異常。對于患者來說&#xff0c;痙攣性…

和Bug較勁的第n天:[Error: Unable to open snapshot file: No such file or directory]

問題描述 最近做了一個小demo&#xff0c;基于parcel的&#xff0c;在遷移倉庫的時候發生了一個報錯 [Error: Unable to open snapshot file: No such file or directory] 原因分析&#xff1a; 在遷移倉庫的時候&#xff0c;我將項目放入了一個以中文命名的文件夾里&#xf…

模電基礎 - 信號的運算和處理

目錄 一. 簡介 二. 加法 三. 減法 四. 乘法 五. 除法 六. 總結 一. 簡介 在模電基礎中&#xff0c;信號的運算和處理是非常重要的內容。 信號的運算包括加法、減法、乘法、除法等。通過使用集成運放&#xff0c;可以很容易地實現這些運算。例如&#xff0c;利用反相輸入…

算法的幾種常見形式

算法&#xff08;Algorithm&#xff09; 算法&#xff08;Algorithm&#xff09;是指解決問題或完成任務的一系列明確的步驟或規則。在計算機科學中&#xff0c;算法是程序的核心部分&#xff0c;它定義了如何執行特定的任務或解決特定的問題。算法可以用多種方式來表示和實現…

宜春旅游集散中心展廳OLED透明屏方案設計

一、項目概述 為提升宜春旅游集散中心展廳的現代化展示水平&#xff0c;增強游客的參觀體驗&#xff0c;我們計劃在展廳的核心區域引入OLED透明屏技術。該方案旨在通過高科技的視覺呈現方式&#xff0c;將展品信息以虛擬與現實相結合的方式展現&#xff0c;打造出一個既具科技感…

谷粒商城學習筆記-22-分布式組件-SpringCloud-OpenFeign測試遠程調用

文章目錄 一&#xff0c;OpenFeign的簡介二&#xff0c;OpenFeign的使用步驟1&#xff0c;場景說明2&#xff0c;引入依賴2&#xff0c;開啟OpenFeign3&#xff0c;編寫Feign接口4&#xff0c;使用feign調用遠程接口5&#xff0c;驗證 錯誤記錄 上一節學習了注冊中心&#xff0…

鼠標錄制工具|鍵鼠軌跡錄制,實現自動辦公

利用鍵鼠錄制工具錄制固定的鼠標點擊、鍵盤輸入等操作&#xff0c;實現自動化執行固定操作&#xff0c;節省時間。鼠標錄制功能可以錄制多步驟的操作&#xff0c;將錄制的動作保存并命名&#xff0c;甚至可以編輯操作速度。下面將演示幾種生活中常見的案例&#xff0c;詳細講解…

企業微信hook接口協議,移除群成員通知

移除群成員通知 返回示例 {"flag": 0, "receiver": 0, "sender_name": "", "is_room": 1, "server_id": 15318083, "send_time": 1687688952, "sender": 1688855749266556, "referid&…

k8s中使用cert-manager生成自簽名證書

一、安裝 cert-manager 注意查看cert-manager和K8S支持的對應版本 我的 k8sv1.28.2&#xff0c;cert-manager v1.12.11 下載 cert-manager.yaml 文件&#xff0c;執行 kubectl apply -f cert-manager.yaml二、生成自簽名證書 cert-selfsigned.yaml apiVersion: cert-manage…

【SpringBoot】隨機鹽值+雙重SHA256加密實戰

目錄&#xff1a; 1.SHA-256和隨機鹽值 2.前端實現 3.后端實現 1.SHA-256和Salt 1.1.什么是SHA-256 SHA-256是一種信息摘要算法&#xff0c;也是一種密碼散列函數。對于任意長度的消息&#xff0c;SHA256都會產生一個256bit長的散列值&#xff08;哈希值&#xff09;&…