Echarts组件封装

本文介绍了如何在Vue中使用Echarts子组件绘制图表,并结合utils/auth.js中的debounce函数实现窗口大小变化时的防抖处理,确保图表在窗口调整后能够正确响应。Echarts子组件监听窗口resize事件,利用防抖函数控制resize处理函数的调用频率,优化性能。同时展示了在父组件中如何配置并使用这些图表。
摘要由CSDN通过智能技术生成

一、utils/auth.js方法

/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export 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;
  };
}

二、Echarts子组件
在这里插入图片描述

// resize.js
import { debounce } from "@/utils/auth";

export default {
  data() {
    return {
      $_sidebarElm: null,
      $_resizeHandler: null
    };
  },
  mounted() {
    this.initListener();
  },
  activated() {
    if (!this.$_resizeHandler) {
      this.initListener();
    }
    this.resize();
  },
  beforeDestroy() {
    this.destroyListener();
  },
  deactivated() {
    this.destroyListener();
  },
  methods: {
    $_sidebarResizeHandler(e) {
      if (e.propertyName === "width") {
        this.$_resizeHandler();
      }
    },
    initListener() {
      this.$_resizeHandler = debounce(() => {
        this.resize();
      }, 100);
      window.addEventListener("resize", this.$_resizeHandler);

      this.$_sidebarElm = document.getElementsByClassName("sidebar-container")[0];
      this.$_sidebarElm &&
        this.$_sidebarElm.addEventListener("transitionend", this.$_sidebarResizeHandler);
    },
    destroyListener() {
      window.removeEventListener("resize", this.$_resizeHandler);
      this.$_resizeHandler = null;

      this.$_sidebarElm &&
        this.$_sidebarElm.removeEventListener("transitionend", this.$_sidebarResizeHandler);
    },
    resize() {
      const { chart } = this;
      // this.resize()
      chart && chart.resize();
    }
  }
};
// index.vue
<template>
  <div :id="id" :class="className" :style="{ height: height, width: width }"></div>
</template>
<script>
// import echarts from "echarts"; //版本过高无法使用
import * as echarts from "echarts";
import resize from "./mixins/resize";
export default {
  mixins: [resize],
  props: {
    // class类名
    className: {
      type: String,
      default: "chart"
    },
    // 图表唯一标识,当id重复将会报错
    id: {
      type: String,
      default: "chart"
    },
    // 图表宽度
    width: {
      type: String,
      default: "100%"
    },
    // 图表高度
    height: {
      type: String,
      default: "300px"
    },
    // 图表类型,提供三种(line:折线  bar:柱形  pie:饼图)
    type: {
      type: String,
      default: "line"
    },
    // 默认配置数据
    defaultData: {
      type: Object,
      default: () => ({
        //图表标题
        titleText: "访问量统计",
        // 图表副标题
        subText: "",
        // x轴描述
        xText: "类别",
        // y轴描述
        yText: "总访问量",
        // 饼图类型 0:普通 1:环形图 2:玫瑰图
        pieType: 0,
        // 是否圆角环形图
        isRadius: false,
        // 是否为平滑曲线
        smooth: false
      })
    },
    // 传入的数据
    chartData: {
      type: [Object, Array],
      default: () => {}
    }
  },
  watch: {
    chartData(val) {
      switch (this.type) {
        case "lie":
          this.drawLine(val);
          break;
        case "bar":
          this.drawBar(val);
          break;
        case "pie":
          this.drawPie(val);
          break;
        default:
          this.drawLine(val);
          break;
      }
    }
  },
  mounted() {
    switch (this.type) {
      case "lie":
        this.drawLine(this.chartData);
        break;
      case "bar":
        this.drawBar(this.chartData);
        break;
      case "pie":
        this.drawPie(this.chartData);
        break;
      default:
        this.drawLine(this.chartData);
        break;
    }
  },
  data() {
    return {
      // 饼图配置数据
      series: [],
      chart: null
    };
  },
  methods: {
    // 绘制折线
    drawLine(chartData) {
      const _this = this;
      this.chart = echarts.init(document.getElementById(this.id));
      let xAxisData = chartData.list.map(function (item) {
        return item.name;
      });
      let lineData = [];
      chartData.list.forEach((item) => {
        lineData.push({
          name: item.name,
          type: this.type,
          // stack: this.type === "" ? "Total" : "",
          data: item.data,
          smooth: this.defaultData.smooth
        });
      });
      this.chart.setOption({
        title: {
          text: this.defaultData.titleText,
          subtext: this.defaultData.subText,
          left: "left"
        },
        tooltip: {
          trigger: "axis"
        },
        legend: {
          data: xAxisData,
          top: "6%",
          type: "scroll"
        },
        grid: {
          top: 100,
          left: 0,
          right: "10%",
          bottom: 60,
          containLabel: true
        },
        toolbox: {
          show: true,
          orient: "vertical",
          // left: "right",
          top: "center",
          right: 20,
          feature: {
            dataView: {
              show: true,
              readOnly: false,
              optionToContent: function (opt) {
                // 绘制数据表格
                let table = _this.getTable(opt);
                return table;
              }
            },
            magicType: {
              type: ["line", "bar", "stack", "tiled"]
            },
            restore: {},
            saveAsImage: {}
          }
        },
        xAxis: [
          {
            name: chartData.xAxisTitle,
            type: "category",
            boundaryGap: this.type === "line" ? false : true,
            data: chartData.xAxis,
            axisTick: {
              alignWithLabel: this.type === "line" ? false : true
            }
          }
        ],
        yAxis: {
          name: chartData.yAxisTitle,
          type: "value"
        },
        dataZoom: [
          {
            type: "inside",
            start: 0,
            end: 100
          },
          {
            start: 0,
            end: 100
          }
        ],
        series: lineData
      });
    },
    // 绘制柱形图
    drawBar(chartData) {
      this.drawLine(chartData);
    },
    // 绘制饼图
    drawPie(chartData) {
      this.chart = echarts.init(document.getElementById(this.id));
      let xAxisData = chartData.map(function (item) {
        return item.name;
      });
      let pieData = [];
      chartData.forEach((v) => {
        pieData.push({
          name: v.name,
          value: v.count
        });
      });
      let series = [];
      switch (this.defaultData.pieType) {
        // 环形图
        case 1:
          series = [
            {
              name: this.defaultData.xText,
              type: "pie",
              radius: ["40%", "70%"],
              avoidLabelOverlap: false,
              itemStyle: {
                borderRadius: this.defaultData.isRadius ? 10 : "",
                borderColor: this.defaultData.isRadius ? "#fff" : "",
                borderWidth: this.defaultData.isRadius ? 2 : ""
              },
              label: {
                show: false,
                position: "center"
              },
              emphasis: {
                label: {
                  show: true,
                  fontSize: "26",
                  fontWeight: "bold"
                }
              },
              labelLine: {
                show: false
              },
              data: pieData
            }
          ];
          break;
        case 2:
          series = [
            {
              name: this.defaultData.xText,
              type: "pie",
              radius: [50, 150],
              center: ["50%", "50%"],
              roseType: "area",
              itemStyle: {
                borderRadius: 8
              },
              data: pieData
            }
          ];
          break;
        // 默认饼图
        default:
          series = [
            {
              name: this.defaultData.xText,
              type: "pie",
              radius: "55%",
              center: ["50%", "60%"],
              data: pieData,
              itemStyle: {
                shadowBlur: 10,
                shadowOffsetX: 0,
                shadowColor: "rgba(0, 0, 0, 0.5)"
              }
            }
          ];
          break;
      }
      this.chart.setOption({
        title: {
          text: this.defaultData.titleText,
          subtext: this.defaultData.subText,
          left: "left"
        },
        tooltip: {
          trigger: "item",
          formatter: "{a} <br/>{b} : {c} ({d}%)"
        },
        legend: {
          // orient: "vertical", //垂直展示
          left: "center",
          top: "6%",
          type: "scroll",
          data: xAxisData
        },
        series: series
      });
    },
    // 绘制数据表格
    getTable(opt) {
      let axisData = opt.xAxis[0].data; //坐标数据
      let series = opt.series; //折线图数据
      let tdHeads = "<td>时间</td>"; //表头
      let tdBodys = ""; //数据
      series.forEach(function (item) {
        //组装表头
        tdHeads += `<td>${item.name}</td>`;
      });
      let table = `<table border="1" style="border-collapse:collapse;
      font-size:14px;text-align:center;width:100%;"><tbody><tr>${tdHeads} </tr>`;
      for (let i = 0, l = axisData.length; i < l; i++) {
        for (let j = 0; j < series.length; j++) {
          //组装表数据
          tdBodys += `<td>${series[j].data[i]}</td>`;
        }
        table += `<tr><td style="padding: 0 20px">${axisData[i]}</td>${tdBodys}</tr>`;
        tdBodys = "";
      }
      table += "</tbody></table>";
      return table;
    }
  }
};
</script>

