vue3封裝簡(jiǎn)易的vue-echarts問(wèn)題
vue3封裝簡(jiǎn)易的vue-echarts
項(xiàng)目場(chǎng)景
數(shù)據(jù)可視化開(kāi)發(fā),采用的技術(shù)棧是vue3+echarts+router。
問(wèn)題描述
在vue2中,才開(kāi)始開(kāi)發(fā)數(shù)據(jù)可視化大屏,都是用echarts,之后改用為vue-echarts組件,但是到了vue3之后,組件會(huì)有一些小問(wèn)題,所以準(zhǔn)備自己封裝一套簡(jiǎn)易的vue-echarts組件,其他的功能之后再迭代上去,足夠項(xiàng)目使用即可。
代碼封裝
<template> <div class="echarts" :id="id"></div> </template>
這里的echarts組件的id應(yīng)該每個(gè)組件不同,因此id值為動(dòng)態(tài)設(shè)置的。
<script> import { onMounted } from 'vue' import { uuid } from '../../utils/index' import Echarts from 'echarts' export default { name: 'TwokeVueEcharts', props: { options: { type: Object, default: () => ({}) } }, setup (ctx) { const id = `vue-echarts-${uuid()}` let chart = null const initEcharts = () => { if (!chart) { const dom = document.getElementById(id) chart = Echarts.init(dom) }else { return } if(!ctx.options) return chart.setOption(ctx.options) } onMounted( () => { initEcharts() }) return { id } } } </script>
這里可以看到我引入了uuid的工具類,是為了生成唯一的id值,這里也可用時(shí)間戳搭配前綴來(lái)實(shí)現(xiàn)。
返回id值以供視圖渲染。
引入的echarts為echarts官方組件
<style lang="scss" scoped> .echarts { width: 100%; height: 100%; } </style>
這里是讓echarts組件可以根據(jù)外面的容器大小,鋪滿展示。
組件使用
兩種方式:
全局安裝
main.js中
import TwokeVueEcharts from './TwokeVueEcharts.vue' import { createApp } from 'vue' import App from './App.vue' createApp(App).component("vue-echarts",TwokeVueEcharts).mount("#app")
組件中引入
<script> import TwokeVueEcharts from './TwokeVueEcharts.vue' export default { components: { TwokeVueEcharts } } </script>
<template> <div style="width:300px;height:300px"> <twoke-vue-echarts :options="options"></twoke-vue-echarts> </div> </template> <script> import TwokeVueEcharts from './TwokeVueEcharts.vue' export default { components: { TwokeVueEcharts }, setup () { return { options: { tooltip: { trigger: 'item', formatter: '{a} <br/>: {c} (ublnpf9mb%)' }, legend: { orient: 'vertical', left: 10, data: ['事件一 名稱', '事件二 名稱', '事件三 名稱', '事件四 名稱'], padding: [250, 6, 7, 8] }, grid: { top: 0, left: 0, right: 0, bottom: 0 }, series: [ { name: '訪問(wèn)來(lái)源', type: 'pie', radius: ['50%', '70%'], avoidLabelOverlap: false, label: { show: false, position: 'center' }, emphasis: { label: { show: true, fontSize: '30', fontWeight: 'bold' } }, labelLine: { show: false }, data: [ { value: 335, name: '事件一 名稱' }, { value: 310, name: '事件二 名稱' }, { value: 234, name: '事件三 名稱' }, { value: 135, name: '事件四 名稱' } ] } ] } } } } </script>
vue3 echarts多圖自適應(yīng)封裝
npm install echarts -S
封裝echarts插件
src/components/echarts.vue
<template> <div :id="echartsDomId"></div> </template> <script> import * as echarts from 'echarts'; import {EleResize} from "@/assets/js/esresize"; import {watch, onMounted, ref,onUnmounted} from 'vue'; export default { name: "rxp-echarts", props: { option: { type: Object, required: true, } }, setup(props) { //存儲(chǔ)echarts的實(shí)例 var instance = null; // 監(jiān)聽(tīng)props是否改變 watch(props, (newValue, oldValue) => { instance.dispose(); //先銷毀 init(); //再創(chuàng)建好了 //重繪不生效啊 // instance.setOption(newValue); },{deep:true}) //計(jì)算屬性 自動(dòng)分配echarts的ID 。防止一個(gè)頁(yè)面的echarts出現(xiàn)相同id const echartsDomId = 'echarts' + Math.random() * 100000; function init() { instance = echarts.init(document.getElementById(echartsDomId)); instance.setOption(props.option); //設(shè)置option //添加監(jiān)聽(tīng)事件,如果頁(yè)面寬度和高度變化, 重新繪制echarts EleResize.on(document.getElementById(echartsDomId), () => { instance.resize(); }) } //組件一旦掛載,運(yùn)行echarts初始化 onMounted(() =>init()); //組件卸載,銷毀echarts實(shí)例 onUnmounted(()=>instance.dispose()); /** * 父節(jié)點(diǎn)通過(guò)ref拿到此組件的實(shí)例,調(diào)用downloadPic函數(shù),觸發(fā)圖片下載。 */ const downloadPic = (name)=>{ let content = instance.getDataURL(); // 這個(gè)方法是經(jīng)過(guò)封裝之后的,id就是我們最終經(jīng)過(guò)init(),setOptions的echart圖表,它具有g(shù)etDataURL()方法 let aLink = document.createElement('a'); let blob = base64ToBlob(content); let evt = document.createEvent("HTMLEvents"); evt.initEvent("click", true, true); aLink.download = `${name}.png`; aLink.href = URL.createObjectURL(blob); aLink.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window })); } function base64ToBlob(code) { let parts = code.split(';base64,'); let contentType = parts[0].split(':')[1]; let raw = window.atob(parts[1]); let rawLength = raw.length; let uInt8Array = new Uint8Array(rawLength); for (let i = 0; i < rawLength; ++i) { uInt8Array[i] = raw.charCodeAt(i); } return new Blob([uInt8Array], { type: contentType }); } return { echartsDomId, //父節(jié)點(diǎn)通過(guò)ref拿到此組件的實(shí)例,調(diào)用downloadPic函數(shù),觸發(fā)圖片下載。 downloadPic } } } </script> <style scoped> div{ width: 100%; height: 100%; } </style>
再封裝監(jiān)聽(tīng)窗口變化觸發(fā)方法
src/assets/js/esresize.js
//EleResize('domId',回調(diào)函數(shù)) //echarts resize var EleResize = { _handleResize: function (e) { var ele = e.target || e.srcElement var trigger = ele.__resizeTrigger__ if (trigger) { var handlers = trigger.__z_resizeListeners if (handlers) { var size = handlers.length for (var i = 0; i < size; i++) { var h = handlers[i] var handler = h.handler var context = h.context handler.apply(context, [e]) } } } }, _removeHandler: function (ele, handler, context) { var handlers = ele.__z_resizeListeners if (handlers) { var size = handlers.length for (var i = 0; i < size; i++) { var h = handlers[i] if (h.handler === handler && h.context === context) { handlers.splice(i, 1) return } } } }, _createResizeTrigger: function (ele) { var obj = document.createElement('object') obj.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden;opacity: 0; pointer-events: none; z-index: -1;') obj.onload = EleResize._handleObjectLoad obj.type = 'text/html' ele.appendChild(obj) obj.data = 'about:blank' return obj }, _handleObjectLoad: function () { this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__ this.contentDocument.defaultView.addEventListener('resize', EleResize._handleResize) } } if (document.attachEvent) { // ie9-10 EleResize.on = function (ele, handler, context) { var handlers = ele.__z_resizeListeners if (!handlers) { handlers = [] ele.__z_resizeListeners = handlers ele.__resizeTrigger__ = ele ele.attachEvent('onresize', EleResize._handleResize) } handlers.push({ handler: handler, context: context }) } EleResize.off = function (ele, handler, context) { var handlers = ele.__z_resizeListeners if (handlers) { EleResize._removeHandler(ele, handler, context) if (handlers.length === 0) { ele.detachEvent('onresize', EleResize._handleResize) delete ele.__z_resizeListeners } } } } else { EleResize.on = function (ele, handler, context) { var handlers = ele.__z_resizeListeners if (!handlers) { handlers = [] ele.__z_resizeListeners = handlers if (getComputedStyle(ele, null).position === 'static') { ele.style.position = 'relative' } var obj = EleResize._createResizeTrigger(ele) ele.__resizeTrigger__ = obj obj.__resizeElement__ = ele } handlers.push({ handler: handler, context: context }) } EleResize.off = function (ele, handler, context) { var handlers = ele.__z_resizeListeners if (handlers) { EleResize._removeHandler(ele, handler, context) if (handlers.length === 0) { var trigger = ele.__resizeTrigger__ if (trigger) { trigger.contentDocument.defaultView.removeEventListener('resize', EleResize._handleResize) ele.removeChild(trigger) delete ele.__resizeTrigger__ } delete ele.__z_resizeListeners } } } } export {EleResize}
使用echarts (vue2搬來(lái)的,vue3使用同理)
<template> <div style="width: 100%;height: 100%;"> <div style="width: 80%;height: 70%;background-color: #888888"> <!-- 注意:option是echarts的配置選項(xiàng), 在為空時(shí),不要初始化組件,所以添加v-if判斷option的值存在 --> <echarts v-if="config && flag" :option="config"></echarts> </div> <button @click="flag=!flag">隱藏echarts</button> <button @click="update">修改option參數(shù)</button> <button @click="upData">修改option中的數(shù)組</button> </div> </template> <script> import echarts from "@/components/echarts"; export default { name: "helloWord", components:{echarts}, data() { return { config:null, //echarts中的配置參數(shù) flag:true, //手動(dòng)切換是否隱藏 } }, created() { this.reset(); }, methods:{ reset(){ setTimeout(()=>{ this.config={ title: { text: "我是初始化數(shù)據(jù)", }, xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] }, yAxis: { type: 'value' }, series: [ { data: [500, 230, 224, 218, 135, 147, 260], type: 'line' } ] } },2000) }, update(){ this.config={ title: { text: "我是修改后的數(shù)據(jù)", }, xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] }, yAxis: { type: 'value' }, series: [ { data: [ //隨機(jī)數(shù)據(jù) parseInt(Math.random()*100), parseInt(Math.random()*100), parseInt(Math.random()*100), parseInt(Math.random()*100), parseInt(Math.random()*100), parseInt(Math.random()*100), parseInt(Math.random()*100), ], type: 'line' } ] } }, upData(){ this.config.series={ data: [ //隨機(jī)數(shù)據(jù) parseInt(Math.random()*100), parseInt(Math.random()*100), parseInt(Math.random()*100), parseInt(Math.random()*100), parseInt(Math.random()*100), parseInt(Math.random()*100), parseInt(Math.random()*100), ], type: 'line' } } } } </script> <style scoped> </style> `` vue echarts多圖自適應(yīng)封裝
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
如何在vite初始化項(xiàng)目中安裝scss以及scss的使用
今天想要給vite項(xiàng)目,添加全局的scss變量文件引用,這樣我們?cè)谑褂胹css變量和函數(shù)的時(shí)候就不需要每個(gè)組件都取引用了,下面這篇文章主要給大家介紹了關(guān)于如何在vite初始化項(xiàng)目中安裝scss以及scss使用的相關(guān)資料,需要的朋友可以參考下2022-10-10解決父組件將子組件作為彈窗調(diào)用只執(zhí)行一次created的問(wèn)題
這篇文章主要介紹了解決父組件將子組件作為彈窗調(diào)用只執(zhí)行一次created的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-07-07Vue實(shí)現(xiàn)可移動(dòng)水平時(shí)間軸
這篇文章主要為大家詳細(xì)介紹了Vue實(shí)現(xiàn)可移動(dòng)水平時(shí)間軸,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06vue數(shù)組對(duì)象排序的實(shí)現(xiàn)代碼
這篇文章主要介紹了vue數(shù)組對(duì)象排序的實(shí)現(xiàn)代碼,這里整理了詳細(xì)的代碼,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2018-06-06vue的el-select綁定的值無(wú)法選中el-option問(wèn)題及解決
這篇文章主要介紹了vue的el-select綁定的值無(wú)法選中el-option問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09詳解Vue項(xiàng)目中出現(xiàn)Loading chunk {n} failed問(wèn)題的解決方法
這篇文章主要介紹了詳解Vue項(xiàng)目中出現(xiàn)Loading chunk {n} failed問(wèn)題的解決方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-09-09