成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

聊聊vue3中echarts用什么形式封裝最好?(代碼詳解)

項(xiàng)目中經(jīng)常用到echarts,不做封裝直接拿來使用也行,但不可避免要寫很多重復(fù)的配置代碼,封裝稍不注意又會(huì)過度封裝,丟失了擴(kuò)展性和可讀性。始終沒有找到一個(gè)好的實(shí)踐,偶然看到一篇文章,給了靈感。找到了一個(gè)目前認(rèn)為用起來很舒服的封裝。

思路

  1. 結(jié)合項(xiàng)目需求,針對(duì)不同類型的圖表,配置基礎(chǔ)的默認(rèn)通用配置,例如x/y,label,圖例等的樣式
  2. 創(chuàng)建圖表組件實(shí)例(不要使用id,容易重復(fù),還需要操作dom,直接用ref獲取當(dāng)前組件的el來創(chuàng)建圖表),提供type(圖表類型),和options(圖表配置)兩個(gè)必要屬性
  3. 根據(jù)傳入type,加載默認(rèn)的圖表配置
  4. 深度監(jiān)聽傳入的options,變化時(shí)更新覆蓋默認(rèn)配置,更新圖表
  5. 提供事件支持,支持echart事件按需綁定交互

注意要確保所有傳入圖表組件的options數(shù)組都是shallowReactive類型,避免數(shù)組量過大,深度響應(yīng)式導(dǎo)致性能問題

目錄結(jié)構(gòu)

├─v-charts │  │  index.ts     // 導(dǎo)出類型定義以及圖表組件方便使用 │  │  type.d.ts    // 各種圖表的類型定義 │  │  useCharts.ts // 圖表hooks │  │  v-charts.vue // echarts圖表組件 │  │ │  └─options // 圖表配置文件 │          bar.ts │          gauge.ts │          pie.ts
登錄后復(fù)制


組件代碼

v-charts.vue

<template>   <div ref="chartRef" /> </template> <script setup> import { PropType } from "vue"; import * as echarts from "echarts/core"; import { useCharts, ChartType, ChartsEvents } from "./useCharts";  /**  * echarts事件類型  * 截至目前,vue3類型聲明參數(shù)必須是以下內(nèi)容之一,暫不支持外部引入類型參數(shù)  * 1. 類型字面量  * 2. 在同一文件中的接口或類型字面量的引用  * // 文檔中有說明:https://cn.vuejs.org/api/sfc-script-setup.html#typescript-only-features  */ interface EventEmitsType {   <T extends ChartsEvents.EventType>(e: `${T}`, event: ChartsEvents.Events[Uncapitalize<T>]): void; }  defineOptions({   name: "VCharts" });  const props = defineProps({   type: {     type: String as PropType<ChartType>,     default: "bar"   },   options: {     type: Object as PropType<echarts.EChartsCoreOption>,     default: () => ({})   } });  // 定義事件,提供ts支持,在組件使用時(shí)可獲得友好提示 defineEmits<EventEmitsType>();  const { type, options } = toRefs(props); const chartRef = shallowRef(); const { charts, setOptions, initChart } = useCharts({ type, el: chartRef });  onMounted(async () => {   await initChart();   setOptions(options.value); }); watch(   options,   () => {     setOptions(options.value);   },   {     deep: true   } ); defineExpose({   $charts: charts }); </script> <style scoped> .v-charts {   width: 100%;   height: 100%;   min-height: 200px; } </style>
登錄后復(fù)制

useCharts.ts