三、父组件使用

<template>
  <div class="app-container">
    <h1>饼图</h1>
    <charts
      :id="'pieCharts'"
      :default-data="defaultData"
      :chart-data="chartData"
      :type="'pie'"
      width="100%"
      height="450px"
    ></charts>
    <h1>折线图</h1>
    <charts
      :id="'lineCharts'"
      :default-data="defaultData"
      :chart-data="lineData"
      :type="'line'"
      width="100%"
      height="500px"
    ></charts>
    <h1>柱形图</h1>
    <charts
      :id="'barCharts'"
      :default-data="defaultData"
      :chart-data="lineData"
      :type="'bar'"
      width="100%"
      height="500px"
    ></charts>
  </div>
</template>
<script>
import Charts from "@/components/Echarts/index";
export default {
  components: {
    Charts
  },
  data() {
    return {
      // 默认配置
      defaultData: {
        titleText: "访问量统计",
        subText: "",
        xText: "类别",
        yText: "总访问量",
        type: "pie"
      },
      // 数据
      chartData: [
        { name: "类别1", count: 10 },
        { name: "类别2", count: 20 },
        { name: "类别3", count: 30 },
        { name: "类别4", count: 40 },
        { name: "类别5", count: 50 },
        { name: "类别6", count: 60 },
        { name: "类别7", count: 70 },
        { name: "类别8", count: 80 }
      ],
      // 折线数据
      lineData: {
        xAxisTitle: "周期/星期",
        yAxisTitle: "访问量",
        xAxis: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], //x轴
        list: [
          {
            name: "Email",
            data: [120, 132, 101, 134, 90, 230, 210]
          },
          {
            name: "Union Ads",
            data: [220, 182, 191, 234, 290, 330, 310]
          },
          {
            name: "Video Ads",
            data: [150, 232, 201, 154, 190, 330, 410]
          },
          {
            name: "Direct",
            data: [320, 332, 301, 334, 390, 330, 320]
          },
          {
            name: "Search Engine",
            data: [820, 932, 901, 934, 1290, 1330, 1320]
          }
        ]
      }
    };
  }
};
</script>

效果图
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值