Vue3實戰(zhàn)筆記(43)—Vue3組合式API下封裝可復(fù)用ECharts圖表組件

前言

接上文矮瘟,已經(jīng)安裝好了ECharts,開始封裝組件方便使用塑娇。


一澈侠、封裝echart圖標(biāo)鉤子

首先應(yīng)用我們之前學(xué)習(xí)的鉤子方式,在hooks目錄下創(chuàng)建一個名為 useECharts.js 的文件埋酬,用于封裝 ECharts 的邏輯:


import { ref, onMounted, onUnmounted } from 'vue';
import * as echarts from 'echarts';

export default function useECharts(chartContainer, options) {
  const chartInstance = ref(null);

  onMounted(() => {
    // 初始化 ECharts 實例
    chartInstance.value = echarts.init(chartContainer.value);
    // 設(shè)置 ECharts 配置項
    chartInstance.value.setOption(options.value);

    // 監(jiān)聽窗口大小變化埋涧,自動調(diào)整圖表大小
    window.addEventListener('resize', () => chartInstance.value.resize());
  });

  onUnmounted(() => {
    // 銷毀 ECharts 實例
    chartInstance.value.dispose();
    // 移除窗口大小變化監(jiān)聽器
    window.removeEventListener('resize', () => chartInstance.value.resize());
  });

  // 返回 ECharts 實例,以便在外部進行操作
  return chartInstance;
}

二奇瘦、使用步驟

其實這樣就做到了簡單的封裝棘催,可以直接使用了:

  <div ref="chartContainer" style="width: 100%; height: 400px"></div>
</template><script>
import useECharts from './useECharts';

export default {
  setup() {
    const chartContainer = ref(null);
    const options = ref({
      // ECharts 配置項
      title: {
        text: 'ECharts 示例',
      },
      tooltip: {},
      xAxis: {
        data: ['類目1', '類目2', '類目3', '類目4', '類目5', '類目6'],
      },
      yAxis: {},
      series: [
        {
          name: '數(shù)值',
          type: 'bar',
          data: [5, 20, 36, 10, 10, 20],
        },
      ],
    });

    const chartInstance = useECharts(chartContainer, options);

    // 你可以在這里根據(jù)需要操作 ECharts 實例,例如更新數(shù)據(jù)
    // chartInstance.value.setOption({...})

    return {
      chartContainer,
    };
  },
};
</script>

為了更方便使用耳标,我們可以進一步封裝一些常用的組件醇坝,例如:
在components中創(chuàng)建組件EChartsGaugeClock.vue

代碼如下(示例):


<template>
    <div ref="chartContainer" style="width: 100%; height: 100%"></div>
</template>

<script setup lang="ts" name="">
import { ref } from 'vue';
import useECharts from '@/hooks/useECharts';

const chartContainer = ref(null);

