唯杰地图 logo唯杰地图
VJMAP
EN

map-lifecycle

vjmap/references/event/map-lifecycle.md 4.3 KB165 行
原文

本文回答: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
  }
});

十、生命周期坑

  1. load 之前 addLayer:报错 Style is not done loading。
  2. render 里做昂贵计算:重绘的每帧都跑;必须节流 or 用 idle。
  3. setStyle 后 addLayer 丢失:setStyle 会清空 layer;在 style.load 里判断后重新加(styledata 会多次触发)。
  4. error 事件吃掉错误:如果没监听,库会打 console.error;监听后记得自己打印。
  5. remove 之后继续 on:报错或静默;代码里判断 if (!map._removed)。

相关