缩放到 17 级直接跳到 19 级,缺的两级全是灰块
滚轮滚一下,级别跳过 18 直接到 19,中间两级的地图从来没出现过。
现象
配置 minZoom: 10, maxZoom: 19,但滚轮每滚一格都跨两级:
从 17 直接到 19,控制台打印的 zoomend 也是 19。
17、18 级的瓦片请求从未发出,该区域一直是灰块。
触屏双指缩放更明显,一次手势能从 15 跳到 18。
原因
zoomSnap 决定缩放级别的最小步长,默认 1;
zoomDelta 决定滚轮一次的增量,默认 1。
但两者被外部代码改过,或者被 zoomSnap: 0.5 与
zoomDelta: 2 混用后,滚轮一次走两级。
另一个常见原因是 maxNativeZoom: 19 而
maxZoom: 21,18、19 级虽然存在但被跳过,
因为 zoomDelta 被设成了 2。
排查过程
- 在
zoomend里打印map.getZoom(),看每次变化的跨度。 - 打印
map.options.zoomSnap与map.options.zoomDelta。 - 检查是否有代码在运行时修改了
map.options。 - 用
map.setZoom(18)手动设置,看是否能停在 18 级。
map.on('zoomend', () => console.log(map.getZoom()));
// 15 -> 17 -> 19 每次 +2
console.log(map.options.zoomSnap, map.options.zoomDelta);
// 0.5 2 <- zoomDelta 为 2,滚轮一次跨两级
解决方案
zoomDelta 与 zoomSnap 要保持合理关系:
zoomDelta 不应小于 zoomSnap,且通常等于 1。
const map = L.map('map', {
center: [39.909, 116.397],
zoom: 15,
minZoom: 10,
maxZoom: 19,
zoomSnap: 0.5, // 允许半级缩放
zoomDelta: 1, // 滚轮一次一级
wheelPxPerZoomLevel: 120
});
// 瓦片只到 17 级时,用 maxNativeZoom 复用,不用提高 maxZoom
L.tileLayer('/tiles/{z}/{x}/{y}.png', {
minZoom: 10,
maxNativeZoom: 17,
maxZoom: 19
}).addTo(map);
连续平滑缩放需关闭 zoomSnap,此时要同时设置
wheelDebounceTime,否则一次滚轮会触发多次 zoom。
L.map('map', {
zoomSnap: 0,
zoomDelta: 0.25,
wheelDebounceTime: 40,
wheelPxPerZoomLevel: 60
});
验证
连续滚轮 5 次,zoomend 输出的级别序列为 15→16→17→18→19,逐级递增;
17、18 级瓦片都有请求记录,灰块消失。
const levels = [];
map.on('zoomend', () => levels.push(map.getZoom()));
// 滚动 5 次后
console.assert(levels.every((z, i) => i === 0 || Math.abs(z - levels[i - 1]) <= 1), '仍跨级');
console.assert(levels.at(-1) === 19, '未到最大级别');
适用版本
| 库 | 版本 | 默认值 |
|---|---|---|
| Leaflet | 1.9.x | zoomSnap: 1、zoomDelta: 1 |
| Leaflet | 1.7 / 1.8 | 同 |
| OpenLayers | 9.x | 用 View 的 constrainResolution 控制 |
经纬志(2026)。《缩放到 17 级直接跳到 19 级,缺的两级全是灰块》。https://www.jingweizhi.com/cookbook/minzoom-maxzoom-jump.html(访问日期 2026-11-03)。