封裝一個ECharts組件的一點思路
有關后台管理系統之前寫過三遍博客,看這篇之前最好先看下這三篇博客。另外這里只展示關鍵部分代碼,項目代碼放在github上: mall-manage-system
1、Vue + Element-ui實現后台管理系統(1) --- 總述
2、Vue + Element-ui實現后台管理系統(2) --- 項目搭建 + ⾸⻚布局實現
3、Vue + Element-ui實現后台管理系統(3) --- 面包屑 + Tag標簽切換功能
這篇主要講解實現圖表的功能:
整體效果

一、封裝一個ECharts組件的一點思路
1、繪制一個簡單的圖表
ECharts上手非常簡單,具體簡單示例可以參考我之前寫的一篇博客:圖表工具--- ECharts.js學習(一) 簡單入門。
2、封裝思路
在實際項目開發中,我們會經常與圖表打交道,比如 訂單數量表、商品銷量表、會員數量表等等,它可能是以折線圖、柱狀圖、餅狀圖等等的方式來展現。
如果我們沒有封裝組件的思想的話,那么我們每次需要畫一個圖表都要重復類似相同的工作,而且代碼看去非常冗余。所以我們就需要考慮封裝一個ECharts組件,這個組件通過接收
不同的數據來渲染成不同的圖表,以后當需要生成一張圖表的時候,只需要把相關的數據傳入到這個組件中,就會渲染對應的圖表。
而這里的核心就是 哪些數據是需要我們傳入組件中的。針對這個問題我們來看下一個ECharts最簡單的示例
// 指定圖表的配置項和數據
var option = {
title: {
text: 'ECharts 入門示例'
},
tooltip: {},
legend: {
data:['銷量']
},
xAxis: {
data: ["襯衫","羊毛衫","雪紡衫","褲子","高跟鞋","襪子"]
},
yAxis: {},
series: [{
name: '銷量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
};
運行結果

這里展示了一個最簡單的圖表,官方例子地址:5 分鍾上手 ECharts,下面對這些參數做個講解
title : 標題
tooltip : 提示框組件
legend : 圖例組件
xAxis : 直角坐標軸中的 x 軸
yAxis : 直角坐標軸中的 y 軸
series : 系列列表。每個系列通過 type 決定自己的圖表類型
這幾個組件來看 series
和 xAxis
是肯定需要外部傳來的數據,y軸 的數據跟series中data相關不需要單獨再傳。至於title , tooltip , legend並不是圖表必須的,所以
不是必須要傳的。就好比你一個圖表你可以沒有標題。
注意
這里還有一點 x軸對於柱狀圖、折線圖相關圖是一定要有的,但對於餅狀圖來講它又不是必須的,所以這里封裝一個ECharts組件時,需要考慮這一點。
3、封裝ECharts組件
新建一個EChart.vue,作為封裝ECharts的組件
<template>
<!--圖表展示在這個div中-->
<div style="height: 100%" ref="echart">
echart
</div>
</template>
<script>
import echarts from 'echarts'
export default {
//接收父類兩個數據 1、chartData (series數據 + x坐標系數據)2、isAxisChart (是否有x坐標系,如果false,那么上面的xData就為空)
props: {
chartData: {
type: Object,
default() {
return {
xData: [],
series: []
}
}
},
isAxisChart: {
//默認type為true 就代表默認是有x軸的
type: Boolean,
default: true
}
},
computed: {
//計算 選擇是有x軸 還是沒有x軸的數據
options() {
return this.isAxisChart ? this.axisOption : this.normalOption
},
//用於下面的resize 改變圖表尺寸,在容器大小發生改變時需要手動調用
isCollapse() {
return this.$store.state.tab.isCollapse
}
},
watch: {
//監聽chartData數據
chartData: {
handler: function() {
this.initChart()
},
deep: true
},
//監聽isCollapse 因為頭部水平擴展是一個動畫需要時間,所以這里延遲300毫秒
isCollapse() {
setTimeout(() => {
this.resizeChart()
}, 300)
}
},
data() {
//在數據中有些數據在數據件中是寫死的
return {
echart: null,
axisOption: {
legend: {
textStyle: {
color: '#333'
}
},
grid: {
left: '20%'
},
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: [],
axisLine: {
lineStyle: {
color: '#17b3a3'
}
},
axisLabel: {
color: '#333'
}
},
yAxis: [
{
type: 'value',
axisLine: {
lineStyle: {
color: '#17b3a3'
}
}
}
],
color: [
'#2ec7c9',
'#b6a2de',
'#5ab1ef',
'#ffb980',
'#d87a80',
'#8d98b3',
'#e5cf0d',
'#97b552',
'#95706d',
'#dc69aa',
'#07a2a4',
'#9a7fd1',
'#588dd5'
],
series: []
},
normalOption: {
tooltip: {
trigger: 'item'
},
color: ['#0f78f4', '#dd536b', '#9462e5', '#a6a6a6', '#e1bb22', '#39c362', '#3ed1cf'],
series: []
}
}
},
methods: {
initChart() {
//獲取處理好的數據
this.initChartData()
//獲取echart對象
if (this.echart) {
this.echart.setOption(this.options)
} else {
//通過refs獲取
this.echart = echarts.init(this.$refs.echart)
this.echart.setOption(this.options)
}
},
//處理好數據
initChartData() {
if (this.isAxisChart) {
this.axisOption.xAxis.data = this.chartData.xData
this.axisOption.series = this.chartData.series
} else {
this.normalOption.series = this.chartData.series
}
},
resizeChart() {
this.echart ? this.echart.resize() : ''
}
},
mounted() {
//resize 改變圖表尺寸,在容器大小發生改變時需要手動調用(因為側邊欄是可以收縮的,所以這里圖表根據是否收縮來改變圖表尺寸)
window.addEventListener('resize', this.resizeChart)
},
//銷毀 防止內存泄漏
destroyed() {
window.removeEventListener('resize', this.resizeChart)
}
}
</script>
<style lang="scss" scoped></style>
這樣一個簡單的公共組件就完成了,接下來我們通過傳入不同的數據到這個組件來渲染不同的圖表。
二、傳入EChart組件數據
我們看到在首頁有三個圖表,那我們這里就要組裝三種不同的數據,傳入到EChart.vue組件中,來生成不同的圖表。
<template>
<div>
<!--圖表一 這里的數據是折線圖-->
<echart style="height: 280px" :chartData="echartData.order"></echart>
<!--圖表二 這里的數據是柱狀圖-->
<echart :chartData="echartData.user" style="height: 260px"></echart>
<!--圖表三 這里的數據是餅狀圖 因為餅狀圖是不用x軸的 所以這里isAxisChart為false-->
<echart :chartData="echartData.video" style="height: 260px" :isAxisChart="false">
</div>
</template>
<script>
import Echart from '../../components/EChart'
export default {
components: {
Echart
},
data() {
return {
echartData: {
//圖一
order: {
xData: [],
series: []
},
//圖二
user: {
xData: [],
series: []
},
//圖三 餅狀圖沒有x軸
mall: {
series: []
}
}
}
},
methods: {
getTableData() {
this.$http.get('/home/getData').then(res => {
res = res.data
// 訂單折線圖
const order = res.data.orderData
//x軸數據 為日前
this.echartData.order.xData = order.date
// 第一步取出series中的name部分——小米,三星、蘋果...
let keyArray = Object.keys(order.data[0])
// 第二步,循環添加數據
keyArray.forEach(key => {
this.echartData.order.series.push({
//如果有需要還可以做一步抓換比如:后台返回性別是1、2。那這里key === 1 ? '男' : 女,
name: key === 'wechat' ? '小程序' : key,
data: order.data.map(item => item[key]),
type: 'line'
})
})
// 用戶柱狀圖
this.echartData.user.xData = res.data.userData.map(item => item.date)
this.echartData.user.series.push({
name: '新增用戶',
data: res.data.userData.map(item => item.new),
type: 'bar'
})
this.echartData.user.series.push({
name: '活躍用戶',
data: res.data.userData.map(item => item.active),
type: 'bar',
barGap: 0
})
// 商品餅圖
this.echartData.mall.series.push({
data: res.data.mallData,
type: 'pie'
})
})
}
},
created() {
this.getTableData()
}
}
</script>
大致的思路就是這樣的,如果你想在組件中加入title等參數,那也可以修改下這個組件就可以了。
總結下封裝組件的基本思路
1、觀察⽂檔,考慮組件需要的基本參數
2、參數篩選,分為從⽗組件傳來的參數和⾃身的參數
3、完善組件,觀察設計圖,找不同,在⽂檔中尋找對應的配置項
4、細節優化,考慮多種場景下,圖表⾃適應的處理
別人罵我胖,我會生氣,因為我心里承認了我胖。別人說我矮,我就會覺得好笑,因為我心里知道我不可能矮。這就是我們為什么會對別人的攻擊生氣。
攻我盾者,乃我內心之矛(14)