主頁 > 企業開發 > 記錄--Vue3 封裝 ECharts 通用組件

記錄--Vue3 封裝 ECharts 通用組件

2023-06-20 09:23:49 企業開發

這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

按需匯入的組態檔

組態檔這里就不再贅述,內容都是一樣的,主打一個隨用隨取,按需匯入,

import * as echarts from "echarts/core";
// 引入用到的圖表
import { LineChart, type LineSeriesOption} from "echarts/charts";
// 引入提示框、資料集等組件
import {
  TitleComponent,
  TooltipComponent,
  GridComponent,
  LegendComponent,
  type TooltipComponentOption,
  type TitleComponentOption,
  type GridComponentOption,
  type LegendComponentOption
} from "echarts/components";
// 引入標簽自動布局、全域過渡影片等特性
import { LabelLayout } from "echarts/features";
// 引入 Canvas 渲染器,必須
import { CanvasRenderer } from "echarts/renderers";

import type { ComposeOption } from "echarts/core";

// 通過 ComposeOption 來組合出一個只有必須組件和圖表的 Option 型別
export type ECOption = ComposeOption<
  | LineSeriesOption
  | GridComponentOption
  | TitleComponentOption
  | TooltipComponentOption
  | LegendComponentOption
>;

// 注冊必須的組件
echarts.use([
  LineChart,
  TitleComponent,
  TooltipComponent,
  GridComponent,
  CanvasRenderer,
  LabelLayout,
  LegendComponent
]);

export default echarts;

基本封裝

DOM結構和實體化

<script setup lang="ts">
import { Ref, onMounted, onBeforeUnmount } from "vue";
import { type EChartsType } from "echarts/core";

interface Props {
  option: ECOption;
  theme?: Object | string; // 主題
}

const props = withDefaults(defineProps<Props>(), {
  theme: null
});

const chartRef = ref<Ref<HTMLDivElement>>(null);
const chartInstance = ref<EChartsType>();

// 繪制
const draw = () => {
  if (chartInstance.value) {
    chartInstance.value.setOption(props.option, { notMerge: true });
  }
};

// 初始化
const init = () => {
  if (!chartRef.value) return;

  // 校驗 Dom 節點上是否已經掛載了 ECharts 實體,只有未掛載時才初始化
  chartInstance.value = https://www.cnblogs.com/smileZAZ/archive/2023/06/19/echarts.getInstanceByDom(chartRef.value);
  if (!chartInstance.value) {
    chartInstance.value = echarts.init(
        chartRef.value,
        props.theme,
        { renderer:"canvas" }
    );

    draw();
  }
};

watch(props, () => {
  draw();
});

onMounted(() => {
  init();
});

onBeforeUnmount(() => {
  // 容器被銷毀之后,銷毀實體,避免記憶體泄漏
  chartInstance.value?.dispose();
});
</script>

<template>
  <div id="echart" ref="chartRef" :style="{ width: '100px', height: '120px' }" />
</template>

chartRef:當前的 DOM 節點,即 ECharts 的容器;

chartInstance:當前 DOM 節點掛載的 ECharts 實體,可用于呼叫實體上的方法,注冊事件,自適應等;

draw:用于繪制 ECharts 圖表,本質是呼叫實體的 setOption 方法;

init:初始化,在此獲取 DOM 節點,掛載實體,注冊事件,并呼叫 draw 繪制圖表,

Cannot read properties of undefined (reading 'type')

請注意,上述代碼目前還不能正常運行,這里會遇到第一個坑 —— 圖表無法顯示,這是 React 中沒有碰到的:

 出現這種問題是因為,我們使用 ref 接收了 echarts.init 的實體,這會導致 chartInstance 被代理成為回應式物件,影響了 ECharts 對內部屬性的訪問,Echarts 官方 FAQ 也闡述了該問題:

 

所以,我們有兩種解決方法:

  1. 使用 shallowRef 替換 ref
  2. 使用 ref + markRaw

shallowRef 和 ref() 不同之處在于,淺層 ref 的內部值將會原樣存盤和暴露,并且不會被深層遞回地轉為回應式,只有對 .value 的訪問是回應式的,

而 markRaw 則會將一個物件標記為不可被轉為代理,回傳該物件本身,在有些值不應該是回應式的場景中,例如復雜的第三方類實體或 Vue 組件物件,這很有用,

 我們這里使用 markRaw 對 init 進行包裹:

chartInstance.value = https://www.cnblogs.com/smileZAZ/archive/2023/06/19/markRaw(
  echarts.init(
      chartRef.value,
      props.theme,
      { renderer:"canvas" }
  )
);

視窗防抖自適應

這里和 React 中就差不多了,主要安利一個 Vue 官方團隊維護的 hooks 庫:vueuse ,和 React 中的 ahooks 一樣,封裝了很多實用的 hooks,我們可以使用 useDebounceFn 來優化自適應函式:

