经纬志
首页 / Leaflet / 教程

图层与图层组

先看结论

Leaflet 里地图上没有「图形」这个概念,只有图层。瓦片、标记、线、面、弹窗都是图层。 单个图层各自 addTo(map) 也能显示,但成组管理才能一次显示、一次清空、 一次绑定事件。这一页把 LayerGroup、FeatureGroup 与 pane 的分工讲清楚。

最后验证 2026-11-03 · Leaflet 1.9.4 · 更新 2026-10-29 · 引用本文

四种容器,用途不同

类型能做什么典型场景
L.Layer单个图层,addTo / remove一个标记、一条线
L.LayerGroup批量增删、统一显隐按业务分类的图层集合
L.FeatureGroup继承 LayerGroup,额外支持事件、getBounds()需要整体点击或视野适配
L.GeoJSON由 GeoJSON 生成,本身就是一个 FeatureGroup面数据、行政区

FeatureGroup 是 LayerGroup 的子类,多出来的能力都围绕「整体」: 整体绑定 click、整体算外包范围、整体 bringToFront()。 选哪个只看一件事:需不需要把这一组当成一个对象来对待。

LayerGroup:批量增删

图层组本身也是图层,所以它可以 addTo(map);之后往组里加东西, 会自动出现在地图上,不需要再调用一次 addTo。

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

group.addLayer(L.marker([39.907359, 116.391263]));
group.addLayer(L.circle([39.907359, 116.391263], {
  radius: 400,
  color: '#17694a',
  fillOpacity: 0.2
}));

// 全部移除,组本身仍在地图上,可以继续加
group.clearLayers();

// 组一起下线
map.removeLayer(group);
group.addTo(map);   // 再上线,之前清空的图层不会回来

clearLayers() 只清空内容,不摘掉组;map.removeLayer(group) 摘掉组,组内所有图层随之从地图上消失,但组对象和它的子图层依然存在, 重新 addTo 时加回来的是当前保留的内容。

FeatureGroup:整体事件与范围

一组标记要共用一个点击处理,逐个绑定既啰嗦又容易漏。 绑在组上,事件会从子图层冒泡上来,e.layer 就是被点中的那个。

var stations = L.featureGroup([
  L.marker([39.907359, 116.391263]).bindTooltip('天安门'),
  L.marker([39.916345, 116.397155]).bindTooltip('王府井'),
  L.marker([39.899000, 116.407000]).bindTooltip('前门')
]).addTo(map);

stations.on('click', function (e) {
  var layer = e.layer;                 // 被点中的子图层
  var ll = layer.getLatLng();
  console.log(ll.lat, ll.lng);
});

map.fitBounds(stations.getBounds(), { padding: [24, 24] });

事件冒泡方向是单向的。子图层的事件会传到组,组上绑定的事件不会反过来触发到子图层。 e.layer 在组级监听里才有值,在单个标记的监听里没有这个字段。

pane:控制叠放层次

同一张地图上,不同图层落在不同的 pane(面板)里,pane 决定谁压谁。 默认 pane 与层级如下,数值越大越靠上:

pane 名称默认 z-index放什么
tilePane200瓦片底图
overlayPane400默认矢量图层、GeoJSON
shadowPane500标记阴影
markerPane600标记图标
tooltipPane650提示框
popupPane700弹窗
// 新建一个专门放注记的面板,压在标记之下
map.createPane('labels');
map.getPane('labels').style.zIndex = 550;
map.getPane('labels').style.pointerEvents = 'none';

L.marker([39.907359, 116.391263], { pane: 'labels' }).addTo(map);

pointerEvents: none 让这一层不接收鼠标,避免注记挡住下面的要素。 纯展示的文字层都应该这么设置。

注意事项

把 GeoJSON 当普通图层逐个加

L.geoJSON(data) 本身是 FeatureGroup,直接 addTo 即可。 再对每个 feature 建 L.polygon 逐个添加,等于放弃了 getBounds 与统一事件,也更容易在更新数据时漏删旧的图层。

用 clearLayers 之后没重置引用

清空后组对象仍可用,但如果代码里另存了某个子图层的引用,那个引用已经不在图上。 重新添加要再 addLayer 一次,否则点上去毫无反应。

指望 zIndex 跨 pane 生效

zIndex 只在同一个 pane 内的兄弟节点之间比较。 把两个图层的 z-index 调成 999 和 1,只要它们在不同 pane,结果仍由 pane 决定。

引用本文

经纬志(2026)。《图层与图层组》。https://www.jingweizhi.com/leaflet/tutorial/layers-groups.html(访问日期 2026-11-03)。