搜索一次加一层,点越叠越多还删不掉
同一个站点搜索五次,图标边缘越来越毛,点击一次弹出五个相同的气泡。
现象
连续搜索同一关键词,地图上的标记数量成倍增长。
点击标记时弹出多个内容相同的 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)。