vue3中使用Apache ECharts的详细方法
爱唱歌的前端 人气:0首先祝贺Echarts顺利的从Apache毕业,多了个响亮的名字:Apache ECharts
,现在的官网地址在这里:传送门,首页相当的国际范,看着比以前舒服多了,但是文档还是那个文档(T▽T)
ps:从Apache毕业的字面意思从一个国内项目变成了一个国际化开源项目,简单说就是从一个很厉害的项目变成了超厉害的项目
项目效果
前言
最近在做一些数据透析的项目需要用到报表图,那么报表图好用的有老牌的ECharts,比较新意的AntV,思前马后的想了一下还是用了Echarts,因为AntV的产品线真的是五花八门,比如G2、G6、F2、L7,看得我头晕眼花,所以决定用Echarts省事多了。
一、安装
目前安装自动指向的版本是5.4.0
npm install echarts --save
二、测试运行
官方快速入门文档地址:传送门,文档真就是快速,只有使用代码,连个框架案例都懒得写了。。
测试的话直接用全量引入了,看着简洁点。使用的话还是和以前差不多,获取dom的话可以用id
或ref
,但我不太喜欢在vue项目中看到原生的东西,所以就用ref了,ref的话取值记得带上.value
;如果进入页面就要显示图表,一定要把初始代码放到onMounted
生命周期函数中,不然会报Error: Initialize failed: invalid dom.
的错误;另外高度一定要设置实高,不然页面会空白。
setup测试代码: 随便拷贝到一个vue文件,能显示图表的话说明echarts能正常运行了
<template> <div class="test"> <h1>setup测试代码</h1> <div ref="echartRef" class="echart"></div> </div> </template> <script setup> import { ref, onMounted } from 'vue' import * as echarts from 'echarts'; const echartRef = ref() onMounted(() => { // 基于准备好的dom,初始化echarts实例 const myChart = echarts.init(echartRef.value); // 绘制图表 myChart.setOption({ title: { text: 'ECharts 入门示例' }, tooltip: {}, xAxis: { data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'] }, yAxis: {}, series: [ { name: '销量', type: 'bar', data: [5, 20, 36, 10, 10, 20] } ] }); }) </script> <style lang="scss" scoped> .test { margin: auto; max-width: 60vw; .echart { width: 100%; height: 500px; } } </style>
三、全局配置
为了不让使用到的页面重复导入echarts,我们得把它设置成全局模块,而vue3现在提供全局化的形式有两种:globalProperties
和provide/inject
,接下来我们看一下怎么用着两种形式去实现全局化。
小提示
按需引入的话需要在'echarts/core'
包里引入自己要使用的图表,名字为Xxx+Chart
,比如折线图就是LineChart
,不知道图表叫什么名字可以到官方示例的标题里看一下,首字母要大写,之后还需要在echarts.use
中注册一下。
1. globalProperties形式:
先在main.js
中引入echarts,并且把它挂载在app.config.globalProperties
,名字风格最好用$
开头,如用了路由,也会自动在这上面挂载$router
和$route
。
①全量引入:
main.js
import { createApp } from 'vue' import App from './App.vue' import router from './router' import * as echarts from 'echarts'; const app = createApp(App) app.use(router) app.mount('#app') app.config.globalProperties.$echarts = echarts
②按需引入:
main.js
import { createApp } from 'vue' import App from './App.vue' import router from './router' // 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。 import * as echarts from 'echarts/core'; // 引入柱状图图表,图表后缀都为 Chart import { LineChart } from 'echarts/charts'; // 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component import { TitleComponent, TooltipComponent, GridComponent, DatasetComponent, TransformComponent } from 'echarts/components'; // 标签自动布局,全局过渡动画等特性 import { LabelLayout, UniversalTransition } from 'echarts/features'; // 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步 import { CanvasRenderer } from 'echarts/renderers'; // 注册必须的组件 echarts.use([ TitleComponent, TooltipComponent, GridComponent, DatasetComponent, TransformComponent, LabelLayout, UniversalTransition, CanvasRenderer, LineChart ]); const app = createApp(App) app.use(router) app.mount('#app') app.config.globalProperties.$echarts = echarts
测试代码:
使用的话先在vue中引入getCurrentInstance
模块,之后就可以在appContext.config.globalProperties
中找到我们挂载的$echarts
了。
xxx.vue
<template> <div class="global-properties"> <h1>globalProperties</h1> <div ref="LineChartRef" class="echart"></div> </div> </template> <script setup> import { ref, onMounted, getCurrentInstance } from 'vue' const LineChartRef = ref() onMounted(() => { // 获取全局echarts实例 const echarts = getCurrentInstance().appContext.config.globalProperties.$echarts // 基于准备好的dom,初始化echarts实例 const lineChar = echarts.init(LineChartRef.value); // 绘制图表 lineChar.setOption({ title: { text: '折线图' }, xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] }, yAxis: { type: 'value' }, series: [ { data: [150, 230, 224, 218, 135, 147, 260], type: 'line' } ] }); }) </script> <style lang="scss" scoped> .global-properties { margin: auto; max-width: 60vw; .echart { width: 100%; height: 500px; } } </style>
2. provide / inject 形式:
由于provide
和inject
必须在setup
中使用,所以我们得在app里提供echarts
①全量引入:
app.vue:
<script setup> import * as echarts from 'echarts'; import { provide } from 'vue' provide('echarts', echarts) </script>
②按需引入:
app.vue:
<script setup> import { provide } from 'vue' // 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。 import * as echarts from 'echarts/core'; // 引入柱状图图表,图表后缀都为 Chart import { BarChart, LineChart } from 'echarts/charts'; // 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component import { TitleComponent, TooltipComponent, GridComponent, DatasetComponent, TransformComponent } from 'echarts/components'; // 标签自动布局,全局过渡动画等特性 import { LabelLayout, UniversalTransition } from 'echarts/features'; // 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步 import { CanvasRenderer } from 'echarts/renderers'; // 注册必须的组件 echarts.use([ TitleComponent, TooltipComponent, GridComponent, DatasetComponent, TransformComponent, LabelLayout, UniversalTransition, CanvasRenderer, BarChart, LineChart ]); provide('echarts', echarts) </script>
测试代码:
接着就可以在子页面注入echarts去使用了
xxx.vue:
<template> <div class="provide-inject"> <h1>provide / inject</h1> <div ref="BarChartRef" class="echart"></div> </div> </template> <script setup> import { ref, onMounted, inject } from 'vue' const BarChartRef = ref() onMounted(() => { // 注入echarts实例 const echarts = inject("echarts"); // 基于准备好的dom,初始化echarts实例 const BarChart = echarts.init(BarChartRef.value); // 绘制图表 BarChart.setOption({ title: { text: '柱状图' }, tooltip: {}, xAxis: { data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'] }, yAxis: {}, series: [ { name: '销量', type: 'bar', data: [5, 20, 36, 10, 10, 20] } ] }); }) </script> <style lang="scss" scoped> .provide-inject { margin: auto; max-width: 60vw; .echart { width: 100%; height: 500px; } } </style>
❀简单封装
上面的按需引入需要导入的东西太多了,导致main.js/app.vue
文件看起来极其肮脏,所以我们可以把它封装起来,需要使用时引入一下就好。
本地工作目录:
Vue3脚手架项目 |-src |-utils |-echarts.js
echarts.js: 文件我放到自己建的utils文件夹了,如果换了位置记得自己改一下引入路径。
// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。 import * as echarts from 'echarts/core'; // 引入柱状图图表,图表后缀都为 Chart import { BarChart, LineChart } from 'echarts/charts'; // 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component import { TitleComponent, TooltipComponent, GridComponent, DatasetComponent, TransformComponent } from 'echarts/components'; // 标签自动布局,全局过渡动画等特性 import { LabelLayout, UniversalTransition } from 'echarts/features'; // 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步 import { CanvasRenderer } from 'echarts/renderers'; // 注册必须的组件 echarts.use([ TitleComponent, TooltipComponent, GridComponent, DatasetComponent, TransformComponent, LabelLayout, UniversalTransition, CanvasRenderer, BarChart, LineChart ]); export { echarts }
如果你选择globalProperties形式,在main.js
这样引入一下就好了:(使用方式不变)
import { createApp } from 'vue' import App from './App.vue' import router from './router' import { echarts } from '@/utils/echarts' // 按需引入echarts const app = createApp(App) app.use(router) app.mount('#app') app.config.globalProperties.$echarts = echarts // 挂载全局使用
而如果你选择provide / inject形式,则在app.vue
这样引入一下就好了:(使用方式不变)
<script setup> import { provide } from 'vue' import { echarts } from '@/utils/echarts' // 按需引入echarts provide('echarts', echarts) // 提供全局使用 </script>
四、循环输出
有时候我们要输出的图表数目可能是不确定的,这时我们要动态的绑定ref来获取dom,不知道的可以看官方文档的示例:传送门,接着假设拿到后端数据后并且页面也更新完了,我们就可以循环的去生成图表了,具体看下的案例。
代码演示:
<template> <div class="loop-output"> <h1>循环输出</h1> <div class="box"> <div v-for="item in echartsData.value" :key="item.id" ref="refList" class="echart"></div> </div> </div> </template> <script setup> import { ref, reactive, onMounted, nextTick } from 'vue' import * as echarts from 'echarts'; onMounted(() => { loadData() }) const refList = ref([]) const echartsData = reactive({ value: [] }) // 模拟加载后端数据 const loadData = () => { echartsData.value = [ { id: '1', value: 30, name: '藤原拓海' }, { id: '2', value: 60, name: '高桥凉介' }, { id: '3', value: 90, name: '奔驰上树' } ] // 需要等页面再次更新完,不然拿不到dom nextTick(() => { echartsData.value.forEach((e, i) => { initEcharts(e, refList.value[i]) }) }) } const initEcharts = (data, echartRef) => { // 基于准备好的dom,初始化echarts实例 const chart = echarts.init(echartRef); let option = { tooltip: { formatter: '{a} <br/>{b} : {c}%' }, series: [ { name: 'Pressure', type: 'gauge', detail: { formatter: '{value}' }, data: [data] } ] }; // 绘制图表 chart.setOption(option); } </script> <style lang="scss" scoped> .loop-output { margin: auto; max-width: 60vw; overflow: hidden; .box { display: flex; justify-content: space-around; flex-wrap: wrap; } .echart { width: 50%; height: 280px; } } </style>
五、动态更新
在我做的项目中不仅页面初次加载时要显示图表,还要根据筛选条件结果去动态更新图表,echarts的图表是用canvas
画出来的,所以想要二次更新需要先在onMounted
中初始化图表,接着用getOption()
拿到图表的option
实例,并且替换更新option里对应的图表数据,再用setOption(option)
去二次触发更新,否则是不会生效的;当然,强制用v-if
去销毁重建图表的dom,然后每次都去init
初始化图表也是可以实现二次更新的,不过那样图表会有闪烁的现象。
代码演示:
<template> <div class="update"> <h1>动态更新</h1> <div ref="echartRef" class="echart"></div> <h3>集齐七天不洗头你的愿望是什么?</h3> <button @click="updateEchart(0)" class="blue">脱单</button> <button @click="updateEchart(1)" class="green">双休</button> <button @click="updateEchart(2)" class="orange">暴富</button> </div> </template> <script setup> import { ref, onMounted } from 'vue' import * as echarts from 'echarts' onMounted(() => { // 初始化报表 pieChart = echarts.init(echartRef.value) option_pie.series[0].data = requestData pieChart.setOption(option_pie) }) const echartRef = ref() let pieChart const option_pie = { title: { text: '饼图', subtext: '', left: 'center' }, tooltip: { trigger: 'item' }, legend: { orient: 'vertical', left: 'left' }, series: [ { name: '', type: 'pie', radius: '50%', data: [], emphasis: { itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' } } } ] } // 模拟服务器获取的数据 let requestData = [ { value: 1, name: '脱单' }, { value: 1, name: '双休' }, { value: 1, name: '暴富' }, ] // 点击更新报表 const updateEchart = (id) => { // 模拟数据更新 if (id != undefined) requestData[id].value += 1 // 获取报表option实例 let option = pieChart.getOption() // 给实例赋上新的值 option.series[0].data = requestData // 二次更新图表 pieChart.setOption(option) } </script> <style lang="scss" scoped> .update { margin: auto; max-width: 60vw; .echart { width: 100%; height: 450px; } button { margin: 0 10px; color: white; cursor: cell; } .blue { background: #5470C6; } .green { background: #95D178; } .orange { background: #FAC858; } } </style>
获取项目Demo
有积分的交一下公粮,没有的话到Gitee下载就好
❀CSDN:
vue3-echarts(js原味):传送门
vue3-echarts-ts(ts风味):传送门
❀Gitee:
加载全部内容