import { useDebounceFn } from "@vueuse/core";

// 視窗自適應并開啟過渡影片
const resize = () => {
  if (chartInstance.value) {
    chartInstance.value.resize({ animation: { duration: 300 } });
  }
};

// 自適應防抖優化
const debouncedResize = useDebounceFn(resize, 500, { maxWait: 800 });

onMounted(() => {
  window.addEventListener("resize", debouncedResize);
});

onBeforeUnmount(() => {
  window.removeEventListener("resize", debouncedResize);
});

額外監聽寬高

目前,圖示的大小還是寫死的,現在我們支持 props 傳遞寬高來自定義圖表大小:

interface Props {
  option: ECOption;
  theme?: Object | string;
  width: string;
  height: string;
}

<template>
  <div
    id="echart"
    ref="chartRef"
    :style="{ width: props.width, height: props.height }"
  />
</template>

請注意:在使用時,我們必須指定容器的寬高,否則無法顯示,因為圖表在繪制時會自動獲取父容器的寬高,

flex/grid 布局下 resize 失效的問題

這個問題剛遇到著實有點蛋疼,摸了蠻久,而 bug 觸發的條件也比較奇葩,但也比較常見:

  1. 在父組件中,復用多個 ECharts 組件;
  2. 使用了 flex 或 grid 這種沒有明確給定寬高的布局;

此時會發現:當前視窗放大,正常觸發 resize, 圖表會隨之放大,但是,此時再縮小視窗,雖然也會觸發 resize,但是圖表的大小卻縮不回來了......

一開始還以為是我封裝的寫法有問題,直到搜到了ECharts 官方的 issues 才發現原來不止我一個遇到了??

我的理解是:首先,無論什么布局 echarts 取的都是 dom 的 clientWidth 和 clientHeight 作為容器寬高,其次,由于 flex、grid 這種布局可以不需要顯示地指定 width、height,這就導致 echarts 在自適應的程序中無法明確地獲取到容器的寬高,所以即便觸發了 resize 事件,但是重繪的圖表還是之前默認的寬高,

解決方案

給每個 flex-itemgrid-item 自適應的寬或者高都設定一個最小值(我專案中的寬是自適應的,高度是固定的):

.chart-item {
    flex: 1;
    min-width: 30vh;
    height: 300px;
}

這里不得不吐槽下,早在2017年就有人提出過這個問題,2020年終于給出了解釋,但是現在都2023了,這個問題還沒有得到解決,issues 還 open 著 ??

系結滑鼠事件

我們可以給圖表中的一些組件添加額外的互動,比如給 title 滑鼠 hover 事件等,記得在需要使用事件的組件上添加 triggerEvent: true 屬性,

我們演示滑鼠移入 title 顯示 y軸 name,滑鼠移出 title 隱藏 y軸 name 的需求:

interface Props {
  // 略...
  onm ouseover?: (...args: any[]) => any;
  onm ouseout?: (...args: any[]) => any;
}

const init = () => {
    // 略......

    // 系結 mousehover 事件:
    if (props.onMouseover) {
      chartInstance.value.on("mouseover", (event: Object) => {
        props.onMouseover(event, chartInstance.value, props.option);
      });
    }
    
    // 系結 mouseout 事件:
    if (props.onMouseout) {
      chartInstance.value.on("mouseout", (event: Object) => {
        props.onMouseout(event, chartInstance.value, props.option);
      });
    }
  }
};
在上述注冊的回呼事件中,我們將 ECharts 實體和傳入的 option 重新傳出去,這樣可以就在外面重新配置 option 并呼叫實體的方法進行圖表的重繪了:
import Chart from "@/components/BaseChart/index.vue";
import type { EChartsType } from "echarts/core";
import type { ECOption } from "@/components/BaseChart/config";
import type { YAXisOption } from "echarts/types/dist/shared";

// 滑鼠移入,顯示y軸 name
const onm ouseover = (chart: EChartsType, option: ECOption) => {
  (option.yAxis as YAXisOption).nameTextStyle.color = "#ccc";
  // 重繪圖表
  chart.setOption(option);
};

// 滑鼠移出,隱藏y軸 name
const onm ouseout = (chart: EChartsType, option: ECOption) => {
  (option.yAxis as YAXisOption).nameTextStyle.color = "transparent";
  chart.setOption(option);
};

<template>
    <Chart
        
        height="305px"
        :option="{
            // 略......
            title: {
                text: "標題",
                triggerEvent: true
            },
        }"
        :on-mouseover="onMouseover"
        :on-mouseout="onMouseout"
    />
</template>

展示 loading 影片

支持受控的 loading 影片

interface Props {
  // 略...
  loading?: boolean; // 受控
}

const props = withDefaults(defineProps<Props>(), {
  theme: null,
  loading: false
});

