更新:在VUE中封装图表时,你应该会遇到下面两个问题,到时候可以看下这里的解决方案:


最近在重构公司的系统后台,项目采用的是前后端分离模式,我负责的数据统计接口和前端模块的开发。上周出了数据统计的接口,这周的话,再写前端,前端主要就是用图表展示各种的统计信息,所以选择了echarts进行可视化开发。

这里提下Echarts,大学的时候接触的比较多,感觉Echarts的扩展性比较强,自定义样式的话也提供配置项,当时网上的教程比较少,想要一些炫酷的效果也只能自己按照文档一点点尝试,其实按照官方文档操作的话,修改起来也比较方便。

因为项目需要用到图表的地方比较多,所以对echarts图表简单的封装了下,下面是开发流程:

一:npm命令安装Echarts

在项目的根目录终端运行下列命令

npm install echarts --save

node_modules文件夹中存在echarts则代表安装成功

二:vue项目中引用echarts
在main.js使用import引入echarts

// 引入echarts
import * as echarts from 'echarts'

// 设置全局变量
Vue.prototype.$echarts = echarts

三:echarts子组件开发

先封装了一个基础折线图,首先在components新建Chart文件夹存放二次封装的组件,然后新建ChartBasicLine.vue文件
在这里插入图片描述

其实vue中使用Echarts和原生的调用流程几乎一致,现在模板里面写下面标签代码

  <div class="chart_content">
     <div
       :ref="chartObj.type"
       class="chart_show"
     />
   </div>

这里的ref很重要,用来获取本页面的dom元素,也就是当前的图表元素,在js图表初始化需要用到这个

然后在js的props可以引用父元素的数据,该数据是对象类型,用来传递父组件的图表信息,如:图片类型、X轴数据、Y轴数据等信息

export default {
  name: 'ChartBasicLine',
  props: {
    chartObj: {
      type: Object
    }
  }
}

接着在js中定义变量图表的配置信息option,这里的话,x和y轴的数据不用定义,是父组件传渲染的。

// 图表配置信息
option: {
  tooltip: {
    trigger: 'axis'
  },
  grid: {
    top: '22px',
    left: '40px',
    right: '30px'
  },
  xAxis: {
    type: 'category'
  },
  yAxis: {
    type: 'value'
  },
  series: [{
    type: 'line'
  }]
}

不同的图表option的值是不同的,需要去Echarts官网示例中查看代码

最后是初始化和渲染图表,这里定义showChart方法,在mounted中调用,其中初始化中refs代表一个对象,持有已注册过的ref的所有子组件,根据类型,渲染不同位置的图表

export default {
  name: 'ChartBasicLine',
  props: {
    chartObj: {
      type: Object
    }
  },
  data() {
    return {
      option: {
        tooltip: {
          trigger: 'axis'
        },
        grid: {
          top: '22px',
          left: '40px',
          right: '30px'
        },
        xAxis: {
          type: 'category'
        },
        yAxis: {
          type: 'value'
        },
        series: [{
          type: 'line'
        }]
      }
    }
  },
  mounted() {
  	// 初始化图表信息
    this.showChart()
  },
  methods: {
    showChart() {
      this.option.xAxis['data'] = this.chartObj.xData
      this.option.series[0]['data'] = this.chartObj.yData
      
      const myChart = this.$echarts.init(this.$refs[this.chartObj.type])
      
      myChart.setOption(this.option)
    }
  }
}

如上所示就是子组件的开发流程

如果想在单页面引用的话,上面div的ref去除:,定义一个值,showChart中设置下X和Y轴的数据就可

四:父组件调用子组件

这里的话就比较简单了,就是调用子组件就行,在index.vue中js引入子组件,定义组件所需要的变量值

// 引入图表子组件
import ChartBasicLine from '@/components/Chart/ChartBasicLine'

export default {
  components: { 
  	ChartBasicLine 
  },
  data() {
    return {
      chartRegUser: {
        num: 100,
        percent: '0.00%',
        status: 0,
        type: 'reg_user',
        tips: '新增用户',
        title: '新增用户(NU)',
        xData: ['2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01'],
        yData: [150, 230, 224, 218, 135, 147, 260]
      },
      chartActiveUser: {
        num: 100,
        percent: '0.00%',
        status: 0,
        type: 'active_user',
        tips: '活跃用户',
        title: '活跃用户(AU)',
        xData: ['2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01'],
        yData: [150, 230, 224, 218, 135, 147, 260]
      },
      chartPaidUser: {
        num: 100,
        percent: '0.00%',
        status: 0,
        type: 'paid_user',
        tips: '付费用户',
        title: '新增用户(PU)',
        xData: ['2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01'],
        yData: [150, 230, 224, 218, 135, 147, 260]
      },
      chartPaidMoney: {
        num: 100,
        percent: '0.00%',
        status: 0,
        type: 'paid_money',
        tips: '付费金额',
        title: '付费金额',
        xData: ['2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01'],
        yData: [150, 230, 224, 218, 135, 147, 260]
      }
    }
  }
}

然后在模板中调用下就行:

    <ChartBasicLine :chartObj="chartRegUser" />
    <ChartBasicLine :chartObj ="chartActiveUser" />
    <ChartBasicLine :chartObj="chartPaidUser" />
    <ChartBasicLine :chartObj="chartPaidMoney" />

五:效果展示

在这里插入图片描述
六:父组件及子组件源码

父组件

<template>
  <div class="index">
    <div class="index_top">
      <div class="index_top_title">
        首页
      </div>
      <div class="index_top_select">
        <el-select v-model="value" placeholder="请选择" size="medium">
          <el-option
            v-for="item in options"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
      </div>
    </div>
    <ChartBasicLine :chartObj="chartRegUser" />
    <ChartBasicLine :chartObj ="chartActiveUser" />
    <ChartBasicLine :chartObj="chartPaidUser" />
    <ChartBasicLine :chartObj="chartPaidMoney" />
  </div>