const options = ref({
  series: [
    {
      name: 'hour',
      type: 'gauge',
      startAngle: 90,
      endAngle: -270,
      min: 0,
      max: 12,
      splitNumber: 12,
      clockwise: true,
      axisLine: {
        lineStyle: {
          width: 15,
          color: [[1, 'rgba(0,0,0,0.7)']],
          shadowColor: 'rgba(0, 0, 0, 0.5)',
          shadowBlur: 15
        }
      },
      splitLine: {
        lineStyle: {
          shadowColor: 'rgba(0, 0, 0, 0.3)',
          shadowBlur: 3,
          shadowOffsetX: 1,
          shadowOffsetY: 2
        }
      },
      axisLabel: {
        fontSize: 50,
        distance: 25,
        formatter: function (value) {
          if (value === 0) {
            return '';
          }
          return value + '';
        }
      },
      anchor: {
        show: true,
        icon: 'path://M532.8,70.8C532.8,70.8,532.8,70.8,532.8,70.8L532.8,70.8C532.7,70.8,532.8,70.8,532.8,70.8z M456.1,49.6c-2.2-6.2-8.1-10.6-15-10.6h-37.5v10.6h37.5l0,0c2.9,0,5.3,2.4,5.3,5.3c0,2.9-2.4,5.3-5.3,5.3v0h-22.5c-1.5,0.1-3,0.4-4.3,0.9c-4.5,1.6-8.1,5.2-9.7,9.8c-0.6,1.7-0.9,3.4-0.9,5.3v16h10.6v-16l0,0l0,0c0-2.7,2.1-5,4.7-5.3h10.3l10.4,21.2h11.8l-10.4-21.2h0c6.9,0,12.8-4.4,15-10.6c0.6-1.7,0.9-3.5,0.9-5.3C457,53,456.7,51.2,456.1,49.6z M388.9,92.1h11.3L381,39h-3.6h-11.3L346.8,92v0h11.3l3.9-10.7h7.3h7.7l3.9-10.6h-7.7h-7.3l7.7-21.2v0L388.9,92.1z M301,38.9h-10.6v53.1H301V70.8h28.4l3.7-10.6H301V38.9zM333.2,38.9v10.6v10.7v31.9h10.6V38.9H333.2z M249.5,81.4L249.5,81.4L249.5,81.4c-2.9,0-5.3-2.4-5.3-5.3h0V54.9h0l0,0c0-2.9,2.4-5.3,5.3-5.3l0,0l0,0h33.6l3.9-10.6h-37.5c-1.9,0-3.6,0.3-5.3,0.9c-4.5,1.6-8.1,5.2-9.7,9.7c-0.6,1.7-0.9,3.5-0.9,5.3l0,0v21.3c0,1.9,0.3,3.6,0.9,5.3c1.6,4.5,5.2,8.1,9.7,9.7c1.7,0.6,3.5,0.9,5.3,0.9h33.6l3.9-10.6H249.5z M176.8,38.9v10.6h49.6l3.9-10.6H176.8z M192.7,81.4L192.7,81.4L192.7,81.4c-2.9,0-5.3-2.4-5.3-5.3l0,0v-5.3h38.9l3.9-10.6h-53.4v10.6v5.3l0,0c0,1.9,0.3,3.6,0.9,5.3c1.6,4.5,5.2,8.1,9.7,9.7c1.7,0.6,3.4,0.9,5.3,0.9h23.4h10.2l3.9-10.6l0,0H192.7z M460.1,38.9v10.6h21.4v42.5h10.6V49.6h17.5l3.8-10.6H460.1z M541.6,68.2c-0.2,0.1-0.4,0.3-0.7,0.4C541.1,68.4,541.4,68.3,541.6,68.2L541.6,68.2z M554.3,60.2h-21.6v0l0,0c-2.9,0-5.3-2.4-5.3-5.3c0-2.9,2.4-5.3,5.3-5.3l0,0l0,0h33.6l3.8-10.6h-37.5l0,0c-6.9,0-12.8,4.4-15,10.6c-0.6,1.7-0.9,3.5-0.9,5.3c0,1.9,0.3,3.7,0.9,5.3c2.2,6.2,8.1,10.6,15,10.6h21.6l0,0c2.9,0,5.3,2.4,5.3,5.3c0,2.9-2.4,5.3-5.3,5.3l0,0h-37.5v10.6h37.5c6.9,0,12.8-4.4,15-10.6c0.6-1.7,0.9-3.5,0.9-5.3c0-1.9-0.3-3.7-0.9-5.3C567.2,64.6,561.3,60.2,554.3,60.2z',
        showAbove: false,
        offsetCenter: [0, '-35%'],
        size: 120,
        keepAspect: true,
        itemStyle: {
          color: '#707177'
        }
      },
      pointer: {
        icon: 'path://M2.9,0.7L2.9,0.7c1.4,0,2.6,1.2,2.6,2.6v115c0,1.4-1.2,2.6-2.6,2.6l0,0c-1.4,0-2.6-1.2-2.6-2.6V3.3C0.3,1.9,1.4,0.7,2.9,0.7z',
        width: 12,
        length: '55%',
        offsetCenter: [0, '8%'],
        itemStyle: {
          color: '#C0911F',
          shadowColor: 'rgba(0, 0, 0, 0.3)',
          shadowBlur: 8,
          shadowOffsetX: 2,
          shadowOffsetY: 4
        }
      },
      detail: {
        show: false
      },
      title: {
        offsetCenter: [0, '30%']
      },
      data: [
        {
          value: 0
        }
      ]
    },
    {
      name: 'minute',
      type: 'gauge',
      startAngle: 90,
      endAngle: -270,
      min: 0,
      max: 60,
      clockwise: true,
      axisLine: {
        show: false
      },
      splitLine: {
        show: false
      },
      axisTick: {
        show: false
      },
      axisLabel: {
        show: false
      },
      pointer: {
        icon: 'path://M2.9,0.7L2.9,0.7c1.4,0,2.6,1.2,2.6,2.6v115c0,1.4-1.2,2.6-2.6,2.6l0,0c-1.4,0-2.6-1.2-2.6-2.6V3.3C0.3,1.9,1.4,0.7,2.9,0.7z',
        width: 8,
        length: '70%',
        offsetCenter: [0, '8%'],
        itemStyle: {
          color: '#C0911F',
          shadowColor: 'rgba(0, 0, 0, 0.3)',
          shadowBlur: 8,
          shadowOffsetX: 2,
          shadowOffsetY: 4
        }
      },
      anchor: {
        show: true,
        size: 20,
        showAbove: false,
        itemStyle: {
          borderWidth: 15,
          borderColor: '#C0911F',
          shadowColor: 'rgba(0, 0, 0, 0.3)',
          shadowBlur: 8,
          shadowOffsetX: 2,
          shadowOffsetY: 4
        }
      },
      detail: {
        show: false
      },
      title: {
        offsetCenter: ['0%', '-40%']
      },
      data: [
        {
          value: 0
        }
      ]
    },
    {
      name: 'second',
      type: 'gauge',
      startAngle: 90,
      endAngle: -270,
      min: 0,
      max: 60,
      animationEasingUpdate: 'bounceOut',
      clockwise: true,
      axisLine: {
        show: false
      },
      splitLine: {
        show: false
      },
      axisTick: {
        show: false
      },
      axisLabel: {
        show: false
      },
      pointer: {
        icon: 'path://M2.9,0.7L2.9,0.7c1.4,0,2.6,1.2,2.6,2.6v115c0,1.4-1.2,2.6-2.6,2.6l0,0c-1.4,0-2.6-1.2-2.6-2.6V3.3C0.3,1.9,1.4,0.7,2.9,0.7z',
        width: 4,
        length: '85%',
        offsetCenter: [0, '8%'],
        itemStyle: {
          color: '#C0911F',
          shadowColor: 'rgba(0, 0, 0, 0.3)',
          shadowBlur: 8,
          shadowOffsetX: 2,
          shadowOffsetY: 4
        }
      },
      anchor: {
        show: true,
        size: 15,
        showAbove: true,
        itemStyle: {
          color: '#C0911F',
          shadowColor: 'rgba(0, 0, 0, 0.3)',
          shadowBlur: 8,
          shadowOffsetX: 2,
          shadowOffsetY: 4
        }
      },
      detail: {
        show: false
      },
      title: {
        offsetCenter: ['0%', '-40%']
      },
      data: [
        {
          value: 0
        }
      ]
    }
  ]
});