import { ChartType } from "./type"; import * as echarts from "echarts/core"; import { ShallowRef, Ref } from "vue";  import {   TitleComponent,   LegendComponent,   TooltipComponent,   GridComponent,   DatasetComponent,   TransformComponent } from "echarts/components";  import { BarChart, LineChart, PieChart, GaugeChart } from "echarts/charts";  import { LabelLayout, UniversalTransition } from "echarts/features"; import { CanvasRenderer } from "echarts/renderers";  const optionsModules = import.meta.glob<{ default: echarts.EChartsCoreOption }>("./options/**.ts");  interface ChartHookOption {   type?: Ref<ChartType>;   el: ShallowRef<HTMLElement>; }  /**  *  視口變化時(shí)echart圖表自適應(yīng)調(diào)整  */ class ChartsResize {   #charts = new Set<echarts.ECharts>(); // 緩存已經(jīng)創(chuàng)建的圖表實(shí)例   #timeId = null;   constructor() {     window.addEventListener("resize", this.handleResize.bind(this)); // 視口變化時(shí)調(diào)整圖表   }   getCharts() {     return [...this.#charts];   }   handleResize() {     clearTimeout(this.#timeId);     this.#timeId = setTimeout(() => {       this.#charts.forEach(chart => {         chart.resize();       });     }, 500);   }   add(chart: echarts.ECharts) {     this.#charts.add(chart);   }   remove(chart: echarts.ECharts) {     this.#charts.delete(chart);   }   removeListener() {     window.removeEventListener("resize", this.handleResize);   } }  export const chartsResize = new ChartsResize();  export const useCharts = ({ type, el }: ChartHookOption) => {   echarts.use([     BarChart,     LineChart,     BarChart,     PieChart,     GaugeChart,     TitleComponent,     LegendComponent,     TooltipComponent,     GridComponent,     DatasetComponent,     TransformComponent,     LabelLayout,     UniversalTransition,     CanvasRenderer   ]);   const charts = shallowRef<echarts.ECharts>();   let options!: echarts.EChartsCoreOption;   const getOptions = async () => {     const moduleKey = `./options/${type.value}.ts`;     const { default: defaultOption } = await optionsModules[moduleKey]();     return defaultOption;   };    const setOptions = (opt: echarts.EChartsCoreOption) => {     charts.value.setOption(opt);   };   const initChart = async () => {     charts.value = echarts.init(el.value);     options = await getOptions();     charts.value.setOption(options);     chartsResize.add(charts.value); // 將圖表實(shí)例添加到緩存中     initEvent(); // 添加事件支持   };    /**    * 初始化事件,按需綁定事件    */   const attrs = useAttrs();   const initEvent = () => {     Object.keys(attrs).forEach(attrKey => {       if (/^on/.test(attrKey)) {         const cb = attrs[attrKey];         attrKey = attrKey.replace(/^on(Chart)?/, "");         attrKey = `${attrKey[0]}${attrKey.substring(1)}`;         typeof cb === "function" && charts.value?.on(attrKey, cb as () => void);       }     });   };    onBeforeUnmount(() => {     chartsResize.remove(charts.value); // 移除緩存   });    return {     charts,     setOptions,     initChart,     initEvent   }; };  export const chartsOptions = <T extends echarts.EChartsCoreOption>(option: T) => shallowReactive<T>(option);  export * from "./type.d";
登錄后復(fù)制

type.d.ts

/*  * @Description:  * @Version: 2.0  * @Autor: GC  * @Date: 2022-03-02 10:21:33  * @LastEditors: GC  * @LastEditTime: 2022-06-02 17:45:48  */ // import * as echarts from 'echarts/core'; import * as echarts from 'echarts' import { XAXisComponentOption, YAXisComponentOption } from 'echarts';  import { ECElementEvent, SelectChangedPayload, HighlightPayload,  } from 'echarts/types/src/util/types'  import {   TitleComponentOption,   TooltipComponentOption,   GridComponentOption,   DatasetComponentOption,   AriaComponentOption,   AxisPointerComponentOption,   LegendComponentOption, } from 'echarts/components';// 組件 import {   // 系列類型的定義后綴都為 SeriesOption   BarSeriesOption,   LineSeriesOption,   PieSeriesOption,   FunnelSeriesOption,   GaugeSeriesOption } from 'echarts/charts';  type Options = LineECOption | BarECOption | PieECOption | FunnelOption  type BaseOptionType = XAXisComponentOption | YAXisComponentOption | TitleComponentOption | TooltipComponentOption | LegendComponentOption | GridComponentOption  type BaseOption = echarts.ComposeOption<BaseOptionType>  type LineECOption = echarts.ComposeOption<LineSeriesOption | BaseOptionType>  type BarECOption = echarts.ComposeOption<BarSeriesOption | BaseOptionType>  type PieECOption = echarts.ComposeOption<PieSeriesOption | BaseOptionType>  type FunnelOption = echarts.ComposeOption<FunnelSeriesOption | BaseOptionType>  type GaugeECOption = echarts.ComposeOption<GaugeSeriesOption | GridComponentOption>  type EChartsOption = echarts.EChartsOption;  type ChartType = 'bar' | 'line' | 'pie' | 'gauge'  // echarts事件 namespace ChartsEvents {   // 鼠標(biāo)事件類型   type MouseEventType = 'click' | 'dblclick' | 'mousedown' | 'mousemove' | 'mouseup' | 'mouseover' | 'mouseout' | 'globalout' | 'contextmenu' // 鼠標(biāo)事件類型   type MouseEvents = {     [key in Exclude<MouseEventType,'globalout'|'contextmenu'> as `chart${Capitalize<key>}`] :ECElementEvent   }   // 其他的事件類型極參數(shù)   interface Events extends MouseEvents {     globalout:ECElementEvent,     contextmenu:ECElementEvent,     selectchanged: SelectChangedPayload;     highlight: HighlightPayload;     legendselected: { // 圖例選中后的事件       type: 'legendselected',       // 選中的圖例名稱       name: string       // 所有圖例的選中狀態(tài)表       selected: {         [name: string]: boolean       }     };     // ... 其他類型的事件在這里定義   }     // echarts所有的事件類型   type EventType = keyof Events }  export {   BaseOption,   ChartType,   LineECOption,   BarECOption,   Options,   PieECOption,   FunnelOption,   GaugeECOption,   EChartsOption,   ChartsEvents }
登錄后復(fù)制

options/bar.ts

import { BarECOption } from "../type"; const options: BarECOption = {   legend: {},   tooltip: {},   xAxis: {     type: "category",     axisLine: {       lineStyle: {         // type: "dashed",         color: "#C8D0D7"       }     },     axisTick: {       show: false     },     axisLabel: {       color: "#7D8292"     }   },   yAxis: {     type: "value",     alignTicks: true,     splitLine: {       show: true,       lineStyle: {         color: "#C8D0D7",         type: "dashed"       }     },     axisLine: {       lineStyle: {         color: "#7D8292"       }     }   },   grid: {     left: 60,     bottom: "8%",     top: "20%"   },   series: [     {       type: "bar",       barWidth: 20,       itemStyle: {         color: {           type: "linear",           x: 0,           x2: 0,           y: 0,           y2: 1,           colorStops: [             {               offset: 0,               color: "#62A5FF" // 0% 處的顏色             },             {               offset: 1,               color: "#3365FF" // 100% 處的顏色             }           ]         }       }       // label: {       //   show: true,       //   position: "top"       // }     }   ] }; export default options;
登錄后復(fù)制

項(xiàng)目中使用

index.vue

<template>   <div>     <section>       <div class="device-statistics chart-box">         <div>累計(jì)設(shè)備接入統(tǒng)計(jì)</div>         <v-charts           type="bar"           :options="statisDeviceByUserObjectOpts"           @selectchanged="selectchanged"           @chart-click="handleChartClick"         />       </div>       <div class="coordinate-statistics chart-box">         <div>坐標(biāo)數(shù)據(jù)接入統(tǒng)計(jì)</div>         <v-charts type="bar" :options="statisCoordAccess" />       </div>     </section>   </div> </template> <script setup> import {   useStatisDeviceByUserObject, } from "./hooks"; // 設(shè)備分類統(tǒng)計(jì) const { options: statisDeviceByUserObjectOpts,selectchanged,handleChartClick } = useStatisDeviceByUserObject(); </script>
登錄后復(fù)制

/hooks/useStatisDeviceByUserObject.ts

export const useStatisDeviceByUserObject = () => {   // 使用chartsOptions確保所有傳入v-charts組件的options數(shù)據(jù)都是## shallowReactive淺層作用形式,避免大量數(shù)據(jù)導(dǎo)致性能問題   const options = chartsOptions<BarECOption>({     yAxis: {},     xAxis: {},     series: []   });   const init = async () => {     const xData = [];     const sData = [];     const dicts = useHashMapDics<["dev_user_object"]>(["dev_user_object"]);     const data = await statisDeviceByUserObject();     dicts.dictionaryMap.dev_user_object.forEach(({ label, value }) => {       if (value === "6") return; // 排除其他       xData.push(label);       const temp = data.find(({ name }) => name === value);       sData.push(temp?.qty || 0);              // 給options賦值時(shí)要注意options是淺層響應(yīng)式       options.xAxis = { data: xData };        options.series = [{ ...options.series[0], data: sData }];     });   };      // 事件   const selectchanged = (params: ChartsEvents.Events["selectchanged"]) => {     console.log(params, "選中圖例了");   };    const handleChartClick = (params: ChartsEvents.Events["chartClick"]) => {     console.log(params, "點(diǎn)擊了圖表");   };      onMounted(() => {     init();   });   return {     options,     selectchanged,     handleChartClick   }; };
登錄后復(fù)制

使用時(shí)輸入@可以看到組件支持的所有事件:

聊聊vue3中echarts用什么形式封裝最好?(代碼詳解)

  • 推薦學(xué)習(xí):《vue.js視頻教程》

贊(0)
分享到: 更多 (0)
?
網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)
久久午夜夜伦鲁鲁片免费无码影视| 精品无码久久久久久久久水蜜桃| 国产午夜视频在线观看| 狠狠躁夜夜躁人妻蜜臂AV| 久久99精品久久水蜜桃| 免费国产黄网站在线观看可以下载 | 99精产国品一二三产区区别电影| 啊哈~给我~啊(H)| 国产AV无码专区亚洲AV中文| 国外B站推广网站| 麻花豆传媒剧国产免费| 人妻丰满熟妇AV无码区乱| 天天做天天爱夜夜爽毛片毛片| 久久久久久无码AV成人影院| 国产自无码视频在线观看| 精品久久亚洲中文无码| 欧美18VIDEOSEX性欧美| 免费A级毛片无码樱桃视频| 人妻少妇精品无码专区二区| 无码人妻丰满熟妇精品区| 亚洲线精品一区二区三八戒| BT天堂资源种子在线| 999精产国品一二三产区区| 大爷你的太大了我| 激情内射人妻1区2区3区| 免费观看高清大片的播放器| 色欲天天天天天综合网| 亚洲精品高清国产一久久| 18禁无码无遮挡H动漫免费看| 恶毒美人长批后被宿敌爆炒了| 国产互换人妻好紧HD无码| 久久精品国产亚洲AV高清漫画| 欧美伊人久久大香线蕉综合 | 堕落女教师动漫全无修| 狠狠人妻久久久久久综合| 欧美性猛交ⅩXXX乱大交| 午夜成人性爽爽免费视频| 制服 丝袜 亚洲 中文 综合 | 中文字幕乱码亚洲∧V日本| 国产94在线 | 传媒麻豆| 久久久精品中文字幕麻豆发布| 日本边添边摸边做边爱喷水| 亚洲国产精品久久久久爰| YSL千人千色T9T9T9T9| 狠狠色噜噜狠狠狠狠7777| 欧美一级一片内射欧美美妇3p| 亚洲AV无码不卡一区二区三区| AV色欲无码人妻中文字幕| 国产又爽又黄又无遮挡的激情视频| 男人扒开添女人下部免费视频 | 秋霞人妻无码中文字幕| 亚洲旡码A∨一区二区三区| 爆乳3把你榨干哦OVA在线观看| 精品国产乱码久久久久久郑州公司| 红桃视频成人传媒| 亲生乖女好紧H下| 亚洲精品无码av中文字幕电影网站 | 亚洲AV无码成人| 亚洲乱码国产乱码精品精| 白嫩的18SEX少妇HD| 精品国模一区二区三区| 色欲久久九色一区二区三区| 又爽又黄无遮挡高潮视频网站| 国产精品美女久久久网站| 欧美少妇XXXXX| 亚洲性无码一区二区三区| 国产成人AV性色在线影院色戒| 男女无遮挡猛进猛出免费视频| 性生大片免费观看网站蜜芽| 波多野结衣乳巨码无在线观看| 久久精品国产精品亚洲蜜月| 无码毛片AAA在线| 锕锕锕锕锕~好深啊APP网站| 久久久久国色AV免费观看性色| 我调教同学的放荡麻麻| ZOMBIE老头SUPREME| 久久婷婷激情综合色综合俺也去| 无翼乌全彩工口里番库| 被老头玩弄邻居人妻中文字幕| 久热中文字幕无码视频| 亚洲AV中文无码字幕色本草| 高清VIDEOSDESEXO日| 欧美视频一区二区三区| 亚洲性人人天天夜夜摸| 国产无遮挡裸体免费视频| 久久久久人妻精品一区蜜桃| 无码人妻精品一区二| 波多野结衣AV一区二区全免费观看| 久久亚洲精品无码GV| 亚洲国产精品成人久久久| 国产精品毛片一区二区三区| 日韩大片高清播放器| 99久久99久久精品国产片| 久久久久免费精品国产| 亚洲国产成人片在线观看无码| 国产精品久久久久一区二区三区 | 久久久久亚洲精品成人网| 亚洲AV之男人的天堂| 国产精品无码免费专区午夜| 久久久久人妻一区精品| 亚洲AV成人AV天堂| 国产精品成人观看视频国产奇米| 日本人XXXX裸体XXXX| STEAMWORKSHOP魅魔| 欧美 国产 综合 欧美 视频| 在线观看免费A∨网站| 久久精品A亚洲国产V高清不卡 | 精品久久久久久亚洲精品| 性孕交大肚子孕妇| 国产老妇伦国产熟女老妇高清97| 四虎WWW成人影院观看| 又粗又粗又黄又硬又深色的| 精品无码久久久久成人漫画 | 色噜噜狠狠一区二区三区| 成人毛片18女人毛片免费看快色| 人马畜禽CORPORATION| Chinese国产男男视频观看| 哦┅┅快┅┅用力啊┅┅村妇 | 免费国产成人高清在线观看网站| 影音先锋女人AV鲁色资源网久久| 国产AV寂寞骚妇| 色综合久久无码五十路人妻| 成人每日更新在线不卡| 搡老女人熟妇老太HD| 成人做爰高潮A片免费视频| 日韩电影久久久被窝网| 丰满人妻无码∧V区视频| 色综合久久一区二区三区| 国产SM调教视频在线观看 | 成人无码专区免费播放三区| 色8激情欧美成人久久综合电影| 丁香色婷婷国产精品视频| 少妇被三个黑人调教| 国产AV无码专区亚洲AⅤ| 无码人妻丰满熟妇区毛片18| 国产日韩一区在线精品| 亚洲AV无码专区里番在线观看| 好爽…又高潮了毛片喷水| 亚洲精品无码一区二区AⅤ污美国| 极品少妇自慰喷白浆av| 亚洲一区二区三区高清AV| 美女粉嫩饱满的一线天MP4| 99久热RE在线精品视频| 人人澡人人透人人爽| 公和熄洗澡三级在线观看| 校花娇喘呻吟校长陈若雪视频| 狠狠躁日日躁夜夜躁2020| 一二三四社区在线高清观看| 免费真人视频网站直播下载| YYYY11111少妇影院| 爽爽AV浪潮AV一区二区| 国产亚洲美女精品久久久| 亚洲日韩欧洲乱码AV夜夜摸| 美女扒开腿让男人桶爽直播| 把腿张开老子臊烂你的动漫| 天天想你免费看西瓜视频| 含着她的花蒂啃咬高潮| 野花视频在线观看最新| 男女爽爽午夜18禁影院免费| 差差漫画网页登录页面弹窗| 为了升职丈夫把我献给他们领导 | 午夜影视啪啪体验区入口| 久久成人成狠狠爱综合网| 97超碰人人人人人人少妇| 色哟哟免费精品网站入口| 韩国三级在线观看完整版| 又粗又黄又爽视频免费看| 人妻少妇一区二区三区| 国产乱码精品一区二区三区中文| 亚洲欧美成人综合久久久| 欧美激情一区二区三区| 国产成人精品午夜二三区波多野| 亚洲国产精品悠悠久久琪琪| 农村风流大炕作爱| 国产丰满老熟女重口对白| 亚洲无线一二三四区手机| 人妻精品久久久久中文字幕一冢本 | 野花香电视剧全集免费观看高清| 欧美性饥渴少妇XXXⅩOOOO| 国产成人无码A区在线观看视频A| 亚洲人成人无码WWW影院| 欧美性猛交XXXX免费看| 国产乱子伦一区二区三区| 杂乱小说2第400部| 少妇粉嫩小泬喷水视频WWW| 久久 国产 尿 小便 嘘嘘| YY111111少妇影院无码老司机| 无码人妻一区二区三区精品视频| 久久综合九色综合欧美狠狠| 厨房丝袜麻麻被后进怀孕| 亚洲乱码日产精品M| 秋霞成人无码电影在线观看| 国产午夜精品一区二区三区软件| 中文字幕一区二区三区日韩精品| 久久熟女俱乐部五十路二区av| ぱらだいす天堂中文网WWW| 亚洲AV乱码中文一区二区三区| 欧产日产国色天香区别9视频| 国产美女极度色诱视频WWW| 做AJ姿势教程大全图片|