vue3封裝簡易的vue-echarts問題
vue3封裝簡易的vue-echarts
項(xiàng)目場景
數(shù)據(jù)可視化開發(fā),采用的技術(shù)棧是vue3+echarts+router。
問題描述
在vue2中,才開始開發(fā)數(shù)據(jù)可視化大屏,都是用echarts,之后改用為vue-echarts組件,但是到了vue3之后,組件會有一些小問題,所以準(zhǔn)備自己封裝一套簡易的vue-echarts組件,其他的功能之后再迭代上去,足夠項(xiàng)目使用即可。
代碼封裝
<template>
<div class="echarts" :id="id"></div>
</template>這里的echarts組件的id應(yīng)該每個(gè)組件不同,因此id值為動態(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í)間戳搭配前綴來實(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} (vvxyksv9kd%)'
},
legend: {
orient: 'vertical',
left: 10,
data: ['事件一 名稱', '事件二 名稱', '事件三 名稱', '事件四 名稱'],
padding: [250, 6, 7, 8]
},
grid: {
top: 0,
left: 0,
right: 0,
bottom: 0
},
series: [
{
name: '訪問來源',
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) {
//存儲echarts的實(shí)例
var instance = null;
// 監(jiān)聽props是否改變
watch(props, (newValue, oldValue) => {
instance.dispose(); //先銷毀
init(); //再創(chuàng)建好了
//重繪不生效啊
// instance.setOption(newValue);
},{deep:true})
//計(jì)算屬性 自動分配echarts的ID 。防止一個(gè)頁面的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)聽事件,如果頁面寬度和高度變化, 重新繪制echarts
EleResize.on(document.getElementById(echartsDomId), () => {
instance.resize();
})
}
//組件一旦掛載,運(yùn)行echarts初始化
onMounted(() =>init());
//組件卸載,銷毀echarts實(shí)例
onUnmounted(()=>instance.dispose());
/**
* 父節(jié)點(diǎn)通過ref拿到此組件的實(shí)例,調(diào)用downloadPic函數(shù),觸發(fā)圖片下載。
*/
const downloadPic = (name)=>{
let content = instance.getDataURL(); // 這個(gè)方法是經(jīng)過封裝之后的,id就是我們最終經(jīng)過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)通過ref拿到此組件的實(shí)例,調(diào)用downloadPic函數(shù),觸發(fā)圖片下載。
downloadPic
}
}
}
</script>
<style scoped>
div{
width: 100%;
height: 100%;
}
</style>再封裝監(jiān)聽窗口變化觸發(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搬來的,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, //手動切換是否隱藏
}
},
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變量文件引用,這樣我們在使用scss變量和函數(shù)的時(shí)候就不需要每個(gè)組件都取引用了,下面這篇文章主要給大家介紹了關(guān)于如何在vite初始化項(xiàng)目中安裝scss以及scss使用的相關(guān)資料,需要的朋友可以參考下2022-10-10
解決父組件將子組件作為彈窗調(diào)用只執(zhí)行一次created的問題
這篇文章主要介紹了解決父組件將子組件作為彈窗調(diào)用只執(zhí)行一次created的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07
vue數(shù)組對象排序的實(shí)現(xiàn)代碼
這篇文章主要介紹了vue數(shù)組對象排序的實(shí)現(xiàn)代碼,這里整理了詳細(xì)的代碼,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2018-06-06
vue的el-select綁定的值無法選中el-option問題及解決
這篇文章主要介紹了vue的el-select綁定的值無法選中el-option問題及解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
詳解Vue項(xiàng)目中出現(xiàn)Loading chunk {n} failed問題的解決方法
這篇文章主要介紹了詳解Vue項(xiàng)目中出現(xiàn)Loading chunk {n} failed問題的解決方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-09-09

