控件
本文档涵盖 Leaflet 中的控件系统,它提供定位在地图角落的 UI 小部件。它解释了 Control 基类、定位系统、生命周期管理以及创建自定义控件的模式。关于地图交互处理器(拖拽、缩放、键盘)的信息,请参阅 地图交互处理器。
控件架构
Control 类为 UI 小部件提供基础实现,这些小部件定位在地图的固定位置(通常在角落)。与图层不同,控件不参与地理坐标系统,而是锚定到地图容器的边缘。
关键区别:控件扩展 Class,而不是 Layer。它们不参与图层系统,无论缩放级别或 pane 配置如何,始终可见。
定位系统
控件定位在地图的四个角落容器之一中。定位系统在创建地图时初始化,并为每个角落提供专用的 DOM 容器。
角落位置
| 位置字符串 | 位置 | 默认控件 |
|---|---|---|
'topleft' | 左上角 | 缩放控件 |
'topright' | 右上角 | (如果未指定则为默认位置) |
'bottomleft' | 左下角 | 比例尺控件 |
'bottomright' | 右下角 | 归属控件 |
实现细节:地图通过 _initControlPos() 在初始化期间创建四个角落容器。每个角落都是一个带有 CSS 类的 <div> 元素,通过 flexbox 或绝对定位处理定位。
Control 基类
Control 类提供定位和生命周期管理的核心功能。所有控件必须实现 onAdd 方法,并可选实现 onRemove。
构造函数和选项
// 默认选项
{
position: 'topright' // 初始角落位置
}构造函数接受一个选项对象,使用 Util.setOptions() 与默认值合并。
核心方法
| 方法 | 描述 | 返回 |
|---|---|---|
getPosition() | 返回当前位置字符串 | string |
setPosition(position) | 更改控件的位置 | this |
getContainer() | 返回控件的 DOM 元素 | HTMLElement |
addTo(map) | 将控件添加到地图 | this |
remove() | 从其地图移除控件 | this |
位置更改行为:当调用 setPosition() 时,控件从其当前角落移除(如果在地图上),并重新添加到新角落。这确保正确的 DOM 顺序和 CSS 应用。
控件生命周期
控件在被添加到地图或从地图移除时遵循特定的生命周期模式。
生命周期方法
onAdd(map: LeafletMap): HTMLElement (必需)
- 必须由子类实现
- 应该创建并返回控件的容器 DOM 元素
- 应该根据需要向地图或 DOM 元素添加事件监听器
- 在控件添加到地图时调用
onRemove(map: LeafletMap): void (可选)
- 应该清理事件监听器和资源
- 在控件从地图移除时调用
- 如果控件不需要清理则不需要
插入顺序:具有 'bottom' 位置的控件通过 insertBefore 插入到其角落容器的开头,而 'top' 位置则附加到末尾。这确保正确的视觉堆叠顺序。
地图集成
地图通过专用方法和 DOM 结构为托管控件提供基础设施。
地图方法
控件容器结构:地图在初始化期间创建单个控件容器(_controlContainer),其中容纳所有四个角落容器(_controlCorners)。此结构由 _initControlPos() 创建,并在地图销毁时由 _clearControlPos() 清理。
角落容器创建
_initControlPos() 方法创建角落基础设施:
- 创建带有类
'leaflet-control-container'的主控件容器 - 创建四个角落 div,每个都有两个 CSS 类用于定位:
- 垂直:
'leaflet-top'或'leaflet-bottom' - 水平:
'leaflet-left'或'leaflet-right'
- 垂直:
- 在
_controlCorners对象中存储引用,键为:'topleft'、'topright'、'bottomleft'、'bottomright'
内置控件
Leaflet 包括几个扩展 Control 基类的内置控件实现:
| 控件 | 用途 | 默认位置 |
|---|---|---|
Control.Zoom | 放大/缩小按钮 | 'topleft' |
Control.Attribution | 版权和数据归属 | 'bottomright' |
Control.Layers | 底图和覆盖图层的图层切换器 | 'topright' |
Control.Scale | 显示地图比例的比例尺 | 'bottomleft' |
注意:这些内置控件的实现文件未包含在提供的源代码中,但它们都遵循相同的模式,即扩展 Control 并实现 onAdd() 和可选的 onRemove()。
创建自定义控件
自定义控件遵循基于 Control 基类的一致模式。
基本模式
实现要求
必需方法:onAdd(map)
- 必须返回表示控件的
HTMLElement - 应该为控件的 UI 创建 DOM 元素
- 应该向地图或 DOM 元素附加事件监听器
- 接收地图实例作为参数
可选方法:onRemove(map)
- 应该移除在
onAdd中添加的事件监听器 - 应该清理任何资源或定时器
- 接收地图实例作为参数
辅助功能辅助:_refocusOnMap(e)
- 可用于在控件交互后将焦点移回地图
- 排除键盘发起的点击(位置 0,0)以将焦点保持在控件上以辅助功能
- 可在控件事件处理器中使用
示例结构
自定义控件通常遵循此结构:
- 类定义:扩展
Control类 - 默认选项:通过
setDefaultOptions()的静态块设置 - 初始化:可选的
initialize()方法用于构造函数逻辑 - DOM 创建:
onAdd()创建并返回控件的容器 - 事件绑定:向地图事件或控件 UI 附加监听器
- 清理:
onRemove()移除监听器并清理资源
位置选项:自定义控件继承基类的 position 选项,允许用户将控件放置在任何角落。
控件与图层比较
理解控件和图层之间的区别对于选择正确的抽象很重要:
| 方面 | 控件 | 图层 |
|---|---|---|
| 基类 | Control 扩展 Class | Layer 扩展 Evented |
| 定位 | 固定到地图角落 | 地理坐标 |
| DOM 位置 | 控件容器中的控制角落 | Panes(tilePane、overlayPane 等) |
| 缩放行为 | 始终以相同大小可见 | 可能缩放或有缩放限制 |
| 主要用途 | UI 小部件和工具 | 地图数据和地理要素 |
| 集成 | map.addControl() / control.addTo() | map.addLayer() / layer.addTo() |
| 必需方法 | onAdd(map): HTMLElement | onAdd(map): void |
| 归属 | 不适用 | getAttribution() 用于归属控件 |
关键洞察:控件是用于与地图本身交互的 UI 元素,而图层代表要在地图上显示的地理数据。为工具和窗口小部件选择 Control,为数据可视化选择 Layer。
技术细节
DOM 结构
当控件添加到地图时,它们创建特定的 DOM 层次结构:
map._container (地图容器)
└── map._controlContainer (类: leaflet-control-container)
├── map._controlCorners['topleft'] (类: leaflet-top leaflet-left)
│ └── control._container (类: leaflet-control)
├── map._controlCorners['topright'] (类: leaflet-top leaflet-right)
├── map._controlCorners['bottomleft'] (类: leaflet-bottom leaflet-left)
└── map._controlCorners['bottomright'] (类: leaflet-bottom leaflet-right)
└── control._container (类: leaflet-control)类分配
每个控件的容器元素自动接收 CSS 类 'leaflet-control',它为控件提供默认样式(通常包括背景、边框和内边距)。
自动清理
控件在地图触发 'unload' 事件时自动注册清理。这确保在地图销毁时正确移除控件,防止内存泄漏。