const chartInstance = useECharts(chartContainer, options);

setInterval(function () {
  var date = new Date();
  var second = date.getSeconds();
  var minute = date.getMinutes() + second / 60;
  var hour = (date.getHours() % 12) + minute / 60;
  // options.animationDurationUpdate = 300;
  chartInstance.value.setOption({
    series: [
      {
        name: 'hour',
        animation: hour !== 0,
        data: [{ value: hour }]
      },
      {
        name: 'minute',
        animation: minute !== 0,
        data: [{ value: minute }]
      },
      {
        animation: second !== 0,
        name: 'second',
        data: [{ value: second }]
      }
    ]
  });
}, 1000);

// 你可以在這里根據(jù)需要操作 ECharts 實例,例如更新數(shù)據(jù)
// chartInstance.value.setOption({...})

</script>

<style lang='scss' scoped>
* {
  margin: 0;
  padding: 0;
}
#chartContainer {
  position: relative;
  height: 300px;
  overflow: hidden;
}

</style>

在components中創(chuàng)建組件EChartsGaugeSimple.vue次坡,
代碼如下(示例):


<template>
    <div ref="chartContainer" style="width: 100%; height: 100%"></div>
</template>

<script setup lang="ts" name="">
import { ref } from 'vue';
import useECharts from '@/hooks/useECharts';

const chartContainer = ref(null);
const options = ref({
  tooltip: {
    formatter: '{a} <br/>呼猪 : {c}%'
  },
  series: [
    {
      name: 'Pressure',
      type: 'gauge',
      progress: {
        show: true
      },
      detail: {
        valueAnimation: true,
        formatter: '{value}'
      },
      data: [
        {
          value: 50,
          name: 'SCORE'
        }
      ]
    }
  ]
});

const chartInstance = useECharts(chartContainer, options);

// 你可以在這里根據(jù)需要操作 ECharts 實例,例如更新數(shù)據(jù)
// chartInstance.value.setOption({...})
</script>

<style lang='scss' scoped>
</style>

兩個組件封裝好了直接在主頁使用:


  <div style="height:600px;">
      <EChartsGaugeSimple></EChartsGaugeSimple>
  </div>

  <div style="height:600px;">
      <EChartsGaugeClock></EChartsGaugeClock>
  </div>

image.png

總結(jié)

把常用的都封裝好砸琅,這樣使用起來方便多了宋距。

千行代碼,一 bug 傾城症脂。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谚赎,一起剝皮案震驚了整個濱河市淫僻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌壶唤,老刑警劉巖雳灵,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異闸盔,居然都是意外死亡悯辙,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門迎吵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來躲撰,“玉大人,你說我怎么就攤上這事击费≤罘剩” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵荡灾,是天一觀的道長。 經(jīng)常有香客問我瞬铸,道長批幌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任嗓节,我火速辦了婚禮荧缘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拦宣。我一直安慰自己截粗,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布鸵隧。 她就那樣靜靜地躺著绸罗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪豆瘫。 梳的紋絲不亂的頭發(fā)上珊蟀,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音外驱,去河邊找鬼育灸。 笑死,一個胖子當(dāng)著我的面吹牛昵宇,可吹牛的內(nèi)容都是我干的磅崭。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼瓦哎,長吁一口氣:“原來是場噩夢啊……” “哼砸喻!你這毒婦竟也來了柔逼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤恩够,失蹤者是張志新(化名)和其女友劉穎卒落,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜂桶,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡儡毕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了扑媚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腰湾。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖疆股,靈堂內(nèi)的尸體忽然破棺而出费坊,到底是詐尸還是另有隱情,我是刑警寧澤旬痹,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布附井,位于F島的核電站,受9級特大地震影響两残,放射性物質(zhì)發(fā)生泄漏永毅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧呀酸,春花似錦秸侣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至县钥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間慈迈,已是汗流浹背魁蒜。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留吩翻,地道東北人兜看。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像狭瞎,于是被迫代替她去往敵國和親细移。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容