因为多处使用,所以我这里直接采用封装组件的方式。
myChart.vue
csharp
<template>
<view class="chart-container">
<view class="my-echarts-container" :id="echartsId" :style="{ width: width, height: height }" ref="echartsRef"></view>
</view>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, nextTick, computed } from 'vue';
import * as echarts from 'echarts';
import type { ECharts, EChartsOption, EChartsResponsiveOption } from 'echarts';
const props = defineProps({
chartOptions: {
type: Object as () => EChartsOption | EChartsResponsiveOption,
required: true,
default: () => ({})
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '600rpx'
}
});
const echartsId = computed(() => `my-echarts-${Date.now()}-${Math.floor(Math.random() * 1000)}`);
const echartsRef = ref<HTMLElement | null>(null);
let myEcharts : ECharts | null = null;
// 3. 初始化 ECharts 实例
const initEcharts = () => {
// document.querySelector 获取原生 DOM 元素,避免原来的 ref方式报错找不到dom
let container: HTMLElement | null = document.querySelector(`#${echartsId.value}`);
// 如果 querySelector 获取失败,再使用 ref
if (!container && echartsRef.value) {
container = echartsRef.value as unknown as HTMLElement;
}
// 判断容器是否有效
if (!container) {
console.error('ECharts 容器获取失败!无法初始化图表');
return;
}
// 销毁已有实例,避免内存泄漏
if (myEcharts) {
myEcharts.dispose();
myEcharts = null;
}
// 原生 ECharts 初始化
try {
myEcharts = echarts.init(container);
renderEcharts();
console.log('ECharts 初始化成功!');
} catch (err) {
console.error('ECharts 初始化失败:', err);
}
};
// 渲染
const renderEcharts = () => {
if (!myEcharts || !props.chartOptions) return;
try {
myEcharts.setOption(props.chartOptions, true);
} catch (err) {
console.error('ECharts 渲染配置失败:', err);
}
};
// 挂载
onMounted(() => {
// 双重 nextTick 确保 DOM 完全渲染(解决部分场景下 DOM 未加载完成问题)
nextTick(() => {
nextTick(() => {
initEcharts();
});
});
});
// 卸载时销毁实例和事件监听
onUnmounted(() => {
if (myEcharts) {
myEcharts.dispose();
myEcharts = null;
}
});
// 监听 Props 变化,更新图表
watch(
() => props.chartOptions,
() => {
nextTick(renderEcharts);
},
{ deep: true, immediate: false }
);
watch(
() => [props.width, props.height],
() => {
nextTick(initEcharts);
},
{ deep: true }
);
defineExpose({
/** 主动更新图表 */
refresh: renderEcharts,
getEchartsInstance: () => myEcharts
});
</script>
<style lang="scss" scoped>
.my-echarts-container {
box-sizing: border-box;
visibility: visible;
overflow: hidden;
background-color: #fafafa;
/* 给容器一个最小宽高,避免 UniApp 渲染时宽高丢失 */
min-width: 300px;
min-height: 400px;
}
</style>
组件使用:
csharp
<myChart class="m-line" :chartOptions="applyChartOptions" />
...
import type { EChartsOption } from 'echarts';
import myChart from '@/components/myChart/myChart'
...
applyChartOptions.value = ref<EChartsOption>({...})
uniapp使用echarts常见报错
1、Uncaught (in promise) TypeError: this.dom.getContext is not a function
没有获取到DOM;
排除1:在初始化前检查是否检查DOM有效;
csharp
if (!echartsRef.value) {
console.error('ECharts 容器 DOM 不存在!');
return;
}
排除2:如果是小程序环境,需要做一下兼容处理,使用 uni-ec-canvas 适配;
2、ECharts 容器不是有效的
排除1:优先使用view标签,UniApp H5 端会自动将 编译为
,ref 获取到的元素更稳定
csharp
<view class="my-echarts-container" id="my-echarts" :style="{ width: width, height: height }" ref="echartsRef"></view>
排除2:容器获取方式优先使用document.querySelector ,避免 UniApp 对 ref 元素的包装。
csharp
let container: HTMLElement | null = document.querySelector(`#my-echarts`);
// 如果 querySelector 获取失败,再使用 ref
if (!container && echartsRef.value) {
container = echartsRef.value as unknown as HTMLElement;
}
// 判断容器是否有效
if (!container) {
console.error('ECharts 容器获取失败!无法初始化图表');
return;
}
排除3:单个页面中多处使用图标组件,应该给容器添加唯一ID
csharp
<view class="my-echarts-container" :id="echartsId" :style="{ width: width, height: height }" ref="echartsRef"></view>
csharp
const echartsId = computed(() => `my-echarts-${Date.now()}-${Math.floor(Math.random() * 1000)}`);
...
const initEcharts = () => {
...
let container: HTMLElement | null = document.querySelector(`#${echartsId.value}`);
...
}