唯杰地图 logo唯杰地图
VJMAP
EN

dispose

vjmap/references/setup/dispose.md 3.3 KB99 行
原文

本文回答:组件卸载 / 切换路由时正确的清理顺序,避免 Marker 残留、监听器泄漏、WebGL 上下文爆满。

一、标准清理顺序

// 卸载时按以下顺序:
// 1) 卸载 MapCadLayer(map.removeControl 会触发其 onRemove → 取消动画、释放 fx、清实体)
if (mapcadLayer) {
  map.removeControl(mapcadLayer);
  mapcadLayer = null;
}

// 2) 移除手动挂上的 Marker / Popup / 监听
markers.forEach(m => m.remove());
markers = [];
map.off("click", myHandler);

// 3) 销毁 Map(会释放 WebGL 上下文、source、layer、tile cache)
map.remove();
map = null;

// 4) Service 无 destroy 方法、本身无状态,不用管;多个 svc 实例共享底层连接也没问题

二、Vue 3

<script setup>
import { onMounted, onUnmounted } from "vue";
let map, mapcadLayer;

onMounted(async () => { /* 初始化见 integrations.md */ });
onUnmounted(() => {
  mapcadLayer && map?.removeControl(mapcadLayer);
  map?.remove();
  map = null;
  mapcadLayer = null;
});
</script>

Vue 2:用 beforeDestroy(或 Vue 2.7 的 beforeUnmount)。

三、React(StrictMode 友好)

useEffect(() => {
  let map, cad, disposed = false;
  (async () => {
    // ... 初始化 ...
    if (disposed) { map?.remove(); return; }
  })();
  return () => {
    disposed = true;
    if (cad && map) map.removeControl(cad);
    map?.remove();
  };
}, []);

React StrictMode 会双触发 useEffect,必须用 disposed 标志位防止第二次 map 在第一次还没建完就 remove。

四、常见泄漏症状

症状 泄漏点 修法
Marker 在页面切换后还显示 没 marker.remove() 或持有 DOM 引用 组件卸载时显式 remove 全部 Marker
切换页面多次后页面卡 map.on("mousemove", ...) 不清 统一保存 handler 并 map.off
切页面十次后抛 CONTEXT_LOST_WEBGL map 没 remove,WebGL 上下文超 16 个 卸载时必须 map.remove()
MapCadLayer 的动画还在运行 没 removeControl(cad) 先 removeControl,再 map.remove()
mapdata watcher 还在触发 MapCadLayer.onRemove 没跑 确认 map.removeControl(cad) 成功调用

五、长驻应用的特殊情况

SPA 里长时间运行 / 地图频繁切换:

  • 切图(切换另一张 DWG)不需要销毁 map,而是用 await map.switchMap({ mapid, mapopenway }, …)(内部 openMap + 换瓦片源 + updateMapExtent;只调 updateMapExtent 不会换瓦片,旧图照样显示),详见 open-map/switching.md。
  • 不断新建 / 销毁 Map 实例会让浏览器 WebGL 上下文池满。每个页面 最多同时保留一张 Map。

六、配合 ResizeObserver 的清理

const ro = new ResizeObserver(() => map.resize());
ro.observe(container);
// 卸载时:ro.disconnect(); ro = null;

七、自动化检查清单

卸载时请确认以下都执行了:

  • map.removeControl(cad)(仅当用了 MapCadLayer)
  • 所有手动 Marker.remove()
  • 所有手动 map.off(...)
  • ResizeObserver.disconnect()
  • map.remove()
  • 本地引用置 null
  • 组件内保留的 setInterval / setTimeout 清除