插件生态与选型
Leaflet 核心只做地图容器、瓦片与基础矢量,绘制、聚合、测量、矢量瓦片全部靠插件。 插件质量参差,判断标准不是功能列表有多长,而是它有没有跟着 1.9 更新。
评估的四条硬指标
| 指标 | 怎么看 | 不合格的代价 |
|---|---|---|
| 最近提交时间 | 仓库近一年有无提交、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)。