先上代码:
// hooks/useECharts.ts
import { ref, watch, onMounted, onUnmounted, type Ref } from 'vue';
import type { ECharts, EChartsOption, Theme } from 'echarts';
export interface UseEChartsOptions {
/** ECharts 实例 */
echarts: any; // 根据实际安装的 echarts 类型调整
/** 图表配置项 */
options: EChartsOption;
/** 主题配置 */
theme?: Theme | string;
/** 是否自动响应 resize 事件 */
autoResize?: boolean;
}
export function useECharts(
options: UseEChartsOptions
): {
chartRef: Ref<HTMLElement | null>;
chartInstance: Ref<ECharts | null>;
setOptions: (opts: EChartsOption) => void;
} {
const chartRef = ref<HTMLElement | null>(null);
const chartInstance = ref<ECharts | null>(null);
const { echarts, theme, autoResize = true } = options;
// 初始化图表
const initChart = () => {
if (!chartRef.value) return;
try {
chartInstance.value = echarts.init(chartRef.value, theme);
chartInstance.value.setOption(options.options);
} catch (err) {
console.error('ECharts initialization error:', err);
}
};
// 更新配置
const setOptions = (opts: EChartsOption) => {
if (!chartInstance.value) return;
chartInstance.value.setOption(opts);
};
// 窗口 resize 处理
const handleResize = () => {
if (!chartInstance.value) return;
chartInstance.value.resize();
};
// 自动 resize
const autoResizeHandler = () => {
if (autoResize) {
window.addEventListener('resize', handleResize);
}
};
// 销毁图表
const dispose = () => {
if (chartInstance.value) {
chartInstance.value.dispose();
chartInstance.value = null;
}
window.removeEventListener('resize', handleResize);
};
// 生命周期
onMounted(() => {
initChart();
autoResizeHandler();
});
onUnmounted(() => {
dispose();
});
// 监听 options 变化
watch(
() => options.options,
(newOptions) => {
setOptions(newOptions);
},
{ deep: true }
);
return {
chartRef,
chartInstance,
setOptions
};
}
使用示例:
<template>
<div ref="chartRef" style="width: 100%; height: 400px;"></div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useECharts } from '@/hooks/useECharts';
import * as echarts from 'echarts'; // 按需引入
const options = ref({
title: {
text: '示例图表'
},
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'
}]
});
const { chartRef } = useECharts({
echarts,
options: options.value,
theme: 'light',
autoResize: true
});
</script>
功能说明:
- 自动初始化:在组件挂载时自动初始化 ECharts 实例
- 响应式配置:使用 watch 深度监听 options 变化并自动更新图表
- 自动调整尺寸:
- 默认开启窗口 resize 监听
- 使用防抖优化性能(可根据需要添加)
- 内存管理:
- 组件卸载时自动销毁实例
- 移除事件监听器
- 类型安全:
- 完整的 TypeScript 类型定义
- 支持 ECharts 原生类型
优化建议:
- 按需加载:
// 在调用时按需引入
const { chartRef } = useECharts({
echarts: await import('echarts/lib/echarts'), // 示例按需加载
// ...其他配置
})
- 添加防抖:
import { debounce } from 'lodash-es';
// 修改 handleResize
const handleResize = debounce(() => {
if (!chartInstance.value) return;
chartInstance.value.resize();
}, 300);
- 扩展功能:
// 添加点击事件处理
const addChartClick = (handler: (params: any) => void) => {
if (chartInstance.value) {
chartInstance.value.on('click', handler);
}
}
// 暴露更多控制方法
return {
// ...其他返回值
refresh: () => chartInstance.value?.resize(),
dispose
}
- 错误处理增强:
// 初始化时添加 try/catch
const initChart = () => {
try {
// 初始化代码
} catch (err) {
console.error('ECharts init failed:', err);
// 可添加错误回调
options.onError?.(err);
}
}
这个 Hooks 封装了 ECharts 的核心功能,同时保持了良好的扩展性。使用时需要注意:
- 需要自行安装 echarts 依赖
- 按需引入需要的图表组件
- 建议配合 CSS 设置容器的宽高
- 复杂图表建议拆分 options 生成逻辑
可以根据具体项目需求继续扩展功能,如添加 loading 状态、主题切换、事件处理等。