uni-app+vue3 app二次封装echarts组件

545 阅读3分钟

组件说明: 由于项目中柱状图、折线图等echarts图表的基本样式几乎相同,如坐标轴样式、网格线等。所以封装成组件,用到echarts的地方,直接引入组件,传数据即可。

小tip:

  • 目前只是单个series系列的echarts, 堆叠图这种多系列的后续完善
  • 组件未完善功能, 如echarts的点击功能还没来得及做,后续完善

组件接收的参数:

  • type: echarts图表的类型,如bar、line、pie、strip(这个并不是官网的标准,这里是用来表示横向柱状图的)
  • optData: echarts图表的option
    const props = defineProps({
        type: String, // bar 、 line
        optData: Object,
    })

组件模板部分很简单,如下:

<template>
    <view>
        <view><l-echart class="chart" ref="chart" @finished="init"></l-echart></view>
    </view>
</template>

组件数据,这里默认设置了bar、line、pie、strip四种基本图

let barOption = {
        legend:{
            show:true,
            data:[]
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'cross'
          }
        },
        grid: {
          left: '3%',
          right: '8%',
          top: '15%',
          bottom:'5%',
          containLabel: true
        },
        xAxis: {
            type: 'category',
            data: [],
            axisLabel: {
              // inside: true,
              // color: '#fff'
            },
            axisTick: {
              show: false
            },
            axisLine: {
              show: true,
              lineStyle:{
                color: '#83bff6'
              }
            },
            z: 10
          },
          yAxis: {
            type: 'value',
            axisLine: {
              show: true,
              lineStyle:{
                color: '#83bff6'
              }
            },
            axisTick: {
              show: false
            },
            // axisLabel: {
            //   color: '#999'
            // },
            splitLine:{
              show:true,
              lineStyle:{
                type: 'dashed',
                color: '#83bff6'
              }
            }
        },
        series: [
        {
            data: [],
            type: "bar",
            itemStyle: {
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                  { offset: 0, color: '#83bff6' },
                  { offset: 0.5, color: '#188df0' },
                  { offset: 1, color: '#188df0' }
                ])
            },
            emphasis: {
                itemStyle: {
                  color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                    { offset: 0, color: '#2378f7' },
                    { offset: 0.7, color: '#2378f7' },
                    { offset: 1, color: '#83bff6' }
                  ])
                }
            },
            areaStyle: {
                show: true,
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                  {
                    offset: 0,
                    color: '#188df0'
                  },
                  {
                    offset: 1,
                    color: '#fff'
                  }
                ])
            },
          }
        ],
        color:['#83bff6']
    }
        
    let stripOption = {
        legend:{
            show:true,
            data:[]
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'cross'
          }
        },
        grid: {
          left: '3%',
          right: '8%',
          top: '15%',
          bottom:'5%',
          containLabel: true
        },
        yAxis: {
            type: 'category',
            data: [],
            axisLabel: {
              // inside: true,
              // color: '#fff'
            },
            axisTick: {
              show: false
            },
            axisLine: {
              show: true,
              lineStyle:{
                color: '#83bff6'
              }
            },
            z: 10
        },
        xAxis: {
            type: 'value',
            axisLine: {
              show: true,
              lineStyle:{
                color: '#83bff6'
              }
            },
            axisTick: {
              show: false
            },
            // axisLabel: {
            //   color: '#999'
            // },
            splitLine:{
              show:true,
              lineStyle:{
                type: 'dashed',
                color: '#83bff6'
              }
            }
        },
        series: [
        {
            data: [],
            type: "bar",
            itemStyle: {
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                  { offset: 0, color: '#83bff6' },
                  { offset: 0.5, color: '#188df0' },
                  { offset: 1, color: '#188df0' }
                ])
            },
            emphasis: {
                itemStyle: {
                  color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                    { offset: 0, color: '#2378f7' },
                    { offset: 0.7, color: '#2378f7' },
                    { offset: 1, color: '#83bff6' }
                  ])
                }
            },
            areaStyle: {
                show: true,
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                  {
                    offset: 0,
                    color: '#188df0'
                  },
                  {
                    offset: 1,
                    color: '#fff'
                  }
                ])
            },
          }
        ],
        color:['#83bff6']
    }
        
    let pieOption = {
      color:["#2f7ce2","#5bc9b6","#ffc851","#ff6f6f","#7cb3ff","#21949b","#a6a4ff","#ff9e73"],
      tooltip: {
          show: true,
          trigger: 'item',
          // formatter: (params) => {
             //  console.log(params)
          // }
      },
      legend: {
        top: '1%',
        left: 'center'
      },
      series: [
        {
           type: 'pie',
           radius: ['30%', '50%'],
           avoidLabelOverlap: false,
           emphasis: {
            label: {
              show: true,
              fontSize: '40',
              fontWeight: 'bold'
            }
          },
          data: []
        }
      ]
    };
    
    let chartOption = {
        line: barOption,
        bar: barOption,
        pie: pieOption,
        strip: stripOption
    }
    

根据type参数,渲染图表:

    const state = reactive({
        option:{},
    })
    function refreshOption(){
        state.option = chartOption[props.type];
        state.option.series[0].type = props.type;
        if(props.type !== "pie" && props.type !== "strip"){
            state.option.xAxis.data = props.optData.xData;
        }
        if(props.type === "strip"){
            state.option.yAxis.data = props.optData.xData;
            state.option.series[0].type = "bar";
        }
        state.option.series[0].data = props.optData.yData;
        if(props.optData.legendData){
            state.option.legend.data = props.optData.legendData;
            state.option.series[0].name = props.optData.legendData[0];
        }
        chart.value.init(echarts, chart => {
            chart.setOption(state.option);
        });
    }
​
    onMounted(() => {
        refreshOption()
    })

组件向外暴露的方法,只有向外暴露了组件外才能访问到以下内容:

    defineExpose({
        chart,
        refreshOption
    })

使用组件

<template>
    <view class="container">
        <view class="charts-box">
            <echart ref="lineChart" type="line" :optData="state.optLine" />
        </view>
        <uni-card title="月用电量情况">
            <view class="charts-box">
                <echart type="bar" :optData="state.optBar" />
            </view>
        </uni-card>
    </view>
</template>
   const state = reactive( {
        optLine: {},
        optBar: {},
    })
    state.optLine = {
        xData: [1,2, 3, 4, 5, 6, 7,8,9,10,11,12,13,1,4,15,16,17,18,19,20,21,22,23,24],
        yData: [100, 110, 113, 126, 143, 158, 165,167,152,102,,],
    }
    state.optBar = {
        xData: [1,2, 3, 4, 5, 6, 7,8,9,10,11,12,13,1,4,15,16,17,18,19,20,21,22,23,24],
        yData: [100, 110, 113, 126, 143, 158, 165,167,152,102,,],
        legendData: ['总功率'],
    }

动态更新数据时可调用以下方法:

function btnClick(btn){
        // change line
        state.optLine = {
            xData: [1,2, 3, 4, 5, 6, 7,8,9,10,11,12,13,1,4,15,16,17,18,19,20,21,22,23,24],
            yData: [100, 110, 113, 126, 143, 158, 165,167,152,102,156,126,180],
        }
        // delay use,because connot mount
        nextTick(() => {
          lineChart.value.refreshOption();
        })
    }

注:这里需要在nextTick中调用组件之前暴露出的refreshOption方法更新数据

效果图:

image-20221026150614571.png

image-20221026150629431.png

另外饼图和横向柱状图的使用也一样,效果图如下:

image-20221026150734179.png

image-20221026150747511.png