首页 > 其他分享 >记录--Vue3 封装 ECharts 通用组件

记录--Vue3 封装 ECharts 通用组件

时间:2023-06-19 19:13:43浏览次数:43  
标签:option -- props value ECharts Vue3 import chartInstance echarts

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

按需导入的配置文件

配置文件这里就不再赘述,内容都是一样的,主打一个随用随取,按需导入。

import * as echarts from "echarts/core";
// 引入用到的图表
import { LineChart, type LineSeriesOption} from "echarts/charts";
// 引入提示框、数据集等组件
import {
  TitleComponent,
  TooltipComponent,
  GridComponent,
  LegendComponent,
  type TooltipComponentOption,
  type TitleComponentOption,
  type GridComponentOption,
  type LegendComponentOption
} from "echarts/components";
// 引入标签自动布局、全局过渡动画等特性
import { LabelLayout } from "echarts/features";
// 引入 Canvas 渲染器,必须
import { CanvasRenderer } from "echarts/renderers";

import type { ComposeOption } from "echarts/core";

// 通过 ComposeOption 来组合出一个只有必须组件和图表的 Option 类型
export type ECOption = ComposeOption<
  | LineSeriesOption
  | GridComponentOption
  | TitleComponentOption
  | TooltipComponentOption
  | LegendComponentOption
>;

// 注册必须的组件
echarts.use([
  LineChart,
  TitleComponent,
  TooltipComponent,
  GridComponent,
  CanvasRenderer,
  LabelLayout,
  LegendComponent
]);

export default echarts;

基本封装

DOM结构和实例化

<script setup lang="ts">
import { Ref, onMounted, onBeforeUnmount } from "vue";
import { type EChartsType } from "echarts/core";

interface Props {
  option: ECOption;
  theme?: Object | string; // 主题
}

const props = withDefaults(defineProps<Props>(), {
  theme: null
});

const chartRef = ref<Ref<HTMLDivElement>>(null);
const chartInstance = ref<EChartsType>();

// 绘制
const draw = () => {
  if (chartInstance.value) {
    chartInstance.value.setOption(props.option, { notMerge: true });
  }
};

// 初始化
const init = () => {
  if (!chartRef.value) return;

  // 校验 Dom 节点上是否已经挂载了 ECharts 实例,只有未挂载时才初始化
  chartInstance.value = echarts.getInstanceByDom(chartRef.value);
  if (!chartInstance.value) {
    chartInstance.value = echarts.init(
        chartRef.value,
        props.theme,
        { renderer: "canvas" }
    );

    draw();
  }
};

watch(props, () => {
  draw();
});

onMounted(() => {
  init();
});

onBeforeUnmount(() => {
  // 容器被销毁之后,销毁实例,避免内存泄漏
  chartInstance.value?.dispose();
});
</script>

<template>
  <div id="echart" ref="chartRef" :style="{ width: '100px', height: '120px' }" />
</template>

chartRef:当前的 DOM 节点,即 ECharts 的容器;

chartInstance:当前 DOM 节点挂载的 ECharts 实例,可用于调用实例上的方法,注册事件,自适应等;

draw:用于绘制 ECharts 图表,本质是调用实例的 setOption 方法;

init:初始化,在此获取 DOM 节点,挂载实例,注册事件,并调用 draw 绘制图表。

Cannot read properties of undefined (reading 'type')

请注意,上述代码目前还不能正常运行,这里会遇到第一个坑 —— 图表无法显示,这是 React 中没有碰到的:

 出现这种问题是因为,我们使用 ref 接收了 echarts.init 的实例。这会导致 chartInstance 被代理成为响应式对象,影响了 ECharts 对内部属性的访问。Echarts 官方 FAQ 也阐述了该问题:

 

所以,我们有两种解决方法:

  1. 使用 shallowRef 替换 ref
  2. 使用 ref + markRaw

shallowRef 和 ref() 不同之处在于,浅层 ref 的内部值将会原样存储和暴露,并且不会被深层递归地转为响应式。只有对 .value 的访问是响应式的。

markRaw 则会将一个对象标记为不可被转为代理。返回该对象本身。在有些值不应该是响应式的场景中,例如复杂的第三方类实例或 Vue 组件对象,这很有用。

 我们这里使用 markRaw 对 init 进行包裹:

chartInstance.value = markRaw(
  echarts.init(
      chartRef.value,
      props.theme,
      { renderer: "canvas" }
  )
);

窗口防抖自适应

这里和 React 中就差不多了,主要安利一个 Vue 官方团队维护的 hooks 库:vueuse 。和 React 中的 ahooks 一样,封装了很多实用的 hooks,我们可以使用 useDebounceFn 来优化自适应函数:

import { useDebounceFn } from "@vueuse/core";

// 窗口自适应并开启过渡动画
const resize = () => {
  if (chartInstance.value) {
    chartInstance.value.resize({ animation: { duration: 300 } });
  }
};

// 自适应防抖优化
const debouncedResize = useDebounceFn(resize, 500, { maxWait: 800 });

onMounted(() => {
  window.addEventListener("resize", debouncedResize);
});

onBeforeUnmount(() => {
  window.removeEventListener("resize", debouncedResize);
});

额外监听宽高

目前,图标的大小还是写死的,现在我们支持 props 传递宽高来自定义图表大小:

