优化细节

This commit is contained in:
2026-02-05 17:11:41 +08:00
parent 821205b18a
commit 151f5a5e1a
10 changed files with 634 additions and 194 deletions

View File

@@ -36,7 +36,7 @@ async function loadChinaMap() {
if (chinaMapLoaded) {
return Promise.resolve();
}
if (chinaMapLoading) {
// 如果正在加载,等待加载完成
return new Promise((resolve) => {
@@ -53,9 +53,9 @@ async function loadChinaMap() {
}, 10000);
});
}
chinaMapLoading = true;
try {
// 从在线 CDN 加载中国地图 GeoJSON 数据
// 使用 ECharts 官方示例数据源
@@ -72,7 +72,7 @@ async function loadChinaMap() {
const geoJson = await response.json();
echarts.registerMap('china', geoJson);
}
chinaMapLoaded = true;
console.log('[EChartsView] 中国地图数据已加载并注册');
} catch (error) {
@@ -94,15 +94,15 @@ function getChartKey(el) {
function ensureChart(el, retryCount = 0) {
if (!el) return null;
const key = getChartKey(el);
let chart = charts.get(key);
// 如果图表已存在且有效,直接返回
if (chart && !chart.isDisposed()) {
return chart;
}
// 如果图表已销毁,从 Map 中移除
if (chart && chart.isDisposed()) {
charts.delete(key);
@@ -113,19 +113,19 @@ function ensureChart(el, retryCount = 0) {
}
chart = null;
}
// 确保元素有尺寸
const rect = el.getBoundingClientRect();
const computedStyle = window.getComputedStyle(el);
const width = parseFloat(computedStyle.width) || rect.width;
const height = parseFloat(computedStyle.height) || rect.height;
// 如果尺寸为 0尝试延迟初始化最多重试 10 次)
if ((width === 0 || height === 0) && retryCount < 10) {
if (retryCount === 0) {
console.warn('[EChartsView] 容器尺寸为 0延迟初始化', { width, height, rect });
}
// 使用指数退避策略,避免无限循环
const delay = Math.min(100 * Math.pow(1.5, retryCount), 1000);
setTimeout(() => {
@@ -133,7 +133,7 @@ function ensureChart(el, retryCount = 0) {
}, delay);
return null;
}
// 如果重试次数过多,使用默认尺寸
if (width === 0 || height === 0) {
console.warn('[EChartsView] 容器尺寸仍为 0使用默认尺寸', { width, height });
@@ -141,7 +141,7 @@ function ensureChart(el, retryCount = 0) {
const parentRect = el.parentElement ? el.parentElement.getBoundingClientRect() : { width: 800, height: 400 };
const finalWidth = width || parentRect.width || 800;
const finalHeight = height || parentRect.height || 400;
if (finalWidth > 0 && finalHeight > 0) {
// 设置元素尺寸
el.style.width = finalWidth + 'px';
@@ -151,19 +151,19 @@ function ensureChart(el, retryCount = 0) {
return null;
}
}
try {
// 注意:地图数据加载在 setOption 中处理,这里不处理
// 因为 ensureChart 是同步函数,不能使用 await
chart = echarts.init(el, null, {
chart = echarts.init(el, null, {
renderer: "canvas",
width: rect.width,
height: rect.height
});
charts.set(key, chart);
// 自适应:监听容器尺寸变化
if (typeof ResizeObserver !== "undefined") {
const ro = new ResizeObserver((entries) => {
@@ -200,7 +200,7 @@ function ensureChart(el, retryCount = 0) {
// 存储 handler 以便后续清理
el._resizeHandler = resizeHandler;
}
return chart;
} catch (e) {
console.error('[EChartsView] 初始化失败', e);
@@ -212,7 +212,7 @@ function disposeChart(el) {
if (!el) return;
const key = getChartKey(el);
const chart = charts.get(key);
if (chart && !chart.isDisposed()) {
try {
chart.dispose();
@@ -220,15 +220,15 @@ function disposeChart(el) {
console.warn('[EChartsView] dispose 失败', e);
}
}
charts.delete(key);
const ro = resizeObservers.get(key);
if (ro) {
ro.disconnect();
resizeObservers.delete(key);
}
if (el._resizeHandler) {
window.removeEventListener("resize", el._resizeHandler);
delete el._resizeHandler;
@@ -260,22 +260,22 @@ export default {
console.error('[EChartsView] setOption: 找不到容器元素');
return;
}
// 检查 option 是否有效
if (!option || typeof option !== 'object') {
console.warn('[EChartsView] setOption: option 无效', option);
return;
}
// 检查是否使用了地图,如果是,先加载地图数据
const needsMap = option.geo || (option.series && Array.isArray(option.series) && option.series.some(s => s.type === 'map' && s.map === 'china'));
if (needsMap) {
await loadChinaMap();
}
// 保存 option 供 ensureChart 使用
el._pendingOption = option;
// 确保图表已初始化
let c = ensureChart(el);
if (!c) {
@@ -369,7 +369,7 @@ export default {
}
return;
}
// 检查图表是否已销毁
if (c.isDisposed()) {
console.warn('[EChartsView] setOption: 图表已销毁,重新初始化');
@@ -380,7 +380,7 @@ export default {
c = ensureChart(el);
if (!c) return;
}
try {
// 如果使用地图,确保地图已加载
if (needsMap) {
@@ -389,7 +389,7 @@ export default {
// 深拷贝 option 确保是纯 JS 对象
const plainOption = JSON.parse(JSON.stringify(option));
c.setOption(plainOption, true);
// 使用 requestAnimationFrame 避免 resize 警告
requestAnimationFrame(() => {
const key = getChartKey(el);
@@ -415,11 +415,20 @@ export default {
<style>
.ec-wrap {
position: relative !important;
width: 100%;
height: 100%;
overflow: hidden; /* 防止 canvas 越界 */
}
.ec-canvas {
width: 100%;
height: 100%;
position: absolute !important;
left: 0;
right: 0;
top: 0;
bottom: 0;
width: 100% !important;
height: 100% !important;
display: block;
}
</style>