map-lifecycle
本文回答:
map.on生命周期事件 —— load / idle / render / sourcedata / styledata / error。
一、事件列表
| 事件 | 触发时机 |
|---|---|
load |
地图首次加载完成(style + initial render) |
idle |
当前帧渲染完毕且没有未完成的操作 |
render |
每次地图重绘后触发(动画 / 交互时高频;静止时不触发) |
sourcedata |
source 有新数据(瓦片加载、setData) |
styledata |
地图样式对象有变化(setStyle / addLayer / setPaintProperty…,会多次触发);vjmap map.updateStyle 栅格模式不触发 |
styledataloading |
样式开始加载 |
sourcedataloading |
source 开始加载 |
error |
出错(图层 / 源 / 瓦片) |
remove |
地图被销毁 |
二、load(关键)
所有 addLayer / addSource 调用必须在 load 之后:
await map.onLoad();
map.addLayer({ id: 'my', source: 'src', type: 'line' });
或用事件:
map.on('load', () => {
map.addLayer(...);
});
map.onLoad() 是 Promise 版本,推荐。
三、idle
"空闲"状态 = 所有瓦片请求完成 + 无动画。用于截图:
map.once('idle', () => {
const dataUrl = map.getCanvas().toDataURL();
download(dataUrl);
});
四、render
地图每次重绘都 fire(按需渲染:静止不触发,动画 / 拖动时每帧触发),对高频操作慎用:
map.on('render', () => {
// 同步 HUD,最好判断变化
});
五、sourcedata
source 状态变化:
map.on('sourcedata', e => {
if (e.sourceId === 'my-src' && map.isSourceLoaded('my-src')) {
console.log('my-src 数据已加载');
}
});
⚠️ e.isSourceLoaded 实为整个样式所有源是否都加载完(取的是 style.loaded()),不是 e.sourceId 这一个源;判断单源用 map.isSourceLoaded(id)。
六、styledata
样式变化:
map.on('styledata', () => {
// 样式对象变了(会多次触发,handler 须幂等)
});
styledata 是地图样式对象变化(setStyle / addLayer / setPaintProperty…)时触发。vjmap map.updateStyle(svc, …) 在栅格模式只换瓦片 URL(只有 sourcedata),不触发 styledata,自定义图层也不会丢;仅矢量瓦片且 darkMode 变化时内部才 setStyle。
七、error
map.on('error', e => {
console.error('地图错误:', e.error);
});
常见:
- 图层 id 重复
- source URL 404 / CORS
- 瓦片下载失败(单个瓦片错不会让地图坏)
八、一次性 once
map.once('load', handler);
或 Promise:
await map.onLoad();
九、组合场景
1 加载进度条
dataloading / sourcedataloading 按瓦片逐个触发,与 sourcedata 不一一对应,勿逐事件计数:
map.on('dataloading', () => showLoading());
map.on('idle', () => hideLoading());
2 地图准备就绪
await map.onLoad();
await map.once('idle'); // once 不传 listener 时返回 Promise
⚠️ map.once(type, layerId, fn) 的图层级 once 在第一次该类事件时就被消耗——即使那次没命中图层(fn 不会被调用)。
3 所有瓦片加载完打截图
map.once('idle', async () => {
const blob = await new Promise(resolve => {
map.getCanvas().toBlob(resolve);
});
saveBlob(blob);
});
4 setStyle 后重建自定义图层
控件是 DOM,不随 setStyle 丢失,无需重建;需要重建的是自定义 source / layer:
map.on('style.load', () => {
if (!map.getSource('my-src')) {
// 重新 addSource / addLayer
}
});
十、生命周期坑
- load 之前 addLayer:报错
Style is not done loading。 - render 里做昂贵计算:重绘的每帧都跑;必须节流 or 用
idle。 - setStyle 后 addLayer 丢失:setStyle 会清空 layer;在
style.load里判断后重新加(styledata 会多次触发)。 - error 事件吃掉错误:如果没监听,库会打
console.error;监听后记得自己打印。 - remove 之后继续 on:报错或静默;代码里判断
if (!map._removed)。
相关
- 交互事件 → map-interaction
- 视图事件 → map-view
- 样式切换 → map-style/theme-switch