interface Props {
  option: ECOption;
  theme?: Object | string;
  width: string;
  height: string;
}

<template>
  <div
    id="echart"
    ref="chartRef"
    :style="{ width: props.width, height: props.height }"
  />
</template>

请注意:在使用时,我们必须指定容器的宽高,否则无法显示,因为图表在绘制时会自动获取父容器的宽高。

flex/grid 布局下 resize 失效的问题

这个问题刚遇到着实有点蛋疼,摸了蛮久,而 bug 触发的条件也比较奇葩,但也比较常见:

  1. 在父组件中,复用多个 ECharts 组件;
  2. 使用了 flex 或 grid 这种没有明确给定宽高的布局;

此时会发现:当前窗口放大,正常触发 resize, 图表会随之放大。但是,此时再缩小窗口,虽然也会触发 resize,但是图表的大小却缩不回来了......

一开始还以为是我封装的写法有问题,直到搜到了ECharts 官方的 issues 才发现原来不止我一个遇到了

标签:option,--,props,value,ECharts,Vue3,import,chartInstance,echarts
From: https://www.cnblogs.com/smileZAZ/p/17491951.html

相关文章

  • 阶段性知识总结解释版【Day01-Day25】
    day021.什么是编程和编程语言编程 是指使用计算机语言编写计算机程序的过程。编程语言 是一种用于编写计算机程序的形式化语言,它可以被解释器或编译器转换成机器码以便计算机执行。编程语言包括C、Java、Python、JavaScript、PHP等。2.计算机五大组成部分,分别阐释一......
  • SPAD346C3必须由某个持有令牌的主站定时查看比自己高的站址是否有新的主站加入
    SPAD346C3必须由某个持有令牌的主站定时查看比自己高的站址是否有新的主站加入SPAD346C3必须由某个持有令牌的主站定时查看比自己高的站址是否有新的主站加入 假设一个网络中有2号站和10号站作为主站,(10号站的)最高地址设置为15。则对于2号站来说,所谓地址间隙就是3到9的范围;对......
  • PDD200A101用性以及实时性、可互操作性、可靠性、抗干扰性
    PDD200A101用性以及实时性、可互操作性、可靠性、抗干扰性PDD200A101用性以及实时性、可互操作性、可靠性、抗干扰性  工业以太网是应用于工业控制领域的以太网技术,在技术上与商用以太网(即IEEE802.3标准)兼容,但是实际产品和应用却又完全不同。这主要表现普通商用以太网的产......
  • 关于 SAP Commerce Cloud 本地安装用 root user 执行安装脚本的问题
    在linuxserver上执行./install-rb2c_acc是不是不能用rootuser去做?遇到警告消息:Errorcreatingbeanwithname'defaultSolrServerService'definedinclasspathresource[global-solrserver-spring.xml]:Invocationofinitmethodfailed;nestedexceptionisde.hy......
  • 核技巧与再生核希尔伯特空间
    核技巧使用核函数直接计算两个向量映射到高维后的内积,从而避免了高维映射这一步。本文用矩阵的概念介绍核函数$K(x,y)$的充分必要条件:对称(半)正定。对称正定看起来像是矩阵的条件。实际上,对于函数$K(x,y):\R^n\times\R^m\rightarrow\R$,将向量$x\in\R^n$的所有实数取值......
  • 阶段性知识总结习题版【Day01-Day25】
    day02什么是编程和编程语言计算机五大组成部分,分别阐释一下各自特点计算机三大核心硬件,各自的特点常见的操作系统day03计算机存储数据的单位有哪些,之间的单位换算是怎样的编程语言的发展史,分别有什么特点编程语言的分类python解释器的版本有哪些,推荐使用的版本是哪个......
  • 什么是 SAP Commerce Cloud 的 Flexible Search?
    SAPCommerceCloud的FlexibleSearch是一种强大而灵活的查询语言和工具,用于在SAPCommerceCloud平台上执行复杂的数据库查询操作。它提供了一种高度可定制的方式来检索和操作存储在CommerceCloud数据库中的数据。FlexibleSearch可以用于在产品、订单、用户等对象之间进行联接......
  • python3 subprocess.getoutput(cmd) 执行linux命令进入交互模式后一直卡住了
    进入交互模式是我们预期之外的,记录一下。进入交互之后linux一直等待你的输入,所有subprocess.getoutput()就一直卡着呢~,我们加入timeout通过学习subprocess中支持timeout有:getoutput并不支持timeout参数尝试了callcheck_allcheck_output这几个方法之后并不能解决Linux交......
  • 单值二叉树
    如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。只有给定的树是单值二叉树时,才返回 true;否则返回false。示例1:输入:[1,1,1,1,1,null,1]输出:true示例2:输入:[2,2,2,5,2]输出:false来源:力扣(LeetCode)链接:https://leetcode.cn/problems/univalued-binary-t......
  • Angular 应用里 NullInjectorError - No provider for XX 错误的一个场景和分析过程
    最近处理客户incident,有个客户从Spartacus4升级到5.2之后,启动Storefront,console遇到了一个错误消息:NullInjectorError-NoproviderforAnonymousConsentTemplatesAdapter!引起这个错误消息的场景有很多,这个incident最后的场景是:以前的module通过loadedfor......