Files
sunProduct/src/components/Echarts/index.vue
2026-06-16 15:09:09 +08:00

119 lines
2.6 KiB
Vue

<template>
<div ref="chartRef" class="echarts-container" :style="{ width, height }"></div>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch, nextTick, shallowRef } from 'vue';
import * as echarts from 'echarts';
import type { EChartsOption, ECharts } from 'echarts';
interface Props {
width?: string;
height?: string;
options: EChartsOption;
theme?: string;
autoResize?: boolean;
immediate?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
width: '100%',
height: '100%',
theme: '',
autoResize: true,
immediate: true
});
const emit = defineEmits<{
ready: [chart: ECharts];
click: [params: echarts.ECElementEvent];
rendered: [];
}>();
const chartRef = ref<HTMLDivElement>();
// 3. 使用 shallowRef 优化性能,因为 ECharts 实例不需要深层响应式
const chartInstance = shallowRef<ECharts | null>(null);
let resizeObserver: ResizeObserver | null = null;
const initChart = () => {
if (!chartRef.value) return;
if (chartInstance.value) {
chartInstance.value.dispose();
chartInstance.value = null;
}
const instance = echarts.init(chartRef.value, props.theme);
chartInstance.value = instance;
chartInstance.value.setOption(props.options);
emit('ready', instance);
emit('rendered');
instance.on('click', (params: any) => {
emit('click', params);
});
};
const updateChart = () => {
if (chartInstance.value) {
chartInstance.value.setOption(props.options, {
notMerge: false,
lazyUpdate: false
});
emit('rendered');
}
};
// ✅ 核心修复:支持 scale 缩放后重绘
const resizeChart = () => {
if (!chartInstance.value) return;
chartInstance.value.resize();
};
const getInstance = () => chartInstance.value;
const exportAsImage = (type: 'png' | 'svg' | 'jpeg' = 'png') => {
return (
chartInstance.value?.getDataURL({
type,
pixelRatio: 2,
backgroundColor: '#fff'
}) || ''
);
};
watch(() => props.options, updateChart, { deep: true });
onMounted(() => {
nextTick(() => initChart());
if (props.autoResize && chartRef.value) {
resizeObserver = new ResizeObserver(resizeChart);
resizeObserver.observe(chartRef.value);
}
window.addEventListener('resize', resizeChart);
});
onBeforeUnmount(() => {
window.removeEventListener('resize', resizeChart);
resizeObserver?.disconnect();
chartInstance.value?.dispose();
chartInstance.value = null;
});
defineExpose({
resizeChart,
updateChart,
getInstance,
exportAsImage
});
</script>
<style lang="scss" scoped>
.echarts-container {
display: block;
width: 100%;
height: 100%;
}
</style>