经纬志
首页 / MapLibre / 教程

交互与控件

先看结论

控件是加在容器上的 DOM 按钮,交互是地图对鼠标与触摸的响应。 MapLibre 把每个交互做成可独立开关的 handler,事件则通过 map.on() 统一分发。

最后验证 2026-11-03 · MapLibre GL JS 4.x · 更新 2026-10-29 · 引用本文

内置控件

控件作用常用参数
NavigationControl缩放按钮与指南针showCompass、visualizePitch
ScaleControl比例尺unit: 'metric'、maxWidth
GeolocateControl定位按钮trackUserLocation、positionOptions
AttributionControl版权信息compact
TerrainControl地形开关source、exaggeration
var map = new maplibregl.Map({
  container: 'map',
  style: 'https://demotiles.maplibre.org/style.json',
  center: [116.391263, 39.907359],
  zoom: 5,
  attributionControl: false      // 先关掉,改用自定义位置
});

map.addControl(new maplibregl.NavigationControl({
  showCompass: true,
  visualizePitch: true
}), 'top-right');

map.addControl(new maplibregl.ScaleControl({
  unit: 'metric',
  maxWidth: 120
}), 'bottom-left');

map.addControl(new maplibregl.GeolocateControl({
  positionOptions: { enableHighAccuracy: true },
  trackUserLocation: true
}), 'top-right');

map.addControl(new maplibregl.AttributionControl({
  compact: true
}), 'bottom-right');

位置参数只有四个:top-left、top-right、 bottom-left、bottom-right。同一角落多次添加时, 控件按添加顺序堆叠,DOM 顺序不影响它们在地图上的层级。

交互开关

每个交互都是一个 handler 对象,可以 enable()、 disable()、isEnabled()。 当业务需要「地图只读」时,逐个关掉比在容器上盖一层遮罩更可靠。

handler默认作用
dragPan开启鼠标拖动与单指拖动平移
scrollZoom开启滚轮缩放
dragRotate开启右键或 Ctrl 拖动旋转与倾斜
doubleClickZoom开启双击放大
touchZoomRotate开启双指缩放与旋转
touchPitch开启双指上下滑动改变倾角
boxZoom开启按住 Shift 拖框放大
keyboard开启方向键平移
// 内嵌在可滚动页面里的地图:保留拖动,关掉滚轮缩放
map.scrollZoom.disable();
map.doubleClickZoom.disable();
map.boxZoom.disable();

// 展示态:全部只读
function setReadOnly(readonly) {
  ['dragPan', 'scrollZoom', 'dragRotate', 'doubleClickZoom',
   'touchZoomRotate', 'touchPitch', 'boxZoom', 'keyboard'
  ].forEach(function (name) {
    if (readonly) map[name].disable();
    else map[name].enable();
  });
}

点击查询要素

事件本身不带要素信息,要拿到被点中的东西必须调用 queryRenderedFeatures。它查询的是当前已渲染的要素, 视野外的数据查不到。

map.on('click', function (e) {
  var features = map.queryRenderedFeatures(e.point, {
    layers: ['sites-circle']        // 限定图层,避免命中底图
  });

  if (features.length === 0) {
    new maplibregl.Popup().remove();
    return;
  }

  var f = features[0];
  new maplibregl.Popup({ closeButton: false })
    .setLngLat(f.geometry.coordinates)
    .setHTML('<b>' + f.properties.name + '</b>')
    .addTo(map);
});

// 图层级事件:直接拿到要素,且只在命中时触发
map.on('mouseenter', 'sites-circle', function () {
  map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'sites-circle', function () {
  map.getCanvas().style.cursor = '';
});

layers 参数非常关键。不限定图层时,点击会返回鼠标位置下所有图层的结果, 包括底图的国界、道路,取 features[0] 常常拿到不想处理的那个。

事件对象里有什么

字段含义注意
e.lngLat经纬度顺序是 [lng, lat]
e.point相对容器左上角的像素{x, y}
e.features命中的要素数组图层级事件里才有
e.originalEvent原生 DOM 事件取 shiftKey 等修饰键
e.preventDefault()阻止默认行为在 click 上不能阻止地图平移

注意事项

图层级监听在图层创建前绑定

map.on('click', 'layer-id', fn) 里的图层 id 必须已经存在。 在 load 之前绑定,事件永远不会触发,也不会报错。

queryRenderedFeatures 的高频调用

在 mousemove 里每帧查询要素,会拖慢整个渲染循环。 用 requestAnimationFrame 或时间间隔节流到 60 毫秒一次, 并把 layers 收窄到真正需要的图层。

控件被容器样式影响

控件按钮依赖 maplibre-gl.css 定位。页面里用全局 button { ... } 改写按钮样式,会把缩放按钮挤成方块。 用 .maplibregl-ctrl 前缀的类做局部覆盖。

引用本文

经纬志(2026)。《交互与控件》。https://www.jingweizhi.com/maplibre/tutorial/interactions-controls.html(访问日期 2026-11-03)。