Vue3 地图白屏排查清单:容器、弹窗与 ol-viewport 重复创建

TL;DR:Vue3 + OpenLayers 地图白屏且控制台无报错,按「容器尺寸 → 初始化时机 → viewport 数量 → 中心点投影 → 底图 URL」这个顺序查,90% 的案例停在第一步。文末 Demo 可一键切换错误 / 正确两种状态,浏览器直接打开即可复现。

之前给客户做 Vue3 + OpenLayers 的水利一张图,页面切到地图 tab 时整块空白,F12 里干干净净,连瓦片请求都没有。查了快两个小时,最后发现是容器高度为 0 时就把 Map new 出来了。

这种 "无报错白屏" 是 WebGIS 前端最磨人的问题 ------ 报错还能搜,不报错全靠猜。这篇把排查顺序和每个环节的验证方法一次说清,本机 Chrome 实测,2026-10。

先分清:真白屏还是 "假白屏"

白屏分两种,排查路径完全不同:

  • 真白屏 :容器里连 .ol-viewport 都没有,或者 canvas 尺寸是 0×0------ 初始化时机问题;

  • 假白屏:viewport 存在,但地图定位到了别处,或瓦片没加载出来 ------ 投影 / 请求问题。

判断方法:F12 里查一下容器内有没有 .ol-viewport。有,就是假白屏,直接跳到第四、五步;没有,从第一步开始。

第一步:容器尺寸,绝大多数的坑都在这

常见三种来源:

  1. 弹窗 / 抽屉未展开就初始化地图;

  2. v-if 控制的地图容器还在渲染中;

  3. 容器设了 height: 0(自适应布局没给高度)。

验证只需一行:

javascript 复制代码
console.log(container.getBoundingClientRect())
// 宽或高为 0,就是它

复现一下错误写法 ------ 容器高度 0 时初始化,页面白屏且控制台无任何报错:

javascript 复制代码
// 错误:容器尺寸为 0 时初始化
const map = new Map({
  target: container, // getBoundingClientRect() 高度为 0
  layers: [new TileLayer({ source: new XYZ({ url: gaodeUrl }) })],
  view: new View({ center: fromLonLat([113.2644, 23.1291]), zoom: 12 })
})

正确写法是等容器有尺寸再初始化:

javascript 复制代码
// 正确:先等容器就绪,确认有尺寸再 new Map
await nextTick()
const rect = container.getBoundingClientRect()
if (rect.width === 0 || rect.height === 0) return // 容器不可见,先别初始化
const map = new Map({ target: container, /* ... */ })

第二步:初始化时机,弹窗里最常见的坑

el-dialog 这类弹窗默认懒渲染 + display: none,直接在 onMounted 里 new Map,容器根本还没挂出来。要用弹窗的 opened 回调,或者 nextTick 后检查 offsetParent------display: none 时它是 null:

javascript 复制代码
if (container.offsetParent === null) {
  // 容器处于隐藏状态,地图初始化会白屏,等显示后再做
}

第三步:ol-viewport 重复创建,路由切换的隐性泄漏

KeepAlive 缓存 + 路由复用是重灾区:每次进页面 new 一个 Map,target 相同,OL 会在容器里再插一个 .ol-viewport,旧实例没销毁 ------ 轻则叠影、事件错乱,重则白屏加内存上涨。

排查看数量:

javascript 复制代码
container.querySelectorAll('.ol-viewport').length // 应为 1,大于 1 就是重复创建

修复是卸载时销毁实例:

javascript 复制代码
onBeforeUnmount(() => {
  map?.setTarget(undefined) // 从容器上摘除,再置空引用
  map = null
})

中心点投影:白屏也可能是 "定位到海里"

View 的 center 默认是 Web 墨卡托(EPSG:3857)。直接塞经纬度(EPSG:4326),地图会定位到 (113, 23) 对应的墨卡托位置 ------ 那在赤道附近的海域,页面同样是一片空白,看起来就是白屏:

javascript 复制代码
import { fromLonLat } from 'ol/proj'

// 正确:经纬度必须转投影
view: new View({ center: fromLonLat([113.2644, 23.1291]), zoom: 12 })

底图 URL 不对,请求 404 也会白屏

高德源在 OpenLayers 里必须写数字占位符 {1-4}。写成 Leaflet 的 {s},瓦片请求会打到字面量域名上,全部 404,底图空白:

javascript 复制代码
// OpenLayers 的 XYZ 源不认 {s},必须写 {1-4}
const gaodeUrl =
  'https://webrd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}'
// Leaflet 才用 {s}:https://webrd0{s}.is.autonavi.com/...

按上面顺序修完,地图正常渲染:

⚠️ 三个容易被忽略的点

  1. 排查 "无报错白屏" 先看 Network 面板:一片空白(无瓦片请求)→ 初始化 / 投影问题;有请求但 404/403 → 底图 URL 或 key 问题;

  2. display: none 的容器 getBoundingClientRect 返回 0,但元素其实 "存在"------ 别只看存在性,要看尺寸;

  3. 地图组件卸载不销毁,路由来回切几次后不只白屏,还会把内存吃上去,最后变成 "用着用着就卡"。

一句话口诀:先查尺寸再查时机,viewport 只留一个,经纬度记得转投影。

小结

排查项 验证方法 常见来源
容器尺寸 getBoundingClientRect() 宽高 弹窗未展开 /height:0
初始化时机 offsetParent === null el-dialog 懒渲染
viewport 数量 querySelectorAll('.ol-viewport').length 路由复用未销毁
中心点投影 是否用了 fromLonLat 直接塞经纬度
底图 URL Network 面板瓦片状态 {s} vs {1-4}

排查顺序也有例外 ------ 如果页面之前能正常显示、某次改动后才白,优先看改动点(比如加了 KeepAlive、换了容器结构)。上面的顺序是给 "一上来就白" 的情况用的。

📦 Demo 见 gitee.com/shijiansuip...(浏览器直接打开即可复现,页面内可一键切换错误 / 正确两种状态)。

标签:vue3、webgis、openlayers

相关推荐
hai_android5 小时前
一个公式看懂动态跨表查找:P8 + VLOOKUP
前端·javascript·vue.js
wdssmq8 小时前
「折腾」Vue 简单的状态管理实践
vue.js
Q264336502310 小时前
【有源码】基于Spring Boot和Vue的在线考试与交流系统-教育信息化背景下在线考试与交流一体化平台
java·vue.js·spring boot·mysql·spring·毕业设计·课程设计
苹果二12 小时前
使用Vue的指南
前端·javascript·vue.js
害人终害己12 小时前
‘vue-cli-service‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。
前端·javascript·vue.js
xiangshangdemayi1 天前
Strata教程:让GISer真正实现了token自由
ai·gis·教程·token·strata·自由
excel1 天前
研究 Vue 3 源码的收获
前端·vue.js
vx-程序开发1 天前
【计算机毕设】51300童装超市管理系统的设计与实现
java·vue.js·spring boot·源码·课程设计·毕设·大作业
ym hyd 1111 天前
题库建立与考试系统源码 Java+SpringBoot+Vue3 前后分离
java·开发语言·vue.js·spring boot·毕设