Vue项目,Echarts组件封装通用模板,内含NoData、resize处理逻辑

1、resize.js 主要处理Echarts组件自适应

export default {
  data() {
    return {
      $_resizeHandler: null
    }
  },
  mounted() {
    this.initListener()
  },
  activated() {
    if (!this.$_resizeHandler) {
      // avoid duplication init
      this.initListener()
    }
    // when keep-alive chart activated, auto resize
    this.resize()
  },
  beforeDestroy() {
    this.destroyListener()
  },
  deactivated() {
    this.destroyListener()
  },
  methods: {
    // use $_ for mixins properties
    // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
    $_sidebarResizeHandler(e) {
      if (e.propertyName === 'width') {
        this.$_resizeHandler()
      }
    },
    initListener() {
      this.$_resizeHandler = debounce(() => {
        this.resize()
      }, 100)
      window.addEventListener('resize', this.$_resizeHandler)
    },
    destroyListener() {
      window.removeEventListener('resize', this.$_resizeHandler)
      this.$_resizeHandler = null
    },
    resize() {
      // 单个绘图实例用chart,否则用charts
      const { chart, charts } = this
      if (Array.isArray(charts)) {
        charts.forEach(chart => {
          chart && chart.resize()
        })
      } else {
        chart && chart.resize()
      }
    }
  }
}
// import { debounce } from '@/utils'
/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
 function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result
  const later = function() {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp
    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last)
    } else {
      timeout = null
      // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args)
        if (!timeout) context = args = null
      }
    }
  }
  return function(...args) {
    context = this
    timestamp = +new Date()
    const callNow = immediate && !timeout
    // 如果延时不存在,重新设定延时
    if (!timeout) timeout = setTimeout(later, wait)
    if (callNow) {
      result = func.apply(context, args)
      context = args = null
    }
    return result
  }
}
2、baseChart.js 抽取公共绘图属性、处理逻辑
import resize from ‘./resize’

export default {
  mixins: [resize],
  props: {
    chartData: {
      type: Object,
      require: true,
      default: () => {}
    },
    chartOption: {
      type: Object,
      default: () => {}
    },
    chartId: {
      type: String,
      require: true,
      default: 'chart'
    },
    className: {
      type: String,
      default: 'chart'
    },
    width: {
      type: String,
      default: '100%'
    },
    height: {
      type: String,
      default: '400px'
    }
  },
  data() {
    return {
      chart: null
    }
  },
  watch: {
    chartData: {
      deep: true,
      handler(chartData) {
        this.updateOption(this.getOption(chartData))
      }
    }
  },
  mounted() {
    this.initChart()
  },
  beforeDestroy() {
    if (this.chart) {
      this.chart.dispose()
      this.chart = null
    }
  },
  methods: {
    initChart() {
      //customed 已注册的主题名称
      this.chart = this.$echarts.init(
        document.getElementById(this.chartId)
        // 'customed'
      )
      const option = this.getOption(this.chartData)
      this.updateOption(option)
    },
    updateOption(option) {
      const { seriesData = [] } = this.chartData
      if (seriesData.length === 0) {
        this.chart.clear()
        this.chart.showLoading({
          text: '暂无数据',
          color: '#fff',
          textColor: '#909399',
          fontSize: '14px'
        })
      } else {
        this.chart.hideLoading()
        this.chart.setOption(option, true)
      }
    }
    // getOption(data) {
    //   const option = {}
    //   // 合并传入option
    //   Object.assign(option, this.chartOption)
    //   return option
    // }
  }
}
3、示例封装一个柱图组件Bar.vue

<template>
    <div :id="chartId" :class="className" :style="{width: width, height:height}"></div>
</template>
<script>
    import baseChart from './mixins/baseChart.js'
    export default {
        mixins:[baseChart],//混入图表通用属性和处理逻辑
        methods: {
            getOption() {
                const { seriesData, xAxisData} = this.chartData
                let option = {
                    xAxis: {
                        type: 'category',
                        data:  xAxisData //['Mon', 'Tue', 'Wed', 'Thu',    'Fri', 'Sat', 'Sun']
                    },
                     yAxis: {
                        type: 'value'
                      },
                    series:  seriesData 
                    //  [{
                    //     data: [120, 200, 150, 80, 70, 110, 130],
                    //     type: 'bar'
                    // }]
                };
                //合并option,处理组件需要覆盖option属性
                option = Object.assign(option, this.chartOption)
                return option
            }
        }
    }
</script>
注意事项:
1、暂无数据处理,如果后端返回数据组装图表数据为空,seriesData = []
2、重置通用组件option某个属性,如果涉及到后端返回的接口数据,
在组件使用的地方:option-data="getOption(chartData)",通过调用函数处理

4、再封装一个pie图
<template>
	<div :id="chartId" :class="className" :style="{width: width, height:height}"></div>
</template>

<script>
	import baseChart from './mixins/baseChart.js'
	export default {
		mixins: [baseChart],
		methods: {
			getOption() {

				const {seriesData} = this.chartData

				const option = {
					tooltip: {
						trigger: 'item'
					},
					legend: {
						top: '5%',
						left: 'center'
					},
					series: [{
						name: 'Access From',
						type: 'pie',
						radius: ['40%', '70%'],
						avoidLabelOverlap: false,
						itemStyle: {
							borderRadius: 10,
							borderColor: '#fff',
							borderWidth: 2
						},
						label: {
							show: false,
							position: 'center'
						},
						emphasis: {
							label: {
								show: true,
								fontSize: '40',
								fontWeight: 'bold'
							}
						},
						labelLine: {
							show: false
						},
						data: seriesData
					}]
				};
				return option
			}

		}
	}
</script>

5、看看具体如何使用
<template>
	<div class="chart-page" id="chart">
		<Bar :chart-data="barChartData" :chart-option="{}" chart-id="barChart" class="chart" />
		
		<Pie :chart-data="pieChartData" :chart-option="{}" chart-id="pieChart" class="chart" />

		<LineChart :chart-data="{}" :chart-option="{}" chart-id="lineChart" class="chart" />
	</div>

</template>

<script>
	import Bar from '../components/Bar.vue'
	import LineChart from '../components/Line.vue'
	import Pie from '../components/Pie.vue'

	export default {
		name: "ChartDemo",
		components: {
			Bar,
			LineChart,
			Pie
		},
		data() {
			return {
				barChartData: {},
				pieChartData: {
					seriesData: []
				}
			}
		},
		mounted() {
			this.initPage()
		},
		methods: {
			initPage() {
				//axios
				this.barChartData = {
					xAxisData: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
					seriesData: [{
						data: [120, 200, 150, 80, 70, 110, 130],
						type: 'bar'
					}]
				}

				//axios
				this.pieChartData = {
					seriesData: [{
							value: 1048,
							name: 'Search Engine'
						},
						{
							value: 735,
							name: 'Direct'
						},
						{
							value: 580,
							name: 'Email'
						},
						{
							value: 484,
							name: 'Union Ads'
						},
						{
							value: 300,
							name: 'Video Ads'
						}
					]
				}


			},
			getOption(chartData) {
				const option = {
					yAxis: {
						data: chartData.yAxisData,
						type: 'value'
					}
				}
				return option
			}
		}

	}
</script>

<style scoped>
	.chart-page {
		display: flex;
		justify-content: space-between;
		align-items: center;
		width: 100%;
		height: 100%;
	}

	.chart {
		height: 400px ;
		width: 500px ;
	}
</style>

最终效果如下图:

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值