</template>

<script>
import ChartBasicLine from '@/components/Chart/ChartBasicLine'

export default {
  components: { ChartBasicLine },
  data() {
    return {
      options: [{
        value: '',
        label: '全部'
      }, {
        value: '选项2',
        label: '双皮奶'
      }, {
        value: '选项3',
        label: '蚵仔煎'
      }, {
        value: '选项4',
        label: '龙须面'
      }, {
        value: '选项5',
        label: '北京烤鸭'
      }],
      value: '',
      chartRegUser: {
        num: 100,
        percent: '0.00%',
        status: 0,
        type: 'reg_user',
        tips: '新增用户',
        title: '新增用户(NU)',
        xData: ['2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01'],
        yData: [150, 230, 224, 218, 135, 147, 260]
      },
      chartActiveUser: {
        num: 100,
        percent: '0.00%',
        status: 0,
        type: 'active_user',
        tips: '活跃用户',
        title: '活跃用户(AU)',
        xData: ['2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01'],
        yData: [150, 230, 224, 218, 135, 147, 260]
      },
      chartPaidUser: {
        num: 100,
        percent: '0.00%',
        status: 0,
        type: 'paid_user',
        tips: '付费用户',
        title: '新增用户(PU)',
        xData: ['2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01'],
        yData: [150, 230, 224, 218, 135, 147, 260]
      },
      chartPaidMoney: {
        num: 100,
        percent: '0.00%',
        status: 0,
        type: 'paid_money',
        tips: '付费金额',
        title: '付费金额',
        xData: ['2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01', '2021-08-01'],
        yData: [150, 230, 224, 218, 135, 147, 260]
      }
    }
  }
}
</script>
<style lang='scss' scoped>
.index {
  width: 100%;
  .index_top {
    width: 97%;
    height: 60px;
    line-height: 60px;
    margin: 10px 1.5%;
    display: flex;
    justify-content: space-between;
    .index_top_title {
      font-size: 20px;
      font-weight: bold;
      color: #333333;
    }
  }
}
</style>

子组件

<template>
  <div class="ChartBasicLine">
    <div class="chart_box">
      <div class="chart_top">
        <div class="chart_top_title">
          {{chartObj.title}}
        </div>
        <div class="chart_top_link">
          查看详情
        </div>
      </div>
      <div class="chart_info">
        <div class="chart_info_left">
          今日
          <span class="chart_today">{{chartObj.num}}</span>
          较昨日:
          <span>{{chartObj.percent}}</span>
        </div>
        <div class="chart_info_time">
          <div>
            时间筛选:
          </div>
          <div>
            <el-select v-model="value" placeholder="请选择" size="medium">
              <el-option
                v-for="item in dateArr"
                :key="item.value"
                :label="item.label"
                :value="item.value"
              />
            </el-select>
          </div>
        </div>
      </div>
      <div class="chart_content">
        <div
          :ref="chartObj.type"
          class="chart_show"
        />
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'ChartBasicLine',
  props: {
    showTitle: {
      type: Boolean,
      default: false
    },
    title: {
      type: String,
      default: null
    },
    chartObj: {
      type: Object
    }
  },
  data() {
    return {
      dateArr: [{
        value: '0',
        label: '实时'
      }, {
        value: '1',
        label: '自然日'
      }, {
        value: '2',
        label: '自然周'
      }, {
        value: '3',
        label: '自然月'
      }],
      value: '',
      option: {
        tooltip: {
          trigger: 'axis'
        },
        grid: {
          top: '22px',
          left: '40px',
          right: '30px'
        },
        xAxis: {
          type: 'category'
        },
        yAxis: {
          type: 'value'
        },
        series: [{
          type: 'line'
        }]
      }
    }
  },
  mounted() {
    this.showChart()
  },
  methods: {
    showChart() {
      this.option.xAxis['data'] = this.chartObj.xData
      this.option.series[0]['data'] = this.chartObj.yData
      const myChart = this.$echarts.init(this.$refs[this.chartObj.type])
      myChart.setOption(this.option)
    }
  }
}
</script>

<style>
  .el-input {
    margin-right: 0 !important;
  }
</style>

<style scoped>
  .chart_box {
    width: 47%;
    height: 500px;
    margin: 0px 1.5% 40px;
    padding: 0 1.5%;
    background-color: #ffffff;
    border-radius: 4px;
    box-shadow: 0 5px 5px 0 rgb(51 51 51 / 5%);
    float: left;
  }
  .chart_top {
    width: 100%;
    height: 40px;
    padding: 10px 0;
    line-height: 40px;
    font-size: 18px;
    font-weight: bold;
    display: flex;
    justify-content: space-between;
  }
  .chart_top_link {
    font-size: 14px;
    color: #2F54EB;
    font-weight: unset !important;
  }
  .chart_info {
    width: 100%;
    height: 40px;
    line-height: 40px;
    margin-top: 10px;
    display: flex;
    justify-content: space-between;
  }
  .chart_info_left {
    font-size: 15px;
  }
  .chart_info_time div {
    display: inline-block;
    vertical-align: top;
  }
  .chart_today {
    font-size: 25px;
    font-weight: bold;
    color: #2F54EB;
    margin: 0 20px 0 5px;
  }
  .chart_content {
    width: 100%;
    height: 380px;
    margin-top: 10px;
  }
  .chart_show {
    width: 100%;
    height: 350px;
    zoom: 1.25
  }
</style>

Logo

前往低代码交流专区

更多推荐