经纬志
首页 / 实战手册 / Leaflet 容器与图层

搜索一次加一层,点越叠越多还删不掉

先看结论

同一个站点搜索五次,图标边缘越来越毛,点击一次弹出五个相同的气泡。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文

现象

连续搜索同一关键词,地图上的标记数量成倍增长。 点击标记时弹出多个内容相同的 popup。 切换筛选条件后,旧标记仍然留在图上。长时间使用,页面内存持续上涨。

原因

每次搜索都执行 map.addLayer(L.marker(...)),每次都创建新实例。 Leaflet 对“同一个图层对象重复添加”会忽略,但对“同一位置的不同对象”不会去重, 于是全部叠在一起。

更麻烦的是 clearLayers 只清空了图层组, 但代码里保存了旧的 marker 引用,后续操作仍然作用于已经移除的对象, 表现为“删了还在”。

排查过程

用 eachLayer 统计当前地图上的图层数量,再与搜索结果数量对比:

var count = 0;
map.eachLayer(function (layer) {
  if (layer instanceof L.Marker) count++;
});
console.log('地图上的标记数', count, '结果数', results.length);

解决方案

所有业务标记放进一个 LayerGroup,每次更新前先清空。 这是最稳的写法:

var resultLayer = L.layerGroup().addTo(map);

function renderResults(results) {
  resultLayer.clearLayers();

  results.forEach(function (r) {
    var marker = L.marker([r.lat, r.lng])
      .bindPopup(r.name + '<br>' + r.address);

    resultLayer.addLayer(marker);
  });
}

renderResults(initialResults);

只需要更新单个标记时,先判断是否已经在图上,避免重复添加:

if (!map.hasLayer(marker)) {
  map.addLayer(marker);
} else {
  marker.setLatLng([newLat, newLng]);
}

数据量较大时不要反复创建标记,改为复用对象池,只改位置与内容:

var pool = [];
function upsert(index, item) {
  var marker = pool[index];
  if (!marker) {
    marker = L.marker([item.lat, item.lng]).addTo(map);
    pool[index] = marker;
  } else {
    marker.setLatLng([item.lat, item.lng]);
  }
  marker.bindPopup(item.name);
}

function trimPool(size) {
  for (var i = size; i < pool.length; i++) {
    if (pool[i]) map.removeLayer(pool[i]);
  }
  pool.length = size;
}

验证

连续搜索五次,标记数量始终等于结果数量,不累加。 点击标记只弹出一个气泡。 切换筛选后,旧标记全部消失;内存面板在多次搜索后保持平稳。

一个判断习惯:看到“越用越卡、图标越来越糊”,先数图层数量。 多数情况不是渲染性能问题,而是同一份数据被反复添加。

引用本文

经纬志(2026)。《搜索一次加一层,点越叠越多还删不掉》。https://www.jingweizhi.com/cookbook/leaflet-duplicate-addlayer.html(访问日期 2026-11-03)。