最近接到了一个新的任务,要求把echarts的饼图放在table的每一个单元格中,饼图显示当前策略盈亏所占比例。
刚开始我就在想或许用render函数很好写出来,将饼图封装在一个组件中,在render函数里使用该组件。
但我的table里的每一项都是从后端传来的,包括表头也是不固定的,会根据想要搜索的日期,生成长度不同的各项。尝试用render函数:
this.symbols[item].render = () => <div class='test'><Chart ref='fetchCharts'></Chart></div>
但是渲染出来饼图的位置不是和它表头与列相对应的。
可能这个render函数我掌握的还不是很行,总之最后回归了原始,使用slot插入的。
1. 先写组件中的静态饼图
先在组件中写一个静态的饼图,不传数据,目的是测试在只写一个option下能否将其显示在各个单元格中,后期再将数据传递到series的data中,就可以实现各个单元格显示同样样式,但数据不同的饼图。
2. 将
组件显示在父组件中
if (this.hideChart === false) {
for (let item = 1; item < this.symbols.length; item++) {
// this.symbols[item].render = () =>
this.symbols[item].slot = 'action'
}
setTimeout(() => {
this.$refs.fetchCharts.fetchCharts()
}, 500)
}
利用for循环,在表头所对应的每一列插入名为 ‘action’ 的slot。
延时调用子组件的函数,是为了先将插槽安置好,再调用子组件,如果在调用子组件前,插槽还未安置好,echarts就会无处安放,导致饼图渲染不出来。
<div v-if="!hideChart">
<i-table :columns="symbols" :data="data" :loading="loading" :height="tableHeight">
<template slot-scope="{ row, index, column}" slot="action">
<Chart v-if='data[index][column.title]' ref="fetchCharts"></Chart>
</template>
</i-table>
</div>
在父组件中,利用 v-if
,目的是令没有数据,即不需要饼图的单元格不显示饼图。
3. 为每一个饼图设置不同id
进行完上面的步骤后,发现仅能显示出一个饼图,发现echarts在初始化的时候是需要一个占位的地方,通过获取元素的id,但在子组件中,仅有这一个id,故只能显示一个饼图,所以要为每一个饼图设置不同的id。
<template>
<div>
<div class="charts-container"></div>
</div>
</template>
为容器设置一个类,获取所有类名为 “charts-container” 的 DOM 元素,循环为其添加不同的 id ,并将这些id存到数组中,方便后面使用:
for (let i in chartsContainer) {
if (chartsContainer[i] === chartsContainer.length) {
break
}
chartsContainer[i].id = 'canvasId' + i
this.canvasIdArr.push('canvas' + i)
}
4. 将全部饼图显示在页面
设置完id,就可以利用循环数组,分别生成各个echarts饼图,从前的option、init、setOption,均以数组的形式创建,发现全部饼图被显示在页面中。
5. 传递数据
既然已经显示在页面中了,便可以传值了。其他地方不用动,只有data中的value通过父组件传的参数赋值。
父组件:
this.$refs.fetchCharts.fetchCharts(this.chart_data, this.pnArr)
子组件:
data: [
{value: this.dataDrawingNum[item], name: '数据'},
{value: (100 - this.dataDrawingNum[item]).toFixed(2), name: '其他'}
],
想让tooltip以百分比的形式显示,可以在tooltip[]里添加:
formatter: function (params) {
let tip = ''
tip = params.percent + '%'
return tip
}
想令饼图在正值时显示绿色,非正值显示红色,可以:
if (this.pnArr[item] > 0) {
optionArr[item].color = ['#F56C6C', '#409EFF']
} else {
optionArr[item].color = ['#67C23A', '#409EFF']
}
其实还有一些些的小bug,嘿嘿!这篇文章大概记录了一下思路,其实细节比这个复杂好多,我也不是一下想出来的,都是一点一点捋出来的,代码不是很好看也。。加油!