Vue3中我是这样玩Echart的
点击关注公众号,“技术干货”及时达!
前言最近接到个业务需求,类似于数据大屏展示图表的功能,需要具备一键换肤和表格转换成为图表的功能,对于我这种老Echarter来说已经是很轻车熟路的操作了,但是由于团队使用的是「Vue3」+「TS」还是遇到了些坑点的。
3183d1c8d04d5ec50922cf28c95600b2.jpgEchart的基本操作在「vue3」中,通过「npm install echarts」可获取到对应的echart资源,在项目文件中建立对应的utils作为引用echart资源的工具库。
「@/utils/utils」
import*asechartsfrom"echarts/core"
import{BarChart,LineChart,PieChart,MapChart,PictorialBarChart,RadarChart}from"echarts/charts"
import{
TitleComponent,
TooltipComponent,
GridComponent,
PolarComponent,
AriaComponent,
ParallelComponent,
LegendComponent,
RadarComponent,
ToolboxComponent,
DataZoomComponent,
VisualMapComponent,
TimelineComponent,
CalendarComponent,
GraphicComponent
}from"echarts/components"
import{CanvasRenderer}from"echarts/renderers"
echarts.use([
LegendComponent,
TitleComponent,
TooltipComponent,
GridComponent,
PolarComponent,
AriaComponent,
ParallelComponent,
BarChart,
LineChart,
PieChart,
MapChart,
RadarChart,
CanvasRenderer,
PictorialBarChart,
RadarComponent,
ToolboxComponent,
DataZoomComponent,
VisualMapComponent,
TimelineComponent,
CalendarComponent,
GraphicComponent
])
exportdefaultecharts
然后再建立个Echart.vue文件
template
divref="echartsRef"style="height:400px;width:500px"gamePlay/div
/template
scriptsetuplang="ts"
import{ref,onMounted}from"vue"
importechartsfrom"@/utils/echarts"
constechartsRef=ref()
onMounted(()={
constmyChart=echarts.init(echartsRef.value)
//指定图表的配置项和数据
constoption={
title:{
text:"ECharts入门示例"
},
tooltip:{},
legend:{
data:["销量"]
},
xAxis:{
data:["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
},
yAxis:{},
series:[
{
name:"销量",
type:"bar",
data:[5,20,36,10,10,20]
}
]
}
//使用刚指定的配置项和数据显示图表。
myChart.setOption(option)
})
/script
就这么简单就可以渲染出一个echart图表了。
封装useEchartHook渲染图表虽然我们已经能渲染出图表了,但是这个操作并不是最优解,因为我们的实际业务中是存在很多不同类型的图表,不可能每个都实例化Echart然后再手动调用setOptions方法,这显的很蠢。那么这个时候就需要引入「useHookEchart」的做法了。
import{Ref,shallowRef,onMounted,onDeactivated,onBeforeUnmount}from"vue"
importechartsfrom"@/utils/echarts"
exporttypeEChartsCoreOption=echarts.EChartsCoreOption
constuseEcharts=(elRef:RefHTMLDivElement,options:EChartsCoreOption)={
constcharts=shallowRefecharts.ECharts()
constinitCharts=()={
charts.value=echarts.init(elRef.value)
setOptions(options)
}
constsetOptions=(options:EChartsCoreOption)={
charts.valuecharts.value.setOption(options)
}
constechartsResize=()={
charts.valuecharts.value.resize()
}
onMounted(()={
window.addEventListener("resize",echartsResize)
})
//防止echarts页面keepAlive时,还在继续监听页面
onDeactivated(()={
window.removeEventListener("resize",echartsResize)
})
onBeforeUnmount(()={
window.removeEventListener("resize",echartsResize)
})
return{
initCharts,
setOptions,
echartsResize
}
}
export{useEcharts}
然后再echart.vue中引入
template
divstyle="width:100%;height:100%"ref="elEcharts"/
/template
scriptsetuplang="ts"
import{shallowRef,onMounted,watch}from"vue"
import{useEcharts,typeEChartsCoreOption}from"@/hooks/useEcharts"
interfaceProps{
options:EChartsCoreOption
}
constprops=definePropsProps()
constthemeStore=useThemeStore()
constelEcharts=shallowRef()
constcurrentOptions=shallowRef(props.options)
const{setOptions,initCharts}=useEcharts(elEcharts,currentOptions.value)
watch(
()=props.options,
(nVal)={
lettargetOptions:EChartsCoreOption={}
if(themeStore.currentColorArraythemeStore.currentColorArray.length0){
targetOptions={...nVal}
targetOptions.color=themeStore.currentColorArray
}else{
targetOptions={...nVal}
}
setOptions(targetOptions)
}
)
onMounted(()={
initCharts()
})
/script
业务中使用
template
BaseEcharts:options="options2"/
/template
importBaseEchartsfrom"@/components/baseEcharts/index.vue"
constoptions2:EChartsCoreOption={
tooltip:{
trigger:"axis"
},
grid:{
left:"3%",
right:"4%",
bottom:"0%",
top:"5%",
containLabel:true
},
xAxis:{
type:"category",
boundaryGap:false,
data:["3-1","3-2","3-3","3-4","3-5","3-6","3-7"]
},
yAxis:{
axisLabel:{
formatter:function(val:number){
returnval
}
}
},
series:[
{
name:"QQ",
type:"line",
stack:"Total",
data:[200,201,202,203,204,205,206]
},
{
name:"微信",
type:"line",
stack:"Total",
data:[200,201,202,203,204,205,206]
}
]
}
image.png关于Echart主题换肤由于产品希望图表的主题是可以自由变换的,也就是图表换肤。那好说,因为在echart中可以通过options上的color字段进行自由换主题。这个时候需要改造useEcharts中的initCharts方法
...
constinitCharts=(themeColor?:Arraystring)={
charts.value=echarts.init(elRef.value)
if(themeColor){
options.color=themeColor
}
setOptions(options)
}
...
然后再建立themeStore(由于是全局操作,这里使用的pinia)
@/store/themeStore中建立updateCurrentColorByArray方法
import{defineStore}from"pinia"
import{ref}from"vue"
exportconstuseThemeStore=defineStore("themeStore",()={
constcurrentColorArray=refstring[]()
//根据颜色组更新当前颜色组
constupdateCurrentColorByArray=(color:string[])={
currentColorArray.value=color
}
return{
updateCurrentColorByArray,
currentColorArray
}
})
在echartsTheme.ts中预设以下几种主题
exportconstechartsThemeData=[
{
name:"vintage",
background:"#fef8ef",
theme:[
"#d87c7c",
"#919e8b",
"#d7ab82",
"#6e7074",
"#61a0a8",
"#efa18d",
"#787464",
"#cc7e63",
"#724e58",
"#4b565b"
]
},
{
name:"dark",
background:"#333",
theme:[
"#dd6b66",
"#759aa0",
"#e69d87",
"#8dc1a9",
"#ea7e53",
"#eedd78",
"#73a373",
"#73b9bc",
"#7289ab",
"#91ca8c",
"#f49f42"
]
},
{
name:"westeros",
background:"transparent",
theme:["#516b91","#59c4e6","#edafda","#93b7e3","#a5e7f0","#cbb0e3"]
},
{
name:"essos",
background:"rgba(242,234,191,0.15)",
theme:["#893448","#d95850","#eb8146","#ffb248","#f2d643","#ebdba4"]
},
{
name:"wonderland",
background:"transparent",
theme:["#4ea397","#22c3aa","#7bd9a5","#d0648a","#f58db2","#f2b3c9"]
},
{
name:"walden",
background:"rgba(252,252,252,0)",
theme:["#3fb1e3","#6be6c1","#626c91","#a0a7e6","#c4ebad","#96dee8"]
},
{
name:"chalk",
background:"#293441",
theme:["#fc97af","#87f7cf","#f7f494","#72ccff","#f7c5a0","#d4a4eb","#d2f5a6","#76f2f2"]
},
{
name:"infographic",
background:"transparent",
theme:[
"#C1232B",
"#27727B",
"#FCCE10",
"#E87C25",
"#B5C334",
"#FE8463",
"#9BCA63",
"#FAD860",
"#F3A43B",
"#60C0DD",
"#D7504B",
"#C6E579",
"#F4E001",
"#F0805A",
"#26C0C0"
]
},
{
name:"macarons",
background:"transparent",
theme:[
"#2ec7c9",
"#b6a2de",
"#5ab1ef",
"#ffb980",
"#d87a80",
"#8d98b3",
"#e5cf0d",
"#97b552",
"#95706d",
"#dc69aa",
"#07a2a4",
"#9a7fd1",
"#588dd5",
"#f5994e",
"#c05050",
"#59678c",
"#c9ab00",
"#7eb00a",
"#6f5553",
"#c14089"
]
},
{
name:"roma",
background:"transparent",
theme:[
"#E01F54",
"#001852",
"#f5e8c8",
"#b8d2c7",
"#c6b38e",
"#a4d8c2",
"#f3d999",
"#d3758f",
"#dcc392",
"#2e4783",
"#82b6e9",
"#ff6347",
"#a092f1",
"#0a915d",
"#eaf889",
"#6699FF",
"#ff6666",
"#3cb371",
"#d5b158",
"#38b6b6"
]
},
{
name:"shine",
background:"transparent",
theme:["#c12e34","#e6b600","#0098d9","#2b821d","#005eaa","#339ca8","#cda819","#32a487"]
},
{
name:"purple-passion",
background:"rgba(91,92,110,1)",
theme:["#8a7ca8","#e098c7","#8fd3e8","#71669e","#cc70af","#7cb4cc"]
}
]
在setting.vue中引入themeStore和echartTheme.ts
template
divclass="echarts-theme"
baseTitletitle="主题方案"toolContent="用于设置所有图表的主题"/
el-row:gutter="20"
el-col:span="12"v-for="iteminechartsThemeData":key="item.name"
divclass="echarts-theme-item-group"@click="handleClick(item.theme)"
div
class="echarts-theme-item-color"
:style="{backgroundColor:sItem}"
v-for="sIteminitem.theme"
:key="sItem"
/
/div
/el-col
/el-row
/div
/template
scriptsetuplang="ts"
importbaseTitlefrom"./baseTitle.vue"
import{echartsThemeData}from"@/config/echartTheme"
import{useThemeStore}from"@/store/modules/themeStore"
constthemeStore=useThemeStore()
consthandleClick=(theme:Arraystring)={
themeStore.updateCurrentColorByArray(theme)
}
/script
stylelang="scss"scoped
.echarts-theme-item-group{
display:flex;
flex-wrap:wrap;
justify-content:space-between;
width:auto;
height:32px;
padding:
margin-bottom:
overflow:hidden;
cursor:pointer;
border:1pxsolid#eee;
border-radius:
}
.echarts-theme-item-color{
display:inline-block;
width:20px;
height:20px;
margin-right:
margin-bottom:10px;
margin-left:
border-radius:
}
/style
在echarts.vue中监听currentColorArray变化,重新去设置图表主题即可
...
watch(
()=themeStore.currentColorArray,
(nVal)={
currentOptions.value.color=nVal
setOptions(currentOptions.value)
}
)
...
image.pngimage.png自定义颜色跟新图表主题当我准备提交代码,关机下班的时候。产品突然说,用户再增加个根据颜色来生成图表的主题,而不是预设的主题。这个时候,我心里真的有1W只草泥马在奔腾。你一个图表目的不就是为了看数据展示吗?搞这么多花里胡哨的干嘛捏?
d45856539f5388b9a8527da4f5a04223.jpeg吐槽归吐槽,班还是要上的,先做个基础布局吧。
image.pngtvision-color根据某个色阶来生成主题,我们可以通过 tvision-color进行操作。
在utils/color.ts
exportconstgetColorArray=(hex:string)={
const{colors:newPalette,primary:brandColorIndex}=Color.getColorGradations({
colors:[hex],
step:10,
remainInput:false//是否保留输入不保留会矫正不合适的主题色
})[0]
return{
newPalette,
brandColorIndex
}
}
getColorArray方法会返回根据这个色阶返回一系列的相关颜色的数据,其中brandColorIndex为这个色阶的主色。
在themeStore中添加
...
//根据颜色更新当前颜色组
constupdateCurrentColorArray=(color:string)={
const{newPalette,brandColorIndex}=getColorArray(color)
constfirstColor=newPalette[0]
constprimaryColor=newPalette[brandColorIndex]
newPalette[0]=primaryColor
newPalette[brandColorIndex]=firstColor
currentColorArray.value=newPalette
}
return{
updateCurrentColorArray,
updateCurrentColorByArray,
}
...
在业务中customColor.vue中调用
template
divclass="customColor"
baseTitletitle="主题色"/
divclass="customColor-list"
div
class="customColor-item"
v-for="itemincolorList"
:key="item"
:style="{backgroundColor:item}"
@click="handleClick(item)"
el-iconv-if="currentValue===item"Check//el-icon
/div
el-color-pickerv-model="color1"@change="customColor"/
/div
/div
/template
scriptsetuplang="ts"
importbaseTitlefrom"./baseTitle.vue"
import{ref}from"vue"
constcolorList=ref(["#409EFF","#007BA7","#212121","#11A983","#13C2C2","#6959CD","#FF6B6B","#87CEEB"])
constemits=defineEmits(["change"])
constcurrentValue=ref()
constcolor1=ref()
consthandleClick=(item:string)={
currentValue.value=item
emits("change",item)
}
constcustomColor=(item:string|null)={
if(item){
handleClick(item)
}
}
/script
stylescopedlang="scss"
@import"@/assets/mixins/box-center";
.customColor-list{
@includebox-center(space-between);
.customColor-item{
width:30px;
height:30px;
font-size:18px;
color:#fff;
cursor:pointer;
border-radius:
@includebox-center;
}
}
/style
image.pngimage.png总结在这过程中,我们使用了Vue3和TS中使用Echart实现一键换肤和根据颜色生成图表主题的功能。通过封装useEchartHook来渲染图表,并使用tvision-color库根据色阶生成颜色组来更新主题。最终实现了用户可以根据自定义颜色来展示图表数据的需求。
点击关注公众号,“技术干货”及时达!
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线