项目中Echarts的使用记录

316 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情

分享在项目中使用Echarts的技巧和一些图表案例

本文内容EchartsVue3TypeScript结合使用

主观性较强,或许对你有帮助。

封装Echarts全局组件

Echarts的安装和引入,参照官网,官网已经有全局使用和按需使用的详细说明

之前使用TypeScript,不太清楚可以给option什么类型,现在回看官网就明白了

开始在components文件夹下创建echarts组件

echartsoptions的类型

echartsoptions的类型如下

type ECOption就是options的类型

import * as echarts from "echarts";
import { BarSeriesOption, LineSeriesOption } from "echarts/charts";
import {
  TitleComponentOption,
  TooltipComponentOption,
  GridComponentOption,
  DatasetComponentOption
} from "echarts/components";
export type ECOption = echarts.ComposeOption<
  | BarSeriesOption
  | LineSeriesOption
  | TitleComponentOption
  | TooltipComponentOption
  | GridComponentOption
  | DatasetComponentOption
>;

defineComponent版本

需要注意的是options的默认值是Function

在组件销毁时,要移除windowresize调用的事件

还有在初始化echarts,获取dom元素时,即便在onMounted事件中,也会有ts的警告, 需要用到! 非空断言操作符

<template>
  <div :id="id" class="echart-div"></div>
</template>

<script lang="ts">
import { defineComponent, onMounted, onUnmounted, PropType, ref, toRefs, watch } from "vue";
import * as echarts from "echarts";
import { ECOption } from "@/types/interface";
export default defineComponent({
  props: {
    id: {
      type: String,
      default: "echartDiv"
    },
    options: {
      type: Object as PropType<ECOption>,
      default: Function
    },
    theme: {
      type: String,
      default: ""
    }
  },
  setup(props) {
    const { options, id, theme } = toRefs(props);
    let chartDom: echarts.EChartsType | null = null;
    const handleOptionsChange = () => {
      if (chartDom != null) {
        chartDom.setOption({ ...options.value });
      }
    };
    const handleChartResize = () => {
      if (chartDom != null) {
        chartDom.resize();
      }
    };

    onMounted(() => {
      chartDom = echarts.init(document.getElementById(id.value)!, theme.value);
      chartDom.setOption({ ...options.value });
      window.addEventListener("resize", () => {
        handleChartResize();
      });
    });
    onUnmounted(() => {
      window.removeEventListener("resize", () => {
        handleChartResize();
      });
    });
    watch(
      () => options.value,
      () => {
        handleOptionsChange();
      },
      { deep: true }
    );
    return {};
  }
});
</script>

<style scoped>
.echart-div {
  width: 100%;
  height: 100%;
}
</style>

script setup版本

script setup语法看起来更加简约

<script setup lang="ts">
import { onMounted, onUnmounted, PropType, ref, toRefs, watch } from "vue";
import * as echarts from "echarts";
import { ECOption } from "@/types/interface";

const props = defineProps({
  id: {
    type: String,
    default: "echartDiv"
  },
  options: {
    type: Object as PropType<ECOption>,
    default: Function
  },
  theme: {
    type: String,
    default: ""
  }
});

let chartDom: echarts.EChartsType | null = null;
const handleOptionsChange = () => {
  if (chartDom != null) {
    chartDom.setOption({ ...props.options });
  }
};
const handleChartResize = () => {
  if (chartDom != null) {
    chartDom.resize();
  }
};

onMounted(() => {
  chartDom = echarts.init(document.getElementById(props.id)!, props.theme);
  chartDom.setOption({ ...props.options });
  window.addEventListener("resize", () => {
    handleChartResize();
  });
});
onUnmounted(() => {
  window.removeEventListener("resize", () => {
    handleChartResize();
  });
});

watch(
  () => props.options,
  () => {
    handleOptionsChange();
  },
  { deep: true }
);
</script>

个人的想法是,echarts全局组件只做图表的初始化,监听options的变化更新图表,监听windowresize事件让图表也resize

图表是怎样的完全取决于options的数据,详细看案例分享

注册全局组件

参考我之前的文章Vue项目中的实用技巧记录 - 掘金 (juejin.cn)