watch(
  () => props.loading,
  loading => {
    loading
      ? chartInstance.value.showLoading()
      : chartInstance.value.hideLoading();
  }
);

暴露實體方法

對父組件暴露獲取 ECharts 實體的方法,讓父組件可直接通過實體呼叫原生函式,

defineExpose({
  getInstance: () => chartInstance.value,
  resize,
  draw
});

順便提一下, defineExpose 是在 <script setup> 才能使用的編譯器宏,用來顯式指定需要暴露給父組件的屬性,

完整代碼

太長了,貼出來沒人會細看,有需要的直接自取,親測有效,啟動專案就能看到,快去魔改吧 ?github

本文轉載于:

https://juejin.cn/post/7245183742264377401

如果對您有所幫助,歡迎您點個關注,我會定時更新技術檔案,大家一起討論學習,一起進步,

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/555614.html

標籤:其他

上一篇:uview提示:設定rules,model必須設定

下一篇:返回列表

標籤雲
其他(161332) Python(38242) JavaScript(25508) Java(18249) C(15237) 區塊鏈(8271) C#(7972) AI(7469) 爪哇(7425) MySQL(7258) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4603) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2436) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) HtmlCss(1968) 功能(1967) Web開發(1951) C++(1942) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 記錄--Vue3 封裝 ECharts 通用組件

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 按需匯入的組態檔 組態檔這里就不再贅述,內容都是一樣的,主打一個隨用隨取,按需匯入。 import * as echarts from "echarts/core"; // 引入用到的圖表 import { LineChart, ty ......

    uj5u.com 2023-06-20 09:23:49 more
  • uview提示:設定rules,model必須設定

    問題: setRules時,uview提示:設定rules,model必須設定 原因: <u-form ref="form1" v-model="model1">眼瞎把v-model當成:model,可能全網只有我遇到。 解決: <u-form ref="form1" :model="model1" ......

    uj5u.com 2023-06-20 09:22:49 more
  • StencilJs學習之組件裝飾器

    stenciljs 可以方便的構建互動式組件 支持以下裝飾器 - component - state - prop - watch - method - element - event - listen ## Component 裝飾器 `@Component` 是一個裝飾器,它將 TypeScri ......

    uj5u.com 2023-06-20 09:22:45 more
  • JavaScript的數學計算庫:decimal.js

    An arbitrary-precision Decimal type for JavaScript. ## 功能 - 整數和浮點數 - 簡單但功能齊全的 API - 復制 JavaScript 和物件的許多方法`Number.prototype` `Math` - 還處理十六進制、二進制和八進制值 ......

    uj5u.com 2023-06-20 09:22:39 more
  • JavaScript 顯示資料

    ## JavaScript 顯示資料 JavaScript 可以通過不同的方式來輸出資料: - 使用 **window.alert()** 彈出警告框。 - 使用 **document.write()** 方法將內容寫到 HTML 檔案中。 - 使用 **innerHTML** 寫入到 HTML 元 ......

    uj5u.com 2023-06-20 09:22:33 more
  • Tab切換以及倒計時組件封裝

    ### 1、Tab組件 ![](https://img2023.cnblogs.com/blog/1103967/202306/1103967-20230608203245862-2093631029.gif) **功能** - 支持默認選中tab - 子元素可以是文本或者圖片 - 自定義tab的數 ......

    uj5u.com 2023-06-20 09:22:18 more
  • 手牽手帶你實作mini-vue

    Vue 的雙向資料系結實作原理是什么樣的,如果讓我們自己去實作一個這樣的雙向資料系結要怎么做呢,本文就與大家分享一下 Vue 的系結原理及其簡單實作 ......

    uj5u.com 2023-06-20 09:22:08 more
  • 前端Vue圖片上傳組件支持單個檔案多個檔案上傳 自定義上傳數量

    #### 前端Vue圖片上傳組件支持單個檔案多個檔案上傳 自定義上傳數量 預覽洗掉圖片 圖片壓縮, 下載完整代碼請訪問uni-app插件市場址:https://ext.dcloud.net.cn/plugin?id=13099 #### 效果圖如下: ![](https://p3-juejin.by ......

    uj5u.com 2023-06-20 09:22:04 more
  • StencilJs學習之組件裝飾器

    stenciljs 可以方便的構建互動式組件 支持以下裝飾器 - component - state - prop - watch - method - element - event - listen ## Component 裝飾器 `@Component` 是一個裝飾器,它將 TypeScri ......

    uj5u.com 2023-06-20 09:21:52 more
  • JavaScript的數學計算庫:decimal.js

    An arbitrary-precision Decimal type for JavaScript. ## 功能 - 整數和浮點數 - 簡單但功能齊全的 API - 復制 JavaScript 和物件的許多方法`Number.prototype` `Math` - 還處理十六進制、二進制和八進制值 ......

    uj5u.com 2023-06-20 09:21:46 more