vue3 echart组件封装

这篇具有很好参考价值的文章主要介绍了vue3 echart组件封装。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

项目中用到了很多echart图表,进行了简单的组件封装,主要包含以下功能:文章来源地址https://www.toymoban.com/news/detail-837815.html

  • 创建图表实例,渲染图表
  • 支持传入自定义函数,可拿到图表实例,实现个性化功能
  • 支持配置更新后图表自动刷新,可配置是清空后再刷新
  • loading状态控制
  • resize时图表更新
  • 支持饼图默认高亮功能

实现

资源引入

  • echart资源按需引入
  • 第三方组件引入(echarts-liquidfill,水波纹图表)
/* 即下文中的 @/modules/echartPlugin */

// https://echarts.apache.org/handbook/zh/basics/import#%E6%8C%89%E9%9C%80%E5%BC%95%E5%85%A5-echarts-%E5%9B%BE%E8%A1%A8%E5%92%8C%E7%BB%84%E4%BB%B6
import * as echarts from "echarts/core";
import {
  BarChart,
  // 系列类型的定义后缀都为 SeriesOption
  BarSeriesOption,
  PieChart,
  PieSeriesOption,
  LineChart,
  LineSeriesOption,
  LinesChart,
  LinesSeriesOption,
  EffectScatterChart,
  EffectScatterSeriesOption,
} from "echarts/charts";
import {
  TitleComponent,
  // 组件类型的定义后缀都为 ComponentOption
  TitleComponentOption,
  TooltipComponent,
  TooltipComponentOption,
  DatasetComponent,
  DatasetComponentOption,
  GridComponent,
  GridComponentOption,
  DataZoomComponent,
  DataZoomComponentOption,
  LegendComponent,
  LegendComponentOption,
  GeoComponent,
  GeoComponentOption,
} from "echarts/components";
import { CanvasRenderer } from "echarts/renderers";
import "echarts-liquidfill";

// 通过 ComposeOption 来组合出一个只有必须组件和图表的 Option 类型
export type ECOption = echarts.ComposeOption<
  | BarSeriesOption
  | TitleComponentOption
  | TooltipComponentOption
  | GridComponentOption
  | DatasetComponentOption
  | DataZoomComponentOption
  | PieSeriesOption
  | LegendComponentOption
  | GeoComponentOption
  | LinesSeriesOption
  | LineSeriesOption
  | EffectScatterSeriesOption
>;

// https://www.npmjs.com/package/echarts-liquidfill
export interface LiquidFillOption {
  series: {
    type: "liquidFill";
    data: number[];
    color?: string[];
    radius?: string;
    center?: [string, string];
    label?: {
      color?: string;
      insideColor?: string;
      fontSize?: number;
      formatter?: (param: {
        borderColor: string;
        color: string;
        data: number;
        dataIndex: number;
        dataType: undefined;
        name: string;
        value: number;
      }) => string | number;
    };
    shape?:
      | "circle"
      | "rect"
      | "roundRect"
      | "triangle"
      | "diamond"
      | "pin"
      | "arrow";
    [name: string]: unknown;
  }[];
  [name: string]: unknown;
}

// 注册必须的组件
echarts.use([
  TitleComponent,
  TooltipComponent,
  GridComponent,
  BarChart,
  LinesChart,
  CanvasRenderer,
  DatasetComponent,
  DataZoomComponent,
  PieChart,
  LegendComponent,
  GeoComponent,
  LineChart,
  EffectScatterChart,
]);

export default echarts;

组件封装

<template>
  <div class="h-echart-wrapper" ref="chartWrapperDom">
    <div class="h-echart" ref="chartDom">loading</div>
  </div>
</template>
<script lang="ts" src="./index.ts"></script>
<style lang="less" scoped>
.h-echart-wrapper {
  height: 100%;
}
.h-echart {
  height: 100%;
  width: 100%;
  text-align: center;
}
</style>
import {
  defineComponent,
  onMounted,
  onUnmounted,
  PropType,
  ref,
  watch,
  toRaw,
} from "vue";
import echarts, { ECOption, LiquidFillOption } from "@/modules/echartPlugin";
import ResizeObserver from "resize-observer-polyfill";

