源代码

import type { EChartsOption } from 'echarts';import type { Ref } from 'vue';import type { Nullable } from '@vben/types';import type EchartsUI from './echarts-ui.vue';import { computed, nextTick, watch } from 'vue';import { usePreferences } from '@vben/preferences';import {tryOnUnmounted,useDebounceFn,useResizeObserver,useTimeoutFn,useWindowSize,
} from '@vueuse/core';import echarts from './echarts';type EchartsUIType = typeof EchartsUI | undefined;type EchartsThemeType = 'dark' | 'light' | null;function useEcharts(chartRef: Ref<EchartsUIType>) {let chartInstance: echarts.ECharts | null = null;let cacheOptions: EChartsOption = {};const { isDark } = usePreferences();const { height, width } = useWindowSize();const resizeHandler: () => void = useDebounceFn(resize, 200);const getOptions = computed((): EChartsOption => {if (!isDark.value) {return {};}return {backgroundColor: 'transparent',};});const initCharts = (t?: EchartsThemeType) => {const el = chartRef?.value?.$el;if (!el) {return;}chartInstance = echarts.init(el, t || isDark.value ? 'dark' : null);return chartInstance;};const renderEcharts = (options: EChartsOption,clear = true,): Promise<Nullable<echarts.ECharts>> => {cacheOptions = options;const currentOptions = {...options,...getOptions.value,};return new Promise((resolve) => {if (chartRef.value?.offsetHeight === 0) {useTimeoutFn(async () => {resolve(await renderEcharts(currentOptions));}, 30);return;}nextTick(() => {useTimeoutFn(() => {if (!chartInstance) {const instance = initCharts();if (!instance) return;}clear && chartInstance?.clear();chartInstance?.setOption(currentOptions);resolve(chartInstance);}, 30);});});};function resize() {chartInstance?.resize({animation: {duration: 300,easing: 'quadraticIn',},});}watch([width, height], () => {resizeHandler?.();});useResizeObserver(chartRef as never, resizeHandler);watch(isDark, () => {if (chartInstance) {chartInstance.dispose();initCharts();renderEcharts(cacheOptions);resize();}});tryOnUnmounted(() => {// 销毁实例,释放资源chartInstance?.dispose();});return {renderEcharts,resize,getChartInstance: () => chartInstance,};
}export { useEcharts };export type { EchartsUIType };

这段 TypeScript 代码定义了一个名为 useEcharts 的自定义钩子函数,用于在 Vue 项目中集成和管理 ECharts 图表。下面是对代码详细的解释:

导入模块

import type { EChartsOption } from 'echarts'; // 导入 ECharts 选项类型
import type { Ref } from 'vue'; // 导入 Vue 的 Ref 类型
import type { Nullable } from '@vben/types'; // 导入可空类型
import type EchartsUI from './echarts-ui.vue'; // 导入 EchartsUI 组件类型import { computed, nextTick, watch } from 'vue'; // 导入 Vue 的计算属性、下一个 DOM 更新周期方法和监听器
import { usePreferences } from '@vben/preferences'; // 导入偏好设置钩子
import {tryOnUnmounted,useDebounceFn,useResizeObserver,useTimeoutFn,useWindowSize,
} from '@vueuse/core'; // 导入 VueUse 核心库的一些钩子
import echarts from './echarts'; // 导入 ECharts 库
  • 类型导入:从不同的库中导入了所需的类型,包括 ECharts 选项类型、Vue 的 Ref 类型、可空类型以及 EchartsUI 组件类型。
  • 功能导入:从 vue 中导入了 computednextTickwatch 等功能,从 @vben/preferences 中导入了偏好设置钩子,从 @vueuse/core 中导入了一些实用的钩子,最后导入了 ECharts 库。

类型定义

type EchartsUIType = typeof EchartsUI | undefined; // 定义 EchartsUI 组件类型
type EchartsThemeType = 'dark' | 'light' | null; // 定义 ECharts 主题类型
  • EchartsUIType:表示 EchartsUI 组件类型,可能为 undefined
  • EchartsThemeType:表示 ECharts 的主题类型,有 'dark''light'null 三种可能。

useEcharts 函数

function useEcharts(chartRef: Ref<EchartsUIType>) {let chartInstance: echarts.ECharts | null = null; // 初始化 ECharts 实例let cacheOptions: EChartsOption = {}; // 初始化缓存的 ECharts 选项const { isDark } = usePreferences(); // 获取是否为深色模式const { height, width } = useWindowSize(); // 获取窗口的高度和宽度const resizeHandler: () => void = useDebounceFn(resize, 200); // 创建防抖的 resize 处理函数const getOptions = computed((): EChartsOption => {if (!isDark.value) {return {};}return {backgroundColor: 'transparent',};}); // 计算根据深色模式的 ECharts 选项
  • 变量初始化
    • chartInstance:用于存储 ECharts 实例,初始值为 null
    • cacheOptions:用于缓存 ECharts 选项,初始值为空对象。
  • 状态获取
    • isDark:通过 usePreferences 钩子获取当前是否为深色模式。
    • heightwidth:通过 useWindowSize 钩子获取窗口的高度和宽度。
  • 防抖处理:使用 useDebounceFn 创建一个防抖的 resize 处理函数,防抖时间为 200 毫秒。
  • 计算属性getOptions 是一个计算属性,根据 isDark 的值返回不同的 ECharts 选项。如果是深色模式,返回一个包含透明背景色的选项;否则返回空对象。

初始化 ECharts 实例

  const initCharts = (t?: EchartsThemeType) => {const el = chartRef?.value?.$el;if (!el) {return;}chartInstance = echarts.init(el, t || isDark.value ? 'dark' : null);return chartInstance;}; // 初始化 ECharts 实例
  • initCharts 函数用于初始化 ECharts 实例。它首先获取 chartRef 对应的 DOM 元素,如果元素不存在则直接返回。然后使用 echarts.init 方法初始化 ECharts 实例,并根据传入的主题或当前的深色模式设置主题。最后返回初始化后的实例。

渲染 ECharts 图表

  const renderEcharts = (options: EChartsOption,clear = true,): Promise<Nullable<echarts.ECharts>> => {cacheOptions = options;const currentOptions = {...options,...getOptions.value,};return new Promise((resolve) => {if (chartRef.value?.offsetHeight === 0) {useTimeoutFn(async () => {resolve(await renderEcharts(currentOptions));}, 30);return;}nextTick(() => {useTimeoutFn(() => {if (!chartInstance) {const instance = initCharts();if (!instance) return;}clear && chartInstance?.clear();chartInstance?.setOption(currentOptions);resolve(chartInstance);}, 30);});});}; // 渲染 ECharts 图表
  • renderEcharts 函数用于渲染 ECharts 图表。它接收两个参数:options 表示要渲染的 ECharts 选项,clear 表示是否清除之前的图表内容,默认为 true
  • 函数首先将传入的 options 缓存到 cacheOptions 中,然后合并 optionsgetOptions 的值得到 currentOptions
  • 如果 chartRef 的高度为 0,说明图表容器还未完全渲染,使用 useTimeoutFn 延迟 30 毫秒后再次调用 renderEcharts 函数。
  • 否则,在 nextTick 中使用 useTimeoutFn 延迟 30 毫秒后进行图表的渲染。如果 chartInstance 不存在,则调用 initCharts 函数初始化实例。然后根据 clear 的值决定是否清除之前的图表内容,并使用 setOption 方法设置新的选项。最后通过 resolve 返回 chartInstance

调整 ECharts 图表大小

  function resize() {chartInstance?.resize({animation: {duration: 300,easing: 'quadraticIn',},});} // 调整 ECharts 图表大小
  • resize 函数用于调整 ECharts 图表的大小。它调用 chartInstanceresize 方法,并设置了一个动画效果,动画持续时间为 300 毫秒,缓动函数为 'quadraticIn'

监听事件

  watch([width, height], () => {resizeHandler?.();}); // 监听窗口大小变化,调用 resize 处理函数useResizeObserver(chartRef as never, resizeHandler); // 监听图表容器大小变化,调用 resize 处理函数watch(isDark, () => {if (chartInstance) {chartInstance.dispose();initCharts();renderEcharts(cacheOptions);resize();}}); // 监听深色模式变化,重新初始化和渲染图表
  • 窗口大小监听:使用 watch 监听 widthheight 的变化,当窗口大小改变时,调用防抖的 resizeHandler 函数。
  • 容器大小监听:使用 useResizeObserver 监听 chartRef 对应的 DOM 元素的大小变化,当容器大小改变时,调用 resizeHandler 函数。
  • 深色模式监听:使用 watch 监听 isDark 的变化,当深色模式改变时,销毁当前的 chartInstance,重新初始化 ECharts 实例,渲染缓存的选项,并调整图表大小。

组件卸载处理

  tryOnUnmounted(() => {// 销毁实例,释放资源chartInstance?.dispose();}); // 在组件卸载时销毁 ECharts 实例
  • 使用 tryOnUnmounted 钩子,在组件卸载时销毁 chartInstance,释放资源。

导出

  return {renderEcharts,resize,getChartInstance: () => chartInstance,};
}export { useEcharts }; // 导出 useEcharts 钩子
export type { EchartsUIType }; // 导出 EchartsUIType 类型
  • useEcharts 函数返回一个对象,包含 renderEchartsresizegetChartInstance 三个方法。
  • 最后导出 useEcharts 钩子和 EchartsUIType 类型,供其他组件使用。

🎉 综上所述,这段代码通过自定义钩子 useEcharts 封装了 ECharts 的初始化、渲染、大小调整和主题切换等功能,方便在 Vue 项目中使用 ECharts 图表。同时,通过监听窗口和容器大小变化以及深色模式的改变,实现了图表的自适应和动态更新。

第一章 代码整体概述

1.1 代码功能简介

1.1.1 代码核心功能

此代码定义了一个名为 useEcharts 的自定义钩子,这个钩子就像是一个神奇的小助手🧙‍♂️,专门用于在 Vue 项目中管理 ECharts 图表的各种操作:

  • 初始化:就像为一场演出搭建舞台一样,它会为 ECharts 图表准备好初始的环境和设置,让图表能够顺利“登场”。
  • 渲染:把数据转化为直观的图表,就如同画家把颜料变成美丽的画作🎨,让用户能够清晰地看到数据的展示效果。
  • 调整大小:当页面大小发生变化时,它能像一个灵活的舞者一样,自动调整图表的大小,保证图表在不同的屏幕尺寸下都能完美呈现。
  • 深色模式适配:随着用户在浅色和深色模式之间切换,它能像一个智能的调光师一样,让图表的颜色和样式也随之改变,提供更好的视觉体验🌙。
1.1.2 代码使用场景

这个代码适用于需要在 Vue 组件中集成 ECharts 图表,并且有以下需求的场景:

  • 响应式调整图表大小:比如在不同尺寸的设备上浏览网页,或者用户手动调整浏览器窗口大小时,图表能够自适应调整大小,始终保持良好的显示效果📱💻。
  • 支持深色模式切换:现在很多应用都提供了深色模式,当用户切换到深色模式时,图表也能相应地调整颜色和样式,避免在深色背景下看不清图表内容🌃。

1.2 代码结构概述

1.2.1 导入模块

代码中导入了各种模块,这些模块就像是不同的工具,共同协作完成代码的功能:

  • ECharts 相关类型:这些类型就像是说明书,告诉代码如何正确地使用 ECharts 的各种功能和数据结构📖。
  • Vue 相关模块:为代码提供了 Vue 框架的支持,让代码能够与 Vue 组件完美结合,实现数据的响应式更新和组件的生命周期管理🖥️。
  • 自定义偏好设置钩子:可以根据用户的个性化设置,对图表进行相应的调整,比如用户可能有自己喜欢的图表颜色、字体等🎨。
  • VueUse 核心库的钩子:VueUse 是一个非常实用的工具库,其钩子可以帮助代码更方便地实现一些常见的功能,比如监听窗口大小变化等🕵️‍♂️。
1.2.2 类型定义

定义了 EchartsUITypeEchartsThemeType 类型,它们的作用和用途如下:

  • EchartsUIType:就像是一个分类标签🏷️,用于对 ECharts 图表的 UI 样式进行分类和定义,让代码能够更清晰地管理和使用不同的 UI 样式。
  • EchartsThemeType:类似于一个主题模板🎨,用于定义 ECharts 图表的主题,比如浅色主题、深色主题等,方便在不同的主题之间进行切换。
1.2.3 钩子函数主体

useEcharts 函数的整体结构和主要逻辑流程就像是一场精心策划的演出🎭:

  • 初始化阶段:准备好各种必要的参数和设置,就像演员们在后台化妆、换装,为演出做好准备。
  • 渲染阶段:根据传入的数据和设置,将图表渲染到页面上,就像演员们在舞台上精彩表演,展示出最终的效果。
  • 监听阶段:持续监听页面大小变化和深色模式切换等事件,一旦有变化就及时调整图表,就像舞台工作人员时刻关注着舞台的情况,及时调整灯光、道具等。
1.2.4 导出内容

导出的 useEcharts 钩子和 EchartsUIType 类型有着重要的作用:

  • useEcharts 钩子:就像是一个可以复用的工具包🛠️,其他 Vue 组件可以通过导入这个钩子,轻松地在自己的组件中集成 ECharts 图表,并使用其提供的各种功能。
  • EchartsUIType 类型:为其他代码提供了一个统一的 UI 样式分类标准,方便不同的组件在使用 ECharts 图表时,能够遵循相同的 UI 规范,保持整体的一致性👔。

第二章 导入模块详解

2.1 ECharts 相关导入

2.1.1 EChartsOption 类型导入

1. 作用解释

EChartsOption 类型就像是一份严格的“设计蓝图”🎨,它是 ECharts 配置选项的类型定义。在我们使用 ECharts 绘制图表时,需要传入一个配置对象来告诉 ECharts 我们想要绘制什么样的图表,比如图表的类型(柱状图、折线图等)、数据内容、样式设置等。而 EChartsOption 类型的存在,就是为了规范这个传入的配置对象。

它可以帮助我们在编写代码时,提前发现配置对象中可能存在的错误,比如属性名拼写错误、属性类型不匹配等。就好比在建造房子之前,先有一份详细准确的蓝图,这样在施工过程中就能避免很多不必要的错误和麻烦。

例如,在 TypeScript 中使用 ECharts 时,如果我们定义一个配置对象并指定其类型为 EChartsOption

import { EChartsOption } from 'echarts';const option: EChartsOption = {xAxis: {type: 'category',data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']},yAxis: {type: 'value'},series: [{data: [820, 932, 901, 934, 1290, 1330, 1320],type: 'line'}]
};

这样,当我们写错属性名或者属性类型不匹配时,编译器就会及时给我们报错提示。

2.1.2 echarts 库导入

1. 导入目的

导入 echarts 库就像是打开了一个功能强大的“工具箱”🧰,我们可以使用这个工具箱里的各种工具来完成 ECharts 的初始化、渲染等功能。

ECharts 库提供了一系列的方法和属性,让我们能够方便地创建和操作图表。比如,我们可以使用 echarts.init 方法来初始化一个 ECharts 实例,然后使用 setOption 方法将配置对象应用到这个实例上,从而实现图表的渲染。

示例代码如下:

import * as echarts from 'echarts';// 初始化 ECharts 实例
const myChart = echarts.init(document.getElementById('main'));// 设置配置项并渲染图表
const option = {// 配置项内容
};
myChart.setOption(option);

通过导入 echarts 库,我们就可以利用这些功能轻松地在网页上绘制出各种精美的图表。

2.2 Vue 相关导入

2.2.2.1 Ref 类型导入

1. 作用解释

在 Vue 中,Ref 类型就像是一个“魔法盒子”🪄,用于创建响应式引用。它可以让我们在代码中方便地引用某个值,并且当这个值发生变化时,与之关联的 DOM 元素或者其他依赖项会自动更新。

在我们的代码中,Ref 类型主要用于引用 EchartsUI 组件。通过 Ref,我们可以获取到 EchartsUI 组件的实例,进而对其进行操作。

例如:

<template><div><EchartsUI ref="echartsRef" /></div>
</template><script lang="ts" setup>
import { ref } from 'vue';
import EchartsUI from './EchartsUI.vue';// 创建一个 Ref 引用
const echartsRef = ref<InstanceType<typeof EchartsUI>>();// 可以在需要的时候使用 echartsRef 来访问 EchartsUI 组件的实例
</script>

这样,我们就可以通过 echartsRef.value 来访问 EchartsUI 组件的实例,调用其方法或者获取其属性。

2.2.2 computednextTickwatch 导入

1. computed 的作用

computed 就像是一个“智能计算器”🧮,用于创建计算属性。计算属性是根据其他数据动态计算得出的属性,它会根据依赖的数据自动更新。

当我们有一些数据需要根据其他数据进行计算时,使用计算属性可以让代码更加简洁和易于维护。例如:

<template><div><p>原始数据: {{ num }}</p><p>计算结果: {{ doubleNum }}</p></div>
</template><script lang="ts" setup>
import { ref, computed } from 'vue';const num = ref(10);// 创建计算属性
const doubleNum = computed(() => num.value * 2);
</script>

在这个例子中,doubleNum 就是一个计算属性,它的值会根据 num 的变化而自动更新。

2. nextTick 的作用

nextTick 就像是一个“时间旅行者”🕵️‍♂️,用于在 DOM 更新后执行回调。在 Vue 中,数据的更新是异步的,当我们修改数据后,DOM 不会立即更新。而 nextTick 可以让我们在 DOM 更新完成后再执行一些操作。

例如,当我们需要获取更新后的 DOM 元素的尺寸或者位置时,就可以使用 nextTick

<template><div><button @click="updateData">更新数据</button><p>{{ message }}</p></div>
</template><script lang="ts" setup>
import { ref, nextTick } from 'vue';const message = ref('原始消息');const updateData = async () => {// 修改数据message.value = '更新后的消息';// 在 DOM 更新后执行回调await nextTick();// 这里可以获取更新后的 DOM 元素console.log('DOM 已更新');
};
</script>

这样,我们就可以确保在 DOM 更新完成后再执行相应的操作。

3. watch 的作用

watch 就像是一个“监控摄像头”📹,用于监听数据变化并执行相应操作。当我们需要在某个数据发生变化时执行一些特定的逻辑时,就可以使用 watch

例如:

<template><div><input v-model="inputValue" /></div>
</template><script lang="ts" setup>
import { ref, watch } from 'vue';const inputValue = ref('');// 监听 inputValue 的变化
watch(inputValue, (newValue, oldValue) => {console.log(`输入的值从 ${oldValue} 变为 ${newValue}`);
});
</script>

在这个例子中,当 inputValue 的值发生变化时,watch 会自动触发回调函数,我们可以在回调函数中执行相应的操作。

2.3 自定义模块导入

2.3.1 usePreferences 导入

1. 作用解释

usePreferences 钩子就像是一个“个人秘书”📋,用于获取用户的偏好设置。在我们的代码中,主要用于判断用户是否选择了深色模式。

用户的偏好设置可能包括主题模式、字体大小、语言等,通过 usePreferences 钩子,我们可以方便地获取这些设置,并根据用户的偏好来调整页面的显示效果。

例如:

<template><div :class="{ 'dark-mode': isDarkMode }"><!-- 页面内容 --></div>
</template><script lang="ts" setup>
import { usePreferences } from './usePreferences';// 获取用户偏好设置
const { isDarkMode } = usePreferences();
</script>

这样,我们就可以根据 isDarkMode 的值来动态添加或移除 dark-mode 类,从而实现深色模式的切换。

2.3.2 EchartsUI 组件导入

1. 导入目的

导入 EchartsUI 组件就像是为图表找到了一个“家”🏠,其目的是为了获取图表容器的 DOM 元素。

EchartsUI 组件通常是一个包含图表容器的组件,我们通过导入这个组件并在页面中使用它,就可以获取到这个容器的 DOM 元素,然后在这个容器中初始化和渲染 ECharts 图表。

例如:

<template><div><EchartsUI ref="chartContainer" /></div>
</template><script lang="ts" setup>
import { ref } from 'vue';
import EchartsUI from './EchartsUI.vue';// 创建一个 Ref 引用
const chartContainer = ref<HTMLElement>();// 在需要的时候可以使用 chartContainer.value 来访问图表容器的 DOM 元素
</script>

这样,我们就可以通过 chartContainer.value 来获取图表容器的 DOM 元素,进而在这个元素上初始化 ECharts 实例。

2.4 VueUse 核心库导入

2.4.1 tryOnUnmounted 导入

1. 作用解释

tryOnUnmounted 就像是一个“清洁工”🧹,用于在组件卸载时执行清理操作。在我们的代码中,主要用于销毁 ECharts 实例。

当一个组件被卸载时,如果不及时清理一些资源,可能会导致内存泄漏等问题。而 tryOnUnmounted 可以确保在组件卸载时,我们能够执行一些必要的清理操作,比如销毁 ECharts 实例。

例如:

<template><div><EchartsUI ref="echartsRef" /></div>
</template><script lang="ts" setup>
import { ref } from 'vue';
import { tryOnUnmounted } from '@vueuse/core';
import EchartsUI from './EchartsUI.vue';const echartsRef = ref<InstanceType<typeof EchartsUI>>();// 在组件卸载时销毁 ECharts 实例
tryOnUnmounted(() => {if (echartsRef.value) {// 销毁 ECharts 实例的逻辑}
});
</script>

这样,当组件被卸载时,就会自动执行销毁 ECharts 实例的操作,避免资源的浪费。

2.4.2 useDebounceFn 导入

1. 用途说明

useDebounceFn 就像是一个“节流阀”🚥,通过防抖处理减少 resize 函数的调用频率,提高性能。

当我们监听元素的大小变化时,比如窗口大小变化或者图表容器大小变化,resize 事件可能会频繁触发。如果每次触发都执行 resize 函数,会导致性能问题。而 useDebounceFn 可以让 resize 函数在一段时间内只执行一次,避免不必要的性能开销。

例如:

<template><div><EchartsUI ref="echartsRef" /></div>
</template><script lang="ts" setup>
import { ref } from 'vue';
import { useDebounceFn } from '@vueuse/core';
import EchartsUI from './EchartsUI.vue';const echartsRef = ref<InstanceType<typeof EchartsUI>>();// 定义 resize 函数
const handleResize = () => {if (echartsRef.value) {// 执行图表的 resize 操作}
};// 使用防抖处理
const debouncedResize = useDebounceFn(handleResize, 300);// 在需要监听大小变化的地方调用 debouncedResize
</script>

在这个例子中,useDebounceFn 会让 handleResize 函数在 300 毫秒内只执行一次,从而减少了函数的调用频率,提高了性能。

2.4.3 useResizeObserver 导入

1. 作用解释

useResizeObserver 就像是一个“尺寸侦探”🕵️,用于监听元素大小变化。在我们的代码中,主要用于监听图表容器的大小变化并调用 resize 函数。

当图表容器的大小发生变化时,我们需要及时调整图表的大小,以保证图表能够正确显示。useResizeObserver 可以帮助我们实时监测图表容器的大小变化,一旦发生变化,就会触发相应的回调函数,我们可以在回调函数中调用 resize 函数来调整图表的大小。

例如:

<template><div><EchartsUI ref="echartsRef" /></div>
</template><script lang="ts" setup>
import { ref } from 'vue';
import { useResizeObserver } from '@vueuse/core';
import EchartsUI from './EchartsUI.vue';const echartsRef = ref<InstanceType<typeof EchartsUI>>();// 监听图表容器的大小变化
useResizeObserver(echartsRef, () => {if (echartsRef.value) {// 调用 resize 函数调整图表大小}
});
</script>

这样,当图表容器的大小发生变化时,就会自动调用 resize 函数来调整图表的大小,保证图表的显示效果。

2.4.4 useTimeoutFn 导入

1. 用途说明

useTimeoutFn 就像是一个“定时闹钟”⏰,用于在指定时间后执行回调函数。在代码中用于处理图表渲染时的延迟操作。

有时候,我们需要在图表渲染之前或者之后执行一些延迟操作,比如等待数据加载完成后再渲染图表,或者在图表渲染完成后执行一些动画效果。useTimeoutFn 可以帮助我们实现这些延迟操作。

例如:

<template><div><EchartsUI ref="echartsRef" /></div>
</template><script lang="ts" setup>
import { ref } from 'vue';
import { useTimeoutFn } from '@vueuse/core';
import EchartsUI from './EchartsUI.vue';const echartsRef = ref<InstanceType<typeof EchartsUI>>();// 在 1000 毫秒后执行回调函数
const { start } = useTimeoutFn(() => {if (echartsRef.value) {// 执行图表渲染的逻辑}
}, 1000);// 可以在需要的时候调用 start 方法开始计时
start();
</script>

这样,就可以在 1000 毫秒后执行图表渲染的逻辑,实现延迟操作。

2.4.5 useWindowSize 导入

1. 作用解释

useWindowSize 就像是一个“窗口测量员”📏,用于获取窗口的高度和宽度,以便在窗口大小变化时调整图表大小。

当窗口大小发生变化时,图表的大小也需要相应地调整,以保证图表能够适应不同的窗口尺寸。useWindowSize 可以实时获取窗口的高度和宽度,我们可以根据这些信息来动态调整图表的大小。

例如:

<template><div><EchartsUI ref="echartsRef" /></div>
</template><script lang="ts" setup>
import { ref } from 'vue';
import { useWindowSize } from '@vueuse/core';
import EchartsUI from './EchartsUI.vue';const echartsRef = ref<InstanceType<typeof EchartsUI>>();// 获取窗口的高度和宽度
const { width, height } = useWindowSize();// 监听窗口大小变化,调整图表大小
watch([width, height], () => {if (echartsRef.value) {// 根据窗口大小调整图表大小的逻辑}
});
</script>

这样,当窗口大小发生变化时,就可以根据新的窗口高度和宽度来调整图表的大小,保证图表的显示效果。

第三章 类型定义详解

3.1 EchartsUIType 类型

3.1.1 类型定义

EchartsUIType 被定义为 typeof EchartsUI | undefined ,这到底是什么意思呢🤔?

  • typeof EchartsUI:这里的 typeof 是一个操作符,它会返回 EchartsUI 的类型。也就是说,它代表的是 EchartsUI 这个组件本身所具有的类型。想象一下,EchartsUI 就像是一个独特的“物品”,而 typeof EchartsUI 就是描述这个“物品”特征的标签🏷️。
  • | undefined:这个 | 符号在类型定义里表示“或”的关系。undefined 是 JavaScript 中的一个原始值,表示变量已声明但未赋值,或者函数没有返回值。所以 | undefined 意味着 EchartsUIType 除了可以是 EchartsUI 的类型,还可以是未定义的情况。就好比一个盒子,里面要么装着 EchartsUI 这个“物品”,要么就是空的(未定义)🎁。

综上所述,EchartsUIType 表示的就是 EchartsUI 组件的类型或者未定义的情况。

3.1.2 用途

这个类型在代码中主要用于 chartRef 的类型定义,这是为什么呢😉?

在 React 等框架中,ref 是一种用来引用 DOM 节点或者组件实例的方式。chartRef 就是用来引用 EchartsUI 组件的一个引用对象。通过将 chartRef 的类型定义为 EchartsUIType,可以确保我们引用的是 EchartsUI 组件。

举个例子,如果我们不小心把 chartRef 引用到了其他类型的组件或者变量上,由于类型不匹配,编译器就会发出警告⚠️,这样就能避免一些潜在的错误。就好像我们给一个特定的“停车位”(chartRef)设置了只能停放“EchartsUI 汽车”的规则,一旦有其他“车辆”试图停进去,就会被阻止🚗🚫。

3.2 EchartsThemeType 类型

3.2.1 类型定义

EchartsThemeType 被定义为 'dark' | 'light' | null ,下面来详细解释一下🧐。

  • 'dark''light':ECharts 是一个强大的可视化库,它支持不同的主题,其中 'dark' 代表深色主题,'light' 代表浅色主题。这就好比我们可以给一幅画选择不同的背景颜色,深色背景会让画面显得神秘、沉稳,浅色背景则会让画面更加明亮、清新🌈。
  • null:在 JavaScript 中,null 表示一个空对象指针。在这里,null 表示不指定任何主题。就好像我们选择不给画设置背景颜色,让它保持默认的样子🖼️。

所以,EchartsThemeType 表示的就是 ECharts 支持的主题类型。

3.2.2 用途

这个类型在代码中的主要使用场景是在 initCharts 函数中指定 ECharts 实例的主题。

initCharts 函数的作用是初始化一个 ECharts 实例,在初始化的过程中,我们可以通过传入 EchartsThemeType 类型的参数来指定使用的主题。例如:

function initCharts(theme: EchartsThemeType) {// 初始化 ECharts 实例const myChart = echarts.init(dom, theme);// 其他初始化操作// ...
}

通过这种方式,我们可以根据不同的需求灵活地选择 ECharts 实例的主题。如果我们想要一个深色主题的图表,就可以调用 initCharts('dark');如果想要浅色主题,就调用 initCharts('light');如果不想指定主题,就调用 initCharts(null)。这样可以让我们的图表在不同的场景下都能呈现出最佳的视觉效果🌟。

第四章 useEcharts 钩子函数详解

4.1 变量初始化

4.1.1 chartInstance 变量

chartInstance 变量在 useEcharts 钩子函数中扮演着至关重要的角色😃。它的主要作用是存储 ECharts 实例。想象一下,ECharts 实例就像是一个功能强大的“魔法盒子”,里面包含了图表的各种属性和方法。通过将这个“魔法盒子”存储在 chartInstance 变量中,我们就可以在后续的代码里轻松地对图表进行各种操作,比如渲染图表,让它在页面上显示出来🎨;或者调整图表的大小,使它能够完美适配不同的屏幕尺寸📏。

4.1.2 cacheOptions 变量

cacheOptions 变量就像是一个“仓库”📦,它的用途是缓存传入的 ECharts 配置选项。在实际开发中,我们可能会根据不同的条件或者用户的操作来重新渲染图表。这时候,就可以从 cacheOptions 这个“仓库”里取出之前存储的配置选项,然后用这些选项来重新渲染图表,避免了重复传递配置选项的麻烦,提高了代码的效率和可维护性。

4.2 响应式数据获取

4.2.1 isDark 获取

通过 usePreferences 钩子来获取 isDark 变量,这就像是给我们的代码装上了一个“模式探测器”🕵️。isDark 变量用于判断当前是否处于深色模式。在不同的模式下,图表的显示效果可能会有所不同,比如在深色模式下,我们可能需要调整图表的背景颜色、字体颜色等配置,让图表在深色背景下也能清晰地显示出来。所以,获取 isDark 变量可以帮助我们根据当前的模式动态地调整图表的配置。

4.2.2 widthheight 获取

使用 useWindowSize 钩子来获取窗口的宽度和高度,就像是给我们的图表安装了一个“尺寸追踪器”📐。在现代的网页设计中,页面需要能够自适应不同的屏幕尺寸。当用户调整浏览器窗口的大小时,图表也需要相应地调整大小,以保证良好的用户体验。通过获取窗口的宽度和高度,我们可以监听窗口大小的变化,并在变化发生时调用相应的函数来调整图表的大小,让图表始终与窗口大小保持一致。

4.3 防抖处理

4.3.1 resizeHandler 函数

resizeHandler 函数是通过 useDebounceFnresize 函数进行防抖处理后的函数。想象一下,当用户频繁地调整窗口大小时,如果每次窗口大小发生微小的变化都立即调用 resize 函数来调整图表大小,那么会导致 resize 函数被频繁调用,这不仅会消耗大量的性能,还可能会让图表的调整效果变得不流畅。而 resizeHandler 函数就像是一个“缓冲器”🧽,它会在用户停止调整窗口大小一段时间后才调用 resize 函数,减少了 resize 函数的调用频率,提高了性能,让图表的调整更加平滑。

4.4 计算属性 getOptions

4.4.1 计算逻辑

getOptions 计算属性的计算逻辑就像是一个“智能转换器”🔄。它会根据 isDark 的值来返回不同的 ECharts 配置选项。当 isDarktrue,也就是处于深色模式时,它会将图表的背景颜色设置为透明,这样可以让图表更好地融入深色背景中。而当 isDarkfalse 时,它会返回默认的配置选项。

4.4.2 用途

这个计算属性在代码中的使用场景就像是一个“拼图块”🧩。它主要用于合并到最终的 ECharts 配置选项中。在渲染图表时,我们需要将各种配置选项组合在一起,而 getOptions 计算属性提供了根据不同模式动态生成的配置选项,将它合并到最终的配置中,就可以让图表根据当前的模式进行正确的渲染。

4.5 initCharts 函数

4.5.1 函数功能

initCharts 函数的主要功能是初始化 ECharts 实例,就像是给图表“搭建一个家”🏠。它会根据传入的主题类型或者当前的深色模式来设置图表的主题。不同的主题可以让图表呈现出不同的风格,比如明亮的风格或者深色的风格,以满足不同用户的需求。

4.5.2 实现细节

在函数内部,首先需要获取图表容器的 DOM 元素,这就像是找到图表“家”的具体位置📍。通常会使用 document.getElementById 或者 ref 等方式来获取 DOM 元素。然后,调用 echarts.init 方法,传入图表容器的 DOM 元素和主题类型,就可以初始化一个 ECharts 实例,将这个实例存储在 chartInstance 变量中,方便后续的操作。

4.6 renderEcharts 函数

4.6.1 函数功能

renderEcharts 函数的主要功能是渲染 ECharts 图表,就像是给图表“穿上漂亮的衣服”👗。它会处理一些特殊情况,比如图表容器高度为 0 的情况,这时候可能需要等待容器高度正常后再进行渲染。同时,它会在 DOM 更新后进行渲染操作,确保图表能够正确地显示在页面上。

4.6.2 实现细节

在函数内部,首先会合并配置选项,将 cacheOptionsgetOptions 等配置选项组合在一起,形成最终的配置。然后,会处理延迟渲染的情况,比如使用 nextTick 等方法确保在 DOM 更新后再进行渲染。接着,会清除之前的图表,避免出现重叠或者显示异常的问题。最后,调用 chartInstance.setOption 方法,将最终的配置选项设置到 ECharts 实例中,完成图表的渲染。

4.6.3 返回值

函数返回的 Promise 对象就像是一个“承诺使者”📜。它在图表渲染完成后返回 ECharts 实例。我们可以通过 then 方法来处理这个返回的实例,比如在图表渲染完成后进行一些额外的操作,如添加事件监听器等。

4.7 resize 函数

4.7.1 函数功能

resize 函数的作用是调整 ECharts 实例的大小,就像是给图表“量身定制衣服”🧵。它还设置了动画效果,让图表在调整大小时能够平滑地过渡,给用户带来更好的视觉体验。

4.7.2 实现细节

在函数内部,会调用 chartInstance.resize 方法,传入一些配置参数,如动画效果的配置等,来实现图表大小的调整。通过这个方法,ECharts 实例会根据新的大小重新计算和绘制图表,让图表适应新的尺寸。

4.8 监听器

4.8.1 窗口大小变化监听

watch([width, height], () => { resizeHandler?.(); }) 就像是一个“窗口变化哨兵”👮。当窗口的宽度或者高度发生变化时,它会触发回调函数,调用 resizeHandler 函数进行图表大小的调整。这样,无论用户如何调整窗口大小,图表都能及时地做出响应,保持良好的显示效果。

4.8.2 图表容器大小变化监听

useResizeObserver(chartRef as never, resizeHandler) 就像是一个“容器变化侦探”🕵️‍♂️。它会监听图表容器的大小变化,当容器的大小发生改变时,会调用 resizeHandler 函数进行图表大小的调整。这对于一些动态改变容器大小的场景非常有用,比如在页面布局发生变化时,图表能够自动调整大小。

4.8.3 深色模式变化监听

watch(isDark, () => { ... }) 就像是一个“模式变化警报器”🚨。当深色模式发生变化时,它会触发回调函数。在回调函数中,会销毁当前的 ECharts 实例,就像是拆除旧的“房子”,然后重新初始化并渲染图表,给图表换上适应新模式的“衣服”,让图表在不同的模式下都能正常显示。

4.9 组件卸载处理

4.9.1 tryOnUnmounted 函数

tryOnUnmounted 函数的作用是在组件卸载时销毁 ECharts 实例,就像是在离开“房子”时关闭所有的电器设备,释放资源⚡。如果不销毁 ECharts 实例,它会一直占用内存,可能会导致内存泄漏,影响页面的性能。通过在组件卸载时销毁实例,可以避免这种问题,让页面更加稳定和高效。

4.10 返回值

4.10.1 返回对象的属性

返回对象中包含了 renderEchartsresizegetChartInstance 方法。

  • renderEcharts 方法就像是一个“渲染大师”🎨,用于渲染图表,将配置选项应用到图表上,让图表显示在页面上。
  • resize 方法就像是一个“尺寸调整师”📏,用于调整图表的大小,让图表适应不同的屏幕尺寸。
  • getChartInstance 方法就像是一个“实例获取员”👨‍🔬,用于获取 ECharts 实例,方便在其他地方对图表进行进一步的操作。通过返回这些方法,外部组件可以方便地使用 useEcharts 钩子提供的功能,实现图表的渲染、调整等操作。

第五章 导出内容详解

5.1 useEcharts 钩子导出

5.1.1 导出目的

在开发 Vue 项目时,我们经常会使用 ECharts 库来创建各种精美的图表。为了更方便地在不同的 Vue 组件中管理和使用 ECharts 图表,我们将 useEcharts 钩子导出。这个钩子封装了与 ECharts 相关的一些通用逻辑,比如图表的初始化、数据更新、事件绑定等。通过导出这个钩子,其他 Vue 组件可以直接引入并使用它,避免了在每个组件中重复编写相同的 ECharts 管理代码,提高了代码的复用性和可维护性😎。

5.1.2 使用方式

以下是在其他组件中使用 useEcharts 钩子的详细步骤:

  1. 引入钩子
    在需要使用 useEcharts 钩子的 Vue 组件中,首先要引入它。假设 useEcharts 钩子定义在 hooks/useEcharts.js 文件中,引入代码如下:
import { useEcharts } from '@/hooks/useEcharts';
  1. 在组件中调用
    在组件的 setup 函数中调用 useEcharts 钩子,并根据需要进行配置。示例代码如下:
<template><div ref="chartRef" style="width: 600px; height: 400px;"></div>
</template><script setup>
import { ref } from 'vue';
import { useEcharts } from '@/hooks/useEcharts';// 创建一个 ref 用于引用图表容器
const chartRef = ref(null);// 调用 useEcharts 钩子
const { initChart } = useEcharts(chartRef);// 初始化图表
initChart({xAxis: {type: 'category',data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']},yAxis: {type: 'value'},series: [{data: [120, 200, 150, 80, 70, 110, 130],type: 'bar'}]
});
</script>

在上述代码中,我们首先创建了一个 chartRef 用于引用图表的容器元素。然后调用 useEcharts 钩子,并传入 chartRef。最后,调用 initChart 方法并传入 ECharts 的配置项来初始化图表🎉。

5.2 EchartsUIType 类型导出

5.2.2 使用方式

5.2.1 导出目的

在 TypeScript 项目中,类型定义非常重要,它可以帮助我们在开发过程中更早地发现类型错误,提高代码的健壮性。EchartsUIType 类型是对 ECharts 相关 UI 元素的类型定义,比如图表的配置项、样式等。通过导出 EchartsUIType 类型,其他模块可以直接引用这个类型,确保在使用 ECharts 相关数据时类型的一致性和准确性🧐。

5.2.2 使用方式

以下是在其他模块中使用 EchartsUIType 类型的详细步骤:

  1. 引入类型
    在需要使用 EchartsUIType 类型的模块中,首先要引入它。假设 EchartsUIType 类型定义在 types/EchartsUIType.ts 文件中,引入代码如下:
import { EchartsUIType } from '@/types/EchartsUIType';
  1. 在类型注解中引用该类型
    在代码中需要使用 ECharts 相关数据的地方,可以使用 EchartsUIType 类型进行类型注解。示例代码如下:
import { EchartsUIType } from '@/types/EchartsUIType';function updateChartConfig(config: EchartsUIType): void {// 在这里可以对图表配置进行更新操作console.log('Updating chart config:', config);
}const chartConfig: EchartsUIType = {xAxis: {type: 'category',data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']},yAxis: {type: 'value'},series: [{data: [120, 200, 150, 80, 70, 110, 130],type: 'bar'}]
};updateChartConfig(chartConfig);

在上述代码中,我们定义了一个 updateChartConfig 函数,它接受一个 EchartsUIType 类型的参数。然后创建了一个 chartConfig 对象,并将其类型注解为 EchartsUIType。最后调用 updateChartConfig 函数并传入 chartConfig,这样可以确保传入的参数类型符合要求😃。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/913703.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/913703.shtml
英文地址,请注明出处:http://en.pswp.cn/news/913703.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

报错 400 和405解决方案

今天出了好多这个错误&#xff0c;Uncaught (in promise) AxiosError {message: Request failed with status code 400 , name: AxiosError , code: ERR_BAD_REQUEST , config: {…}, request: XMLHttpRequest, …}反正就是前后端的参数不匹配&#xff0c;要不就是请求方式不…

Java源码的前端编译

Java源码的前端编译 欢迎来到我的博客&#xff1a;TWind的博客 我的CSDN:&#xff1a;Thanwind-CSDN博客 我的掘金&#xff1a;Thanwinde 的个人主页 0.前言 当一份Java代码写好时&#xff0c;将其进行编译&#xff0c;运行&#xff0c;并不是简单把这个Java源码从头到尾执行…

JWT6报错误 kid empty unable to lookup correct key

JWT5和jwt6在加密和解密和时候还明些区别的 &#xff0c;在5中&#xff0c;是不需要这个kid的&#xff0c;加解都不需要。但6中是需要这个keyId。 所以在使用的时候要做个区别&#xff0c;参考下面链接&#xff1a; ThinkPhp5.0.24 JWT报错 ‘“kid“ empty, unable to lookup…

高效学习之一篇搞定分布式管理系统Git !

一、Git是什么1&#xff0e;Git是目前世界上最先进的分布式版本管理系统 2&#xff0e;工作原理/流程workspace&#xff1a;工作区 Index/Stage&#xff1a;暂存区 Repository&#xff1a;仓库区&#xff08;本地仓库&#xff09; Remote&#xff1a;远程仓库二、SVN和Git的最主…

AdsPower API 新增查询环境 Cookies 接口,自动化更进一步!

你是不是有过这样的经历&#xff1f;账号在 AdsPower 环境中已经成功登录&#xff0c;但你还要花时间手动导出 Cookies、再整理处理&#xff0c;过程繁琐、效率低下。 现在&#xff0c;我们上线了 API 查询环境 Cookies 的接口&#xff0c;支持通过 API 直接获取已登录环境的 …

Craftium游戏引擎中的客户端同步机制解析

Craftium游戏引擎中的客户端同步机制解析 craftium A framework for creating rich, 3D, Minecraft-like single and multi-agent environments for AI research based on Minetest 项目地址: https://gitcode.com/gh_mirrors/cr/craftium 游戏状态同步的核心问题 在分…

spring cloud负载均衡之FeignBlockingLoadBalancerClient、BlockingLoadBalancerClient

本文主要分析被 FeignClient 注解的接口类请求过程中负载均衡逻辑&#xff0c;流程分析使用的源码版本信息如下&#xff1a;<spring-boot.version>3.2.1</spring-boot.version><spring-cloud.version>2023.0.0</spring-cloud.version>背景 平常我们代码…

提示工程(Prompt Engineering)研究进展

提示工程(Prompt Engineering)研究进展 以及它如何帮助大语言模型(LLMs)和视觉语言模型(VLMs)更好地工作。用简单的话说,就是通过设计巧妙的“提示”(比如指令、例子),让模型在不修改内部参数的情况下,更精准地完成各种任务,比如回答问题、推理、生成内容等。 文档…

【ARM】AI开发板A7处理器JTAG实现指南

一、文档背景尽管开发板原厂提供了相关文档&#xff0c;但可能缺乏对 A7 处理器 JTAG 功能的详细说明。这可能会导致以下问题&#xff1a;开发人员难以理解和利用 A7 处理器的基本功能&#xff0c;阻碍调试和开发进度。在进行Uboot移植过程中&#xff0c;无法应用图形界面的调试…

FPGA(一)Quartus II 13.1及modelsim与modelsim-altera安装教程及可能遇到的相关问题

零.前言 在学习FPGA课程时&#xff0c;感觉学校机房电脑用起来不是很方便&#xff0c;想着在自己电脑上下载一个Quartus II 来进行 基于 vhdl 语言的FPGA开发。原以为是一件很简单的事情&#xff0c;没想到搜了全网文章发现几乎没有一个完整且详细的流程教学安装&#xff08;也…

软考(软件设计师)存储管理—存储空间管理,文件共享保护

一、文件存取方法 1. 顺序存取&#xff08;Sequential Access&#xff09; 原理&#xff1a;按记录写入顺序依次访问特点&#xff1a; 读操作&#xff1a;读取当前位置&#xff0c;指针自动前移写操作&#xff1a;追加到文件末尾 适用场景&#xff1a;磁带设备、日志文件 #merm…

Thinkphp6中如何将macro方法集成到Request类中

在学习crmeb的时候发现他使用了一个macro的方法用在中间件中&#xff0c;于对macro进行了简单的研究&#xff0c;发现这个方法可以在中间件中进行定义一些方法&#xff0c;然后让后面的控制器进行使用。 如&#xff1a; 在授权的中间件中&#xff0c;定义了$request->macro…

Java List 使用详解:从入门到精通

一、List 基础概念1.1 什么是 List&#xff1f;List 就像是一个智能书架&#xff1a;可以按顺序存放书籍&#xff08;元素&#xff09;每本书都有固定位置&#xff08;索引&#xff09;可以随时添加、取出或重新排列书籍// 创建一个书架&#xff08;List&#xff09; List<S…

Java零基础笔记06(数组:一维数组、二维数组)

明确: 程序是用来处理数据的, 因此要掌握数据处理的数据结构数组是编程中常用的数据结构之一&#xff0c;用于存储一系列相同类型的元素。在Java中&#xff0c;数组是一种对象&#xff0c;可以存储固定大小的相同类型元素的集合。1.一维数组数组是一个数据容器,可用来存储一批同…

10倍处理效率提升!阿里云大数据AI平台发布智能驾驶数据预处理解决方案

阿里云大数据AI平台重磅发布智能驾驶数据预处理解决方案&#xff0c;可帮助汽车行业客户实现构建高效、稳定的数据预处理产线流程&#xff0c;数据包处理效率相比自建可提升10倍以上&#xff0c;数据处理推理任务优化提速1倍以上&#xff0c;相同资源产能提升1倍[1]&#xff0c…

SAP HANA内存数据库解析:特性、优势与应用场景 | 技术指南

SAP HANA 是一款列式内存关系数据库&#xff0c;集 OLAP 和 OLTP 操作于一体。相较于同类产品&#xff0c;SAP HANA 需要的磁盘空间更少&#xff0c;并且可扩展性高。SAP HANA 可以部署在本地、公有云或私有云以及混合场景中。该数据库适用于各种数据类型的高级分析和事务处理。…

Openharmony4.0 rk3566上面rknn的完美调用

一 背景&#xff1a; 我们都知道如果要在android上面使用rknn推理模型需要按照如下的步骤&#xff1a; 详细请参考笔者的文章&#xff1a;Android11-rk3566平台上采用NCNN&#xff0c;RKNN框架推理yolo11官方模型的具体步骤以及性能比较-CSDN博客 简而言之就是 模型转换&#…

Java多线程知识小结:Synchronized

在Java中&#xff0c;synchronized 关键字是实现线程同步的核心工具&#xff0c;用于保证同一时刻只有一个线程可以执行被修饰的代码块或方法。以下从基本原理、锁升级过程、应用场景及优化建议四个维度详细解析&#xff1a; 一、基本原理 1. 同步的对象 synchronized 锁的是对…

MTK项目wifi.cfg文件如何配置的Tput和功耗参数

下面的MTK参数主要与无线网络(Wi-Fi)配置相关,特别是与WMM(Wi-Fi Multimedia)和功率控制相关的设置 WMM相关参数: WmmParamCwMax/WmmParamCwMin:定义竞争窗口的最大/最小值,这里设置为10/4,用于控制信道访问的退避机制13 WmmParamAifsN:仲裁帧间间隔数,设置为3影响不同…

分水岭算法:图像分割的浸水原理

分水岭算法&#xff1a;基于拓扑地貌的边界提取核心原理 分水岭算法将图像视为拓扑地貌&#xff0c;灰度值代表海拔高度。通过模拟浸水过程&#xff1a;局部极小值&#xff1a;对应集水盆&#xff08;区域内部&#xff09;。分水岭线&#xff1a;集水盆之间的山脊&#xff08;区…