在Vue中封装Echarts并使用
为什么要封装
- 如果不封装,每用一次图表,都要重新配置一边option,封装起来方便复用,也方便统一管理。
- 解决元素以及窗口的resize等问题。
- 自己动手封装,只需要看一份文档,并且可以使用更多的原生功能。
- 看完这篇文章你或许觉得自己封装并不难。
效果图以及项目目录
1、效果图
2、项目目录
具体封装过程
1、Echarts的安装
npm i echarts --save
2、引入
- 全部引入
在你使用Echarts的.vue单文件直接使用以下语句引入:
import echarts from 'echarts'
- 按需引入
图省事可以整个引入,但是Echarts还是不小的,我们大部分只用到了其中的一部分功能,所以我推荐按需引入:
// 按需引入 引入 ECharts 主模块
var echarts = require('echarts/lib/echarts')
// 引入柱状图
require('echarts/lib/chart/pie')
// 引入提示框和标题组件
require('echarts/lib/component/tooltip')
require('echarts/lib/component/title')
require('echarts/lib/component/legend')
如果你想用某个组件,但是不清楚该组件属于Echarts的哪一个组成部分,这时你可以查阅文档,点进去鼠标往下翻两下就可以简单下面这张图了,里面说的也比较清楚:
3、封装案例
此处以堆叠柱状图为例:BarChart.vue
<template>
<div :class="className" :style="{height:height,width:width}" />
</template>
<script>
// 按需引入 引入 ECharts 主模块
var echarts = require('echarts/lib/echarts')
// 引入柱状图
require('echarts/lib/chart/bar')
// 引入提示框和标题组件
require('echarts/lib/component/tooltip')
require('echarts/lib/component/title')
import chartResize from './mixins/chart-resize'
export default {
mixins:[chartResize],
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '350px'
},
// 父组件传递过来的图表数据
chartData: {
type: Object,
required: true
}
},
data() {
return {
// Echarts实例
chart: null
}
},
watch: {
/* 如果图表数据是后台获取的,监听父组件中的数据变化,重新触发Echarts */
chartData: {
deep: true,
handler(val) {
this.setOptions(val)
}
}
},
mounted() {
/* 图表初始化 */
this.$nextTick(() => {
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) {
return
}
/* 释放图表实例 */
this.chart.dispose()
/* dispose 会释放内部占用的一些资源和事件绑定,但是解除实例的引用我们是做不到的,所以需要重新赋值为null */
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(this.$el)
this.setOptions(this.chartData)
},
setOptions({
days, data1, data2 } = {
}) {
this.chart.setOption({
title: {
text: '堆叠柱状图',
textStyle: {
fontSize: 15
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
// 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
grid: {
top: 35,
left: '2%',
right: '2%',
bottom: '3%',
containLabel: true
},
xAxis: [{
type: 'category',
data: days,
axisTick: {
alignWithLabel: true
}
}],
yAxis: [{
type: 'value',
axisTick: {
show: false
}
}],
series: [{
name: '数量一',
type: 'bar',
stack: 'vistors',
barWidth: '60%',
data: data1,
animationDuration:2000
},
{
name: '数量二',
type: 'bar',
stack: 'vistors',
barWidth: '60%',
data: data2,
animationDuration:2000
}]
})
}
}
}
</script>
- 在实际的情况当中,我们使用的图表数据一般都是从后台动态获取的,我们就需要对父组件传递过来的chartData进行监听,数据变化时,触发Echarts,进行视图的更新:
watch: {
/* 如果图表数据是后台获取的,监听父组件中的数据变化,重新触发Echarts */
chartData: {
deep: true,
handler(val) {
this.setOptions(val)
}
}
}
- 在组件销毁时,请不要忘记以下操作,释放一定的内存空间:
beforeDestroy() {
if (!this.chart) {
return
}
/* 释放图表实例 */
this.chart.dispose()
/* dispose 会释放内部占用的一些资源和事件绑定,但是解除实例的引用我们是做不到的,所以需要重新赋值为null */
this.chart = null
},
4、使用组件的页面
index.vue
<template>
<div id="echarts-container">
<el-row :gutter="20">
<el-col :span="12">
<div class="grid-content bg-purple">
<bar-chart :chartData="barChartData"/>
</div>
</el-col>
<el-col :span="12">
<div class="grid-content bg-purple">
<rose-chart />
</div>
</el-col>
</el-row>
<el-row style="background-color:#fff">
<line-chart :chartData="lineChartData" />
</el-row>
</div>
</template>
<script>
// 引入组件
import BarChart from './components/BarChart'
import RoseChart from './components/RoseChart'
import LineChart from './components/LineChart'
export default {
// 注册局部组件
components:{
BarChart,
RoseChart,
LineChart
},
data() {
return {
// 柱状图数据
barChartData: {
days: ['11.21', '11.22', '11.23', '11.24', '11.25', '11.26', '11.27'],
data1: [100, 120, 161, 134, 105, 160, 165],
data2: [120, 82, 91, 154, 162, 140, 145]
},
// 折线图数据
lineChartData: {
expectedData: [4, 9, 12, 11, 5, 2, 9],
actualData: [10, 4, 3, 11, 13, 10, 7]
}
}
}
}
</script>
<style lang="less" scoped>
#echarts-container{
width: 100%;
height: 100%;
background-color: #F0F2F5;
.el-row {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
.el-col {
border-radius: 4px;
}
.bg-purple-dark {
background: #99a9bf;
}
.bg-purple {
background: #fff;
}
.bg-purple-light {
background: #e5e9f2;
}
.grid-content {
border-radius: 4px;
min-height: 36px;
}
.row-bg {
padding: 10px 0;
background-color: #f9fafc;
}
}
</style>
- 在这个页面简单的使用了Element-UI的栅格布局。
- 在使用自己封装的Echarts组件时,也进行了数据的传入。
5、使用mixins解决resize问题
Echarts有更新数据的特性,以及窗口缩放时不能自适应的问题。这样导致数据更新了Echarts视图却没有更新,窗口缩放引起echarts图形变形问题。如下:
窗口变化,但是视图却没有自适应,就导致出现显示的问题。
但是使用了自定义的mixins之后,可以随着窗口的变化而自适应:
自定义的mixins代码如下:chart-resize.js
import ResizeListener from 'element-resize-detector';
export default {
methods: {
/* 对chart元素尺寸进行监听,当发生变化时同步更新echart视图 */
chartEleResizeListener() {
const chartInstance = ResizeListener({
strategy: 'scroll',
callOnAdd: true
});
chartInstance.listenTo(this.$el, () => {
if (!this.chart) return;
this.chart.resize();
});
},
/* 当窗口缩放时,echart动态调整自身大小 */
windowResizeListener() {
if (!this.chart) return;
this.chart.resize();
}
},
mounted() {
window.addEventListener('resize', this.windowResizeListener);
this.chartEleResizeListener();
},
beforeDestroy() {
window.removeEventListener('resize', this.windowResizeListener);
}
}
6、element-resize-detector
是一个监听元素大小改变的插件,除了窗口的大小改变会引起变形之外,echart实例的父元素大小
改变也会使其变形,所以我们还要对其父元素大小改变进行监听,做到完全的自适应。
写在最后
如有不足,欢迎指正。
对源码感兴趣欢迎访问我的github。
来源:oschina
链接:https://my.oschina.net/u/4309857/blog/4873634