已分为webpackvite两种情况下如何自动注册全局组件

欢迎点赞分享

使用案例

基本使用

使用柱状图展示使用的案例

<script setup lang="ts">
import { reactive } from "vue";
import EchartsComponent from "@/components/echartsComponent.vue";
import { ECOption } from "@/types/interface";

const lightOptions = reactive({
  title: {
    text: "主题Demo"
  },
  tooltip: {},
  xAxis: {
    data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
  },
  yAxis: {},
  series: [
    {
      name: "销量",
      type: "bar",
      data: [5, 20, 36, 10, 10, 20]
    }
  ]
} as ECOption);

setTimeout(() => {
  lightOptions.series = {
    name: "销量",
    type: "bar",
    data: [0, 0, 1, 10, 20, 30]
  };
}, 1000);
</script>

<template>
  <div class="container">
    <!-- 亮色主题 -->
    <EchartsComponent :id="'lightTheme'" :options="lightOptions" class="echarts-demo light-theme"> </EchartsComponent>
    <!-- 黑暗主题 -->
    <EchartsComponent
      :id="'darkTheme'"
      :options="lightOptions"
      :theme="'dark'"
      class="echarts-demo dark-theme"
    ></EchartsComponent>
  </div>
</template>

<style lang="scss" scoped>
.container {
  display: flex;
}
.echarts-demo {
  height: 300px;
  width: 40%;
  margin: 20px;
}
</style>

效果图如下

image.png

环形进度图

之前项目遇到类似的ui设计,原本想用echarts实现,最后还是别的同事用canvas实现了

这次参考了 分享你我 的案例实现了

<script setup lang="ts">
import { reactive } from "vue";
import EchartsComponent from "@/components/echartsComponent.vue";
import { ECOption } from "@/types/interface";
import * as echarts from "echarts";

const chartData = {
  total: 100,
  value: 77
};
const total = chartData.total;
const value = [chartData.value];
const color = "rgba(149, 212, 117)";
const bgColor = "rgba(149, 212, 117,.1)";

const lightOptions = reactive({
  angleAxis: {
    max: total,
    clockwise: true, // 逆时针
    show: false // 隐藏刻度线
  },
  radiusAxis: {
    type: "category",
    show: true,
    axisLabel: {
      show: false
    },
    axisLine: {
      show: false
    },
    axisTick: {
      show: false
    }
  },
  polar: {
    center: ["50%", "50%"],
    radius: "100%" //图形大小
  },
  series: [
    {
      stack: "round",
      type: "bar",
      data: value,
      showBackground: false,
      coordinateSystem: "polar",
      roundCap: true,
      barWidth: 15,
      silent: true,
      itemStyle: {
        normal: {
          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
            {
              offset: 0,
              color: bgColor
            },
            {
              offset: 1,
              color: color
            }
          ])
        }
      }
    },
    {
      stack: "round",
      type: "bar",
      data: [0.01],
      showBackground: false,
      backgroundStyle: {
        shadowColor: "rgba(0, 0, 0, 0.2)",
        shadowBlur: 10,
        shadowOffsetY: 2
      },
      coordinateSystem: "polar",
      roundCap: true,
      barWidth: 15,
      itemStyle: {
        color: color,
        borderColor: color,
        borderWidth: 5
      }
    }
  ]
} as ECOption);
</script>

<template>
  <div class="container">
    <!-- 亮色主题 -->
    <EchartsComponent :id="'lightRing'" :options="lightOptions" class="echarts-demo light-theme"> </EchartsComponent>
    <!-- 黑暗主题 -->
    <EchartsComponent
      :id="'darkRing'"
      :options="lightOptions"
      :theme="'dark'"
      class="echarts-demo dark-theme"
    ></EchartsComponent>
  </div>
</template>

<style lang="scss" scoped>
.container {
  display: flex;
}
.echarts-demo {
  height: 300px;
  width: 40%;
  margin: 20px;
}
</style>

效果图如下

image.png

其他案例

待更新

详细代码

LWH/vite-vue3-project (gitee.com)

详细代码在src/views/echartssrc/components文件夹中

参考文章

全网echarts案例资源大总结和echarts的高效使用技巧(细节版) - 掘金 (juejin.cn)