背景介绍
近期做了一个简单的vue+ele后台管理系统的项目,跟以前不一样的是,需要在vue后台管理系统最后一页中,实现3个echart数据图和一些数据展示。具体实现效果如图:
问题描述和办法总结
其实具体实现倒不复杂,但也不免踩了一些坑。在这里汇总如下
安装echart
安装好echarts后要做一个导入,这个步骤不能忘了,不然后面从初始化就无法执行。
import * as echarts from 'echarts';
获取Echart的DOM不成功
echart需要在一个具有宽高的盒子中绘制完成,因此需要先获取一个dom。但是获取dom的时候出现问题了,就是无法获取到dom
最后想了想,想到echart是要获取到一个dom,而相关的代码我却习惯性的放在created中,在created阶段还没有dom,怎么可能获取dom成功呢?
把相关代码改到了mounted中,又检查了dom的获取方法document.getElementById(document.getElementsByClassName也可),然后顺利获取到了dom。
另外需要注意PaymentOrderChart等初始化好后的echart图表需要保存到data中,因为重新获取到数据之后,需要执行PaymentOrderChart中的setOption对数据进行重新设置。
代码如下:
mounted() {
// 缴费订单数趋势折线图
let PaymentOrderChartDom = document.getElementsByClassName('payment_order_body')[0];
this.PaymentOrderChart = echarts.init(PaymentOrderChartDom);
let PaymentOrderChartOption = this.PaymentOrderChartOption
PaymentOrderChartOption && this.PaymentOrderChart.setOption(PaymentOrderChartOption,true);
// 缴费金额趋势折线图
let PaymentAmountChartDom = document.getElementsByClassName('payment_amount_body')[0];
this.PaymentAmountChart = echarts.init(PaymentAmountChartDom);
let PaymentAmountChartOption = this.PaymentAmountChartOption
PaymentAmountChartOption && this.PaymentAmountChart.setOption(PaymentAmountChartOption,true);
// 缴费金额分布饼状图
let PayContributeChartDom = document.getElementsByClassName('pay_contribute_body')[0];
this.PayContributeChart = echarts.init(PayContributeChartDom);
let payContributeOption = this.payContributeOption
payContributeOption && this.PayContributeChart.setOption(payContributeOption,true);
let that = this
setTimeout(function (){
window.onresize = function () {
that.PaymentOrderChart.resize();
that.PaymentAmountChart.resize();
that.PayContributeChart.resize()
}
},200)
},
echarts图表不会变化尺寸
最开始在拖拽浏览器窗口的时候,图标只会按照最初渲染大小显示,会造成图表畸大或者畸小
也就是说图表的宽度需要随着浏览器窗口的大小变化,因此需要在mounted中增加监视函数,让图表在浏览器窗口变化时重置显示尺寸。代码如下:
let that = this
setTimeout(function (){
window.onresize = function () {
that.PaymentOrderChart.resize();
that.PaymentAmountChart.resize();
that.PayContributeChart.resize()
}
},200)
查询条件变化后再次获取数据后,图表显示数据堆叠
这个问题很简单,就是在查询条件变化后,需要将原先的数据存放数组清空,不然push进去之后,显示的数据就是原先的数据再加上新获取的数据。
// 获取缴费订单数 缴费金额趋势折线图
async getPaymentOrderCountAndAmount(){
// 每次获取新数据前先清空图表数据
this.PaymentOrderChartOption.xAxis.data = []
this.PaymentOrderChartOption.series[0].data = []
this.PaymentAmountChartOption.xAxis.data = []
this.PaymentAmountChartOption.series[0].data = []
let {data:arr}= await getPaymentOrder(this.queryBean)
arr.forEach(item=>{
this.PaymentOrderChartOption.xAxis.data.push(item.dateNo)
this.PaymentOrderChartOption.series[0].data.push(item.totalCount)
this.PaymentAmountChartOption.xAxis.data.push(item.dateNo)
this.PaymentAmountChartOption.series[0].data.push(item.totalAmount)
})
// 更新缴费订单数趋势折线图
this.PaymentOrderChart.clear()
this.PaymentOrderChart.setOption(this.PaymentOrderChartOption,true)
// 更新缴费订单金额趋势折线图
this.PaymentAmountChart.clear()
this.PaymentAmountChart.setOption(this.PaymentAmountChartOption,true)
},
获取缴费金额分布饼状图,又对后台返回的数据进行了改造
// 获取缴费金额分布饼状图
async getPayContributeAmount(){
let {data:obj} = await getPayContribute(this.queryBean)
let arr = []
for (let key in obj){
let temp = {}
temp.value = obj[key]
if (key === 'totalAmount') continue
if( key === 'fifty') temp.name='小于50元'
if( key === 'hundred') temp.name='50~100元'
if( key === 'twoHundred') temp.name='100~200元'
if( key === 'threeHundred') temp.name='200~300元'
if( key === 'moreHundred') temp.name='大于300元'
arr.push(temp)
}
this.payContributeOption.series[0].data = arr
// 更新缴费分布饼状图
this.PayContributeChart.clear()
this.PayContributeChart.setOption(this.payContributeOption,true)
}
echart中自定义tooltip
tooltip就是鼠标经过的时候,显示的每个数据点的信息提示框,这个提示框可以可以在图表数据option中自行设置。不管是折线图还是饼状图,都可以在定义的formatter的返回值中定义提示框的格式和显示内容,注意formatter函数获取到的参数params基本上包含了这个数据点的所有数据。
有意思的是折线图中formatter的返回模板字符串可以识别<br>,而饼状图中的formatter的返回模板字符串无法识别<br>,只能直接换行才能显示正确。
// 缴费订单数趋势
PaymentOrderChart:null,
PaymentOrderChartOption:{
tooltip: {
show:true,
trigger: 'axis',
formatter:(params)=>{
return `${params[0].name.length === 8?'日期':'时间'}:${params[0].name}${params[0].name.length === 8?'':' 时'}<br>${params[0].marker}订单数:${params[0].value}个`
}
},
xAxis: {
type: 'category',
name:'时 间',
nameLocation:'middle',
nameTextStyle:{
fontSize:18,
},
nameGap:30,
data: []
},
yAxis:{
type: 'value',
name:'缴 费 订 单 数(个)',
nameLocation: 'middle',
nameTextStyle:{
fontSize:18,
},
nameGap:40
},
series: [
{
data: [],
type: 'line'
}
]
},
// 缴费金额分布 饼状图数据
PayContributeChart:null,
payContributeOption:{
tooltip: {
trigger: 'item'
},
legend: {
top: '25%',
right:'20%',
data:['小于50元','50~100元','100~200元','200~300元','大于300元'],
// left: 'center'
orient:'vertical',
itemGap:25
},
series: [
{
name: '缴费金额分布',
type: 'pie',
left:'-30%',
radius: ['40%', '70%'],
avoidLabelOverlap: true,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '20',
fontWeight: 'bold',
formatter:(params)=>{
return `${params.name}
${params.percent}%`
}
}
},
labelLine: {
show: false
},
data: [
// 格式:
// { value: 1048, name: 'Search Engine' },
]
}
]
}
页面所有显示数据和图标,需要随着搜索框选择值的变化而更新。
这一项就是说搜索框的选择值有变化时,需要重新获取页面数据
// 搜索框查询参数
queryBean: {
deptId: undefined,
chargeTimeBegin: undefined,
chargeTimeEnd: undefined,
},
一个参数影响到重新获取数据,这不watch正合适么,(computed是不行的,因为computed中只支持同步操作),马上将获取参数的函数都安排到watch监视器里面。最终效果完美实现
watch:{
queryBean:{
handler(val,oldVal){
// 获取充值人数
this.getSelectConsNoCount()
// 获取缴费信息
this.getPayDataList()
this.getSorderDataList()
this.getRefundDataList()
// 获取缴费订单数和金额
this.getPaymentOrderCountAndAmount()
// 机构贡献排行
this.getOrganContributeList()
// 设备贡献排行
this.getEquipContributeList()
// 获取缴费金额分布饼状图 数据
this.getPayContributeAmount()
},
deep:true
}
},
写在最后
其实我觉得发现问题并也不可怕,在项目中我发现的所有问题有些是百度解决的,其他很多都是根据代码原理想想也就改正过来了。就比如说的第一个例子“无法获取到DOM”,获取不到dom要不就是dom不存在,要不就是获取方法不正确。当能够确定写法正确的时候,那就一定是dom本身就不存在(nexttick也可以解决)。最终自然而然的就想到了vue的生命周期,也就顺利解决了这个问题。
好了,感谢您观看到这儿,有什么问题可以评论区留言。如果帮助到了您,欢迎点赞收藏哦!鞠躬!