返回笔记列表
01 · NOTES / WebGIS 开发

第 09 节 · 类体系全景

2026 年 9 月 1 日

第 09 节 · 类体系全景

📌 版本信息:Leaflet 1.9.4(2026-08-29 核对) 📚 本地教材:resources/05-leaflet/Leaflet/src/(源码目录,本节的地图) | Leaflet API 参考 🎯 阶段二开篇——把散落在阶段一的 API 挂回"类树"上,读源码不再迷路。

一、这一节的目标

  1. 掌握 Leaflet 的类树主干:Map / Layer 家族 / Control 家族 / CRS 家族
  2. 理解 L.Class.extend 的继承机制与 options 合并模式
  3. 会带着源码目录找实现("这个方法的源码在哪"的能力)

二、类树主干(背下这张图)

L.Map                      ← 地图本体(你唯一的"应用对象")
├── panes / _layers        内部:渲染分区与图层注册表
L.Evented                  ← 事件基类(Map/Layer/Control 全继承它!)
├── L.Layer                ← 所有图层的抽象基类
│   ├── L.TileLayer        瓦片底图(GridLayer 子类)
│   ├── L.GeoJSON          ← L.FeatureGroup 子类(数据进出的门户)
│   ├── L.FeatureGroup     ← L.LayerGroup + 交互/样式
│   ├── L.LayerGroup       纯分组
│   ├── L.Path             矢量基类(SVG/Canvas 渲染的公共逻辑)
│   │   ├── Polyline / Polygon / Rectangle / Circle / CircleMarker
│   ├── L.Marker           标记(图标 + 交互,非 Path 体系)
│   └── L.ImageOverlay / VideoOverlay / WMS
L.Control                  ← 控件基类(zoom/scale/layers/attribution…)
L.CRS                      ← 坐标系基类(EPSG3857/4326/Simple)
L.Icon / L.DivIcon         ← 图标
L.LatLng / L.LatLngBounds  ← 基础值对象(不可变)
L.Bounds / L.Point         ← 像素坐标值对象

三个阅读收益

  1. Evented 是万物之祖:所以 map.on / layer.on / marker.off 全套事件 API 通用——查事件 API 只查 Evented 一节
  2. GeoJSON 是 FeatureGroup 的子类:所以第 05/07 节的 Group 能力(fitBounds/clearLayers/addData)它全有——API 参考不用重复看
  3. Path 是矢量公共父类setStyle/getBounds/bindTooltip 定义在此——Polyline/Polygon/Circle 通用

三、L.Class.extend:继承与 options 模式

Leaflet 没用 ES class,用自己实现的 L.Class(比 ES class 早十年,且提供独有的 options 合并机制):

// 自定义"图层"的标准写法(第 07 节 Control.extend 同款机制)
const NeonMarker = L.Marker.extend({
  options: {                                  // 与父类 options 深合并(覆盖同名项)
    pulse: true,                              // 自己的新选项
  },
  initialize(latlng, options) {               // 构造器(new 时调用)
    L.Marker.prototype.initialize.call(this, latlng, options);   // 调父类构造
    if (this.options.pulse) { /* 附加逻辑 */ }
  },
  blink() { console.log('眨眼'); },            // 新方法(挂在原型上,实例共享)
});
new NeonMarker([30.59, 114.31]).addTo(map).blink();

读懂三个模式:①options 深合并(子类只写差异项);②initialize 是构造器名(不是 constructor);③L.XXX.prototype.method.call(this) 手动调父类——ES5 风格继承,源码里遍地都是。


四、源码目录导航(resources/05-leaflet/Leaflet/src/)

src/
├── map/        Map.js(本体,2000+ 行)+ handler(交互:拖拽/滚轮/双击缩放…)
├── layer/      layer.js(Layer 基类)→ marker/ vector/ tile/(三大分支各一文件夹)
│   └── vector/ Path._project/_update —— 渲染器原理的入口(第 11 节)
├── geometry/   Point/Bounds/LatLngTransformation(纯数学,无 DOM)
├── geo/        CRS/投影/LatLng(模块 04 的代码落地)
├── control/    Control.js 与各内置控件
├── core/       Class.js(继承机制)/ Util / Events
└── dom/        DOM 封装(跨浏览器兼容层)

查源码的标准姿势:API 文档里看到某方法 → 全局搜方法名(如 invalidateSize)→ 读实现 + 附近注释。Leaflet 源码注释密度高、风格干净,是前端开源库中最好的读物之一。


五、自测题

  1. Leaflet 万物之祖(事件来源)是哪个类?
  2. GeoJSON 类的父类链?这带来什么 API 复用?
  3. Path 基类覆盖哪些具体图层?意味着什么 API 通用?
  4. L.Class 的 options 合并机制对子类意味着什么?
  5. 想看"拖拽地图"的实现,去 src 哪个目录?

参考答案

  1. L.Evented——Map/Layer/Control 都继承它(on/off/once/fire 全套)。
  2. GeoJSON → FeatureGroup → LayerGroup → Layer → Evented;Group 全套 API(fitBounds/clearLayers/addData/控件注册)直接可用。
  3. Polyline/Polygon/Rectangle/Circle/CircleMarker;setStyle/bindTooltip/getBounds 等一份定义多处复用。
  4. 子类只声明差异项,与父类 options 深合并——子类 options 精简且默认值自动继承。
  5. src/map/handler/(Dragging.js 等交互处理器都在这)。

六、下一步

类树在手 → 第 10 节:CRS 详解,把"坐标系"落到 Leaflet 的代码结构。