export default defineComponent({
  name: "h-echart",
  props: {
    // echart配置
    options: {
      type: Object as PropType<ECOption | LiquidFillOption>,
      required: true,
    },
    // 饼图是否需要默认高亮
    needDefaultHighLight: {
      type: Boolean,
      default: false,
    },
    loading: Boolean,
    // 自定义函数,会暴露echart实例出去,可以实现个性化操作
    customFn: Function as PropType<
      (echartInstance: null | echarts.ECharts) => void
    >,
    // 更新图表之前是否先清空
    clearBeforeUpdate: Boolean,
  },
  setup(props) {
    const chartWrapperDom = ref<null | HTMLElement>(null);
    const chartDom = ref<null | HTMLElement>(null);
    // WARN: echarts5 实例用响应式对象存放时会导致功能tooltip功能异常
    let echartInstance: null | echarts.ECharts = null;
    let chartWrapperResize: null | ResizeObserver = null;
    let highlightName: string | null = null;
    let firstRender = true;

    const setOptions = (options?: ECOption | LiquidFillOption) => {
      echartInstance &&
        options &&
        echartInstance.setOption(toRaw(options), {
          notMerge: true,
        });

      if (props.needDefaultHighLight && firstRender) {
        firstRender = false;
        const _options = props.options as ECOption;

        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        if (_options.series && _options.series[0] && _options.series[0].data) {
          // eslint-disable-next-line @typescript-eslint/ban-ts-comment
          // @ts-ignore
          const name = _options.series[0].data[0].name as string;

          setTimeout(() => {
            // 默认高亮
            echartInstance &&
              echartInstance.dispatchAction({
                type: "highlight",
                seriesIndex: 0,
                name,
              });

            highlightName = name;
          }, 600);
        }
      }
    };

    watch(
      () => props.loading,
      (newLoading) => {
        if (newLoading !== undefined && echartInstance) {
          newLoading
            ? echartInstance.showLoading({
                textColor: "rgb(255 255 255 / 0%)",
                showSpinner: false,
                zlevel: 0,
              })
            : echartInstance.hideLoading();
        }
      }
    );

    const init = () => {
      chartDom.value && (echartInstance = echarts.init(chartDom.value));

      props.customFn && props.customFn(echartInstance);

      if (props.needDefaultHighLight && echartInstance) {
        echartInstance.on("mouseover", function (e) {
          if (e.name !== highlightName) {
            echartInstance!.dispatchAction({
              type: "downplay",
              seriesIndex: 0,
              name: highlightName,
            });
          }
        });

        echartInstance.on("mouseout", function (e) {
          highlightName = e.name;
          echartInstance!.dispatchAction({
            type: "highlight",
            seriesIndex: 0,
            name: e.name,
          });
        });
      }
      setOptions(props.options);
    };

    onMounted(() => {
      // 初始化图表实例
      setTimeout(init, 300);

      // 观察包裹层变化,进行图表resize
      if (chartWrapperDom.value) {
        chartWrapperResize = new ResizeObserver(() => {
          echartInstance && echartInstance.resize();
        });

        chartWrapperResize.observe(chartWrapperDom.value);
      }
    });

    // 观察者清理
    onUnmounted(() => {
      chartWrapperResize?.disconnect();
    });
    watch(
      () => props,
      // 配置变化,重新设置
      (newVal) => {
        if (newVal.clearBeforeUpdate) {
          echartInstance && echartInstance.clear();
        }
        setOptions(toRaw(newVal.options));
      },
      { immediate: true, deep: true }
    );

    return {
      chartDom,
      chartWrapperDom,
    };
  },
});

组件注册及全局类型声明

/* ./components/index.ts */
import { App } from "vue";
import HEchart from "./h-echart";
import HIframeKeepAlive from "./h-iframe-keep-alive/index.vue";

export default function useCompoments(app: App<Element>) {
  app &&
    app.component &&
    [
      HEchart,
      HIframeKeepAlive,
    ].forEach((_component) => {
      app.component(_component.name, _component);
    });
}

// 声明全局组件类型
// https://github.com/johnsoncodehk/volar/blob/master/extensions/vscode-vue-language-features/README.md
declare module "@vue/runtime-core" {
  export interface GlobalComponents {
    HEchart: typeof HEchart;
    HIframeKeepAlive: typeof HIframeKeepAlive;
  }
}
import useCompoments from "./components";

const app = createApp(App).use(router);
tempApp = app;

// 注册所自定义组件
useCompoments(app);

使用

    <div class="chart-wrapper">
      <h-echart :options="boardPieOptions" needDefaultHighLight />
    </div>
  const boardPieOptions = computed(() => {
    return getBoardPieOptions(props.arrivalNodeStats.types);
  });

