115 lines
2.7 KiB
Plaintext
115 lines
2.7 KiB
Plaintext
<template>
|
||
<view class="ec-wrap">
|
||
<!-- 使用 ref 来获取容器 -->
|
||
<view ref="ecCanvas" class="ec-canvas" :style="{ width: '100%', height: '100%' }"></view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="uts">
|
||
import { ref, onMounted, onBeforeUnmount, watch, onUnmounted } from 'vue'
|
||
import * as echarts from 'echarts'
|
||
|
||
const props = defineProps({
|
||
option: { type: Object, default: () => ({}) },
|
||
theme: { type: String, default: 'light' }
|
||
})
|
||
|
||
const ecCanvas = ref<UniElement | null>(null)
|
||
let chart: any = null
|
||
let resizeObserver: any = null
|
||
|
||
// 加载并注册中国地图
|
||
async function loadChinaMap() {
|
||
try {
|
||
// 检查是否已注册过
|
||
if (echarts.getMap('china')) return
|
||
|
||
// 尝试从 CDN 加载中国地图
|
||
const response = await fetch('https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json')
|
||
if (response.ok) {
|
||
const geoJson = await response.json()
|
||
echarts.registerMap('china', geoJson)
|
||
console.log('[EChartsView] 中国地图载入并注册成功')
|
||
}
|
||
} catch (e) {
|
||
console.warn('[EChartsView] 地图加载失败,降级处理', e)
|
||
}
|
||
}
|
||
|
||
const initChart = async () => {
|
||
if (!ecCanvas.value) {
|
||
console.warn('[EChartsView] 找不到 canvas 引用')
|
||
return
|
||
}
|
||
|
||
// 在 H5 环境下,ecCanvas.value 会表现为 HTML 元素
|
||
const el = ecCanvas.value as any; // 这里显式作为 any 使用以避开UTS编译器对DOM API的严格限制
|
||
|
||
if (chart) {
|
||
chart.dispose()
|
||
chart = null
|
||
}
|
||
|
||
// 计算是否需要地图
|
||
const opt = props.option as any;
|
||
const needsMap = opt['geo'] != null || (opt['series'] != null && Array.isArray(opt['series']) && (opt['series'] as any[]).some(s => s.type === 'map' && s.map === 'china'))
|
||
|
||
if (needsMap) {
|
||
await loadChinaMap()
|
||
}
|
||
|
||
try {
|
||
chart = echarts.init(el, props.theme)
|
||
chart.setOption(props.option)
|
||
|
||
// 监听容器尺寸变化实施自适应
|
||
if (typeof ResizeObserver !== 'undefined') {
|
||
resizeObserver = new ResizeObserver(() => {
|
||
if (chart) chart.resize()
|
||
})
|
||
resizeObserver.observe(el)
|
||
}
|
||
} catch (e) {
|
||
console.error('[EChartsView] 初始化失败', e)
|
||
}
|
||
}
|
||
|
||
onMounted(() => {
|
||
// 渲染后延迟初始化以确保容器宽高已经渲染完毕
|
||
setTimeout(() => {
|
||
initChart()
|
||
}, 100)
|
||
})
|
||
|
||
onUnmounted(() => {
|
||
if (chart) {
|
||
chart.dispose()
|
||
chart = null
|
||
}
|
||
if (resizeObserver) {
|
||
resizeObserver.disconnect()
|
||
resizeObserver = null
|
||
}
|
||
})
|
||
|
||
watch(() => props.option, (newVal) => {
|
||
if (chart) {
|
||
chart.setOption(newVal)
|
||
}
|
||
}, { deep: true })
|
||
</script>
|
||
|
||
<style scoped>
|
||
.ec-wrap {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.ec-canvas {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
}
|
||
</style>
|