uniapp项目中使用echarts

因为多处使用,所以我这里直接采用封装组件的方式。

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}`);
...
}
相关推荐
胡萝卜术5 小时前
从API调用到手写LRU:力扣146「LRU缓存」的哈希表+双向链表终极进化之路
前端·javascript·面试
科技道人5 小时前
记录 默认置灰/禁用 app ‘Search Engine Selector‘ 的disable按钮
开发语言·前端·javascript
shuaijie051811 小时前
强制修改调用接口的api地址。
javascript·vue.js·ecmascript
JerrySir11 小时前
恶意 npm 包只活了 17 分钟:技术面试里,为什么“升级依赖”还不算止血?
javascript·安全
白帽小阳11 小时前
2026前端面试题!(附答案及解析)
javascript·网络·python·安全·web安全·网络安全·护网行动
这是个栗子11 小时前
前端开发中的常用工具函数(八)
开发语言·前端·javascript
Hilaku11 小时前
Vue 和 React 真正的差距,不在语法,而在团队犯错成本
前端·javascript·程序员
研☆香12 小时前
为什么变量声明在赋值前也能使用?—— 深入理解 JavaScript 变量提升与作用域
开发语言·前端·javascript
柯克七七12 小时前
我把 bug 修得太干净了,测试组以为这个模块本来就没问题
前端·javascript·typescript
Null15512 小时前
浏览器唤起桌面端应用(终极篇)
前端·javascript