到了这里,关于vue3 echart组件封装的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • vue3范围选择组件封装

    个人项目地址: SubTopH前端开发个人站 (自己开发的前端功能和UI组件,一些有趣的小功能,感兴趣的伙伴可以访问,欢迎提出更好的想法,私信沟通,网站属于静态页面) SubTopH前端开发个人站 https://subtop.gitee.io/subtoph.github.io/#/home 实现效果 直接上代码 组件文件  组件使用

    2024年02月11日
    浏览(35)
  • vue3组件封装系列-表单请求

    我们在开发一些后台管理系统时,总是会写很多的列表查询页面,如果不封装组件,就会无限的复制粘贴,而且页面很冗余,正常情况下,我们都是要把组件进行二次封装,来达到我们想要效果。这里我分享一下我近期封装的关于列表的组件封装。 vue3+element-plus srccomponents

    2024年04月23日
    浏览(34)
  • vue3组件二次封装Ui处理

    在Vue开发中,我们常常需要使用UI框架提供的组件。但是UI框架的组件可能并不符合我们的需求,这时候就需要进行二次封装。下面是一些关于Vue组件二次封装Ui处理的技巧: 子组件代码: 父组件使用: 如果使用props接收弊端: 基本上组件不会只有一两个属性,属性多的话接

    2023年04月14日
    浏览(83)
  • vue3自定义封装组件:消息提示、轮播图、加载更多、骨架屏组件

    定义组件:src/components/library/xtx-infinite-loading.vue 注册组件:src/components/library/index.js  引用组件:src/main.js 使用组件: .vue文件 首先是轮播图的样式:src/components/library/xtx-carousel.vue  然后是轮播图的结构与逻辑封装:src/components/library/xtx-carousel.vue 插件注册:src/components/library

    2024年02月12日
    浏览(46)
  • Vue3 + Element Plus 封装公共表格组件(带源码)

    由于项目中有很多菜单都是列表数据的展示,为避免太多重复代码,故将 Element Plus 的 Table 表格进行封装,实现通过配置展示列表数据 支持自动获取表格数据 支持数据列配置及插槽 支持操作列配置及插槽 支持多选框配置 支持表尾配置及插槽 支持分页显示 3.1 复制基本表格

    2024年02月08日
    浏览(87)
  • vue3封装element-ui-plus组件

    最近看视频学习封装公共组件,将学习的内容记录以下,方便以后cv。 下面跟未来的自己说:         先说思路再放代码嗷,我怕你以后忘了。要cv直接往最后拉。 思路:         其实主要是通过slot去接收父组件传递过来的模板。父组件引用了组件件,往里面传了个表单,

    2024年02月09日
    浏览(67)
  • 基于Vant组件库二次封装组件(TS+Vue3.x环境)

    1. 今天的需求是封装一个 Navigation Bar 导航栏组件,目的是给到App几乎所有的页面复用:      2. 因为之前的项目里使用过Vant组件库,笔者第一时间想到了Vant组件库中的 NavBar 组件,和当前App的需求匹配度很高。Vant组件库的 NavBar 组件: 3. 相信你也发现了,Vant组件库默认主题

    2023年04月18日
    浏览(54)
  • vue3中播放flv流视频,以及组件封装超全

    实现以上功能的播放,只需要传入一个流的地址即可,当然组件也只有简单的实时播放功能 下面直接上组件 里面的flvjs通过npm i flv.js直接下载    这里我封装了两个组件   ,一个是单个的播放,另外一个是窗口切换的  这个是窗口切换的组件  下面是实际使用方法 因为上面

    2024年04月09日
    浏览(37)
  • vue2.x-echarts公共组件封装--简易篇(3d柱状图,炫酷仪表盘,折线,曲线图)

    更新一下之前写的echarts简单图表公共组件的封装,该组件可以实现自适应展示效果 废话不多说,上代码: vue-echarts通用组件 下面的一个混入文件是用来实现,窗口改变echarts自适应的js文件: 接下来是debounce.js 下面直接上代码:父组件调用+展示效果 截图: 下面是一个仪表盘

    2023年04月13日
    浏览(72)
  • axios封装—vue3项目

    前言 axios的API很友好,可以在项目中直接使用。但是在大型项目中,http请求很多,且需要区分环境, 每个网络请求有相似需要处理的部分,会导致代码冗余,破坏工程的可维护性,扩展性,所以需要对axios请求进行相应的封装 正文 安装axios 封装请求api 1. 在src目录下新建个

    2024年02月07日
    浏览(78)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包