01 · NOTES / WebGIS 开发
第 01 节 · 第一张地图
2026 年 9 月 1 日
第 01 节 · 第一张地图
📌 版本信息:Leaflet 1.9.4(当前稳定版;2026-08-29 核对,官方 1.9 系列持续维护) 📚 来源:Leaflet Quick Start | Leaflet API 参考(本模块随查随用) | 中文站 leafletjs.cn 🎯 GIS 理论(模块 04)+ 前端能力(模块 02)正式合体——本节结束后,你将拥有第一张完全由自己代码驱动的地图。
一、这一节的目标
- 掌握 Leaflet 的两种引入方式(CDN / npm)与各自的适用场景
- 记住"Leaflet 三板斧":
L.map()→L.tileLayer()→ 加要素 - 掌握核心参数:中心/缩放/容器尺寸的三个经典坑
- 完成自己的第一张地图(并理解每一行在干什么)
二、Leaflet 是什么
一句话:Leaflet 是一个开源的轻量级 JavaScript 地图显示库(核心 ~42KB)——它不做数据、不做服务,只负责把"瓦片 + 要素"高效地画出来、交互起来。
定位对照(建立地图库世界观):
| 库 | 定位 | 体量 | 场景 |
|---|---|---|---|
| Leaflet | 轻量二维显示 | 42KB | 移动端友好、快速集成、中小数据 |
| OpenLayers | 全功能二维 | ~1MB | 企业级:投影/分析/复杂交互全都要 |
| MapLibre | 矢量瓦片 GL | ~800KB | 炫酷样式 + 大规模矢量 |
| Cesium | 三维地球 | MB 级 | 三维/倾斜摄影 |
选型口诀:先 Leaflet 后 OL,矢量瓦片上 MapLibre,三维上 Cesium。本课程按此顺序逐一交付。
三、引入方式与三板斧
<!-- 方式 ① CDN(练习/单页 demo 首选:双击即开,无需构建) -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<!-- 方式 ② npm(正式项目):
npm i leaflet
import L from 'leaflet'; import 'leaflet/dist/leaflet.css';
(打包器会把 CSS 一起处理;Vite 项目推荐这种) -->
<!-- 完整的第一张地图(每一行都认识才算过) -->
<body>
<div id="map" style="height: 90vh"></div> <!-- ① 容器:必须有高度! -->
<script>
// ② 地图实例:绑容器 + 初始中心与级别
const map = L.map('map', {
center: [30.5929, 114.3052], // ⚠️ [纬度, 经度]——与 GeoJSON 的 [lng,lat] 相反!
zoom: 10,
});
// ③ 底图瓦片层:加到地图上
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap 贡献者', // 版权声明:法律义务,别删
}).addTo(map);
// ④ 一个要素:标记 + 弹窗
L.marker([30.5929, 114.3052]).addTo(map).bindPopup('你好,WebGIS!');
</script>
</body>
三板斧口诀:L.map 定视野,tileLayer 铺底图,要素 addTo。 模块 04 的知识在此归位:URL 模板 {z}/{x}/{y} 由 Leaflet 在每次缩放/拖动时按第 02 节公式自动计算填充;[lat, lng] 顺序是 Leaflet 的 API 约定(GeoJSON 内部它也帮你按规范处理)。
四、三个经典坑(提前打疫苗)
| 坑 | 症状 | 原因与解法 |
|---|---|---|
| 地图不显示/灰块 | 容器里一片灰 | 容器高度为 0(div 默认高度 0)——CSS 给明确高度 |
| 瓦片错位/灰块 | 只加载出部分图 | 容器尺寸后来才变(如 flex 布局后算出)——map.invalidateSize() 通知重算 |
| 弹窗图标是碎图 | marker 显示 broken image | 打包器下 Leaflet 的图标资源路径丢失——L.Icon.Default.mergeOptions 或改用 DivIcon/CDN 图标(第 03 节细讲) |
五、动手跟练:01 · hello-map
配套文件:05-leaflet/examples/01-hello-map.html(CDN 版,双击即开)
步骤:
- 打开后对照文档读每一行;F12 Network 看瓦片请求(m00/模块 04 的知识复检:z/x/y 在动)
- 完成 6 个 TODO:改中心到你家乡、
map.flyTo([lat,lng], 14)飞行动画按钮、map.getZoom()/setZoom控制台实验、双击地图观察缩放(内置交互)、zoomControl: false关掉再手动加回、加第二张底图分层(预告第 02 节) - 观察实验:把容器 CSS 高度删掉,见证第一个坑
通关标准:
- 三板斧默写
- 能解释
[lat, lng]与 GeoJSON[lng, lat]的顺序差异 - flyTo/setView/setZoom 三个视野 API 用过
六、自测题
- Leaflet 的定位与三大竞品的一句话差异?
- 容器必须满足什么条件地图才显示?
L.map的 center 参数顺序?为什么和 GeoJSON 相反?- attribution 能删吗?
- 容器布局后尺寸变化,调用什么方法修正?
参考答案
- Leaflet=轻量二维;OL=全功能二维;MapLibre=矢量瓦片 GL;Cesium=三维。
- 有明确的高度(和宽度),且挂载时尺寸已确定。
[lat, lng];Leaflet API 沿用"纬度在前"习惯,而 GeoJSON RFC 规定 [lng, lat]——两套约定并存,注意翻译。- 不能——瓦片数据的版权署名义务(OSM 许可条款)。
map.invalidateSize()。
七、下一步
地图能看了 → 第 02 节:底图与瓦片源,把"底图从哪来"玩明白(providers 百宝箱 + 天地图接入)。