经纬志
首页 / Leaflet / 教程

插件生态与选型

先看结论

Leaflet 核心只做地图容器、瓦片与基础矢量,绘制、聚合、测量、矢量瓦片全部靠插件。 插件质量参差,判断标准不是功能列表有多长,而是它有没有跟着 1.9 更新。

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

评估的四条硬指标

指标怎么看不合格的代价
最近提交时间仓库近一年有无提交、issue 有无回复遇到浏览器升级就只能自己改源码
声明的兼容版本README 或 peerDependencies 是否覆盖 1.9用到 1.9 才有的 rotateOrigin 等能力时直接失效
是否自带 CSS包里有没有 .css 需要一并引入控件样式错位,看起来像布局 bug
是否改写全局是否给 L 挂新命名空间多个插件命名冲突,加载顺序敏感

前两条能过滤掉大部分坑。Leaflet 1.x 的 API 在 1.7 之后基本稳定, 一个 2016 年之后没动过的插件,往往还能跑,但遇到高分屏、触摸设备与现代打包工具时, 问题需要自己兜底。

常见类别的选择

需求常见插件说明
大量点聚合Leaflet.markercluster与 1.9 兼容,需额外引入 CSS
矢量绘制编辑Leaflet-Geoman、Leaflet.draw后者停更较早,新项目优先前者
热力图leaflet.heat基于 canvas,点数上万仍可用
矢量瓦片Leaflet.VectorGrid能读 MVT,样式需自行映射
测量工具leaflet-measure距离与面积,依赖 Turf 风格的球面算法
全屏 / 侧栏leaflet-fullscreen、leaflet-sidebar-v2都是控件,注意与自有 UI 的层级

以聚合插件为例的完整接入

插件一般只需两件事:在 Leaflet 之后加载脚本,把图层换成插件提供的类型。 聚合插件额外要求引入它自己的 CSS,漏掉时聚合数字会显示在错误的位置。

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet.markercluster@1.5.3/dist/MarkerCluster.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet.markercluster@1.5.3/dist/MarkerCluster.Default.css">

<script src="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://cdn.jsdelivr.net/npm/leaflet.markercluster@1.5.3/dist/leaflet.markercluster.js"></script>

<script>
  var map = L.map('map').setView([39.907359, 116.391263], 10);

  var clusters = L.markerClusterGroup({
    maxClusterRadius: 60,
    spiderfyOnMaxZoom: true,
    showCoverageOnHover: false
  });

  points.forEach(function (p) {
    clusters.addLayer(L.marker([p.lat, p.lng]));
  });

  map.addLayer(clusters);   // 一次性加入,别逐个 addTo(map)
</script>

逐点 addTo(map) 再交给聚合组是常见写错方式:每个点都会先单独渲染一次, 再被聚合层接管,首屏会明显卡顿。先把点加进组,最后把组加到地图。

加载顺序与可用性探测

插件都依赖 window.L,顺序错会得到 L.markerClusterGroup is not a function。用 defer 或模块打包时,顺序更容易乱。加载完成后做一次探测,比让页面静默失败要好。

function hasPlugin(name) {
  return typeof L !== 'undefined' && typeof L[name] === 'function';
}

if (hasPlugin('markerClusterGroup')) {
  map.addLayer(buildClusters(points));
} else {
  // 退化为普通图层组,功能降级但地图仍可用
  map.addLayer(L.layerGroup(points.map(function (p) {
    return L.circleMarker([p.lat, p.lng], { radius: 4 });
  })));
}

注意事项

插件版本与 Leaflet 版本脱钩

插件复制粘贴的是旧示例,而 Leaflet 已经升到 1.9。反过来,插件内部用了 L.Util.template 等内部方法的旧签名,也会静默失效。 锁定 Leaflet 与插件版本,是唯一省事的做法。

插件自带样式被全局 CSS 覆盖

聚合图标、绘制工具栏都靠插件 CSS 定位。项目里一条 .leaflet-control { ... } 的全局规则就可能把它们挤走。 用容器选择器限定作用范围,不要直接改 .leaflet-* 前缀的类。

把插件当核心依赖

绘制、测量这类交互,若产品长期维护,评估自己实现核心部分往往更稳: 插件停更时,替换成本远高于当初少写的几百行代码。

引用本文

经纬志(2026)。《插件生态与选型》。https://www.jingweizhi.com/leaflet/tutorial/plugins.html(访问日期 2026-11-03)。