文章目录
- 前言
- 一、基本概念
- 二、 显示地图的基本HTML
- 三、核心类与方法
-
- 2.2 地图操作
- 3.2 图层系统
- 3.3 弹出信息
- 四、事件系统
- 五、自定义样式
-
- 5.1 图标
- 5.2 样式选项
- 六、图层控制
- 七、GeoJSON 数据
- 八、常用配置
- 九、坐标系注意事项
- 十、性能优化要点
- 十一、常用插件
- 总结
前言
Leaflet作为一个轻量级、开源的JavaScript地图库,以其简洁的API和强大的功能成为Web地图开发的首选。本文将从零开始,通过实用示例和代码解析,帮助开发者快速掌握Leaflet的核心用法,包括地图显示、标记添加、事件处理等关键技能,特别针对国内高德地图服务的应用进行详细说明。
一、基本概念
| 地图实例 | Leaflet 地图的核心对象 | L.map('container') |
| 经纬度 | [纬度, 经度] 坐标格式 | [39.9, 116.4](北京) |
| 缩放级别 | 数字越大越详细,通常 0-18 | zoom: 13 |
| 地图瓦片 | 256×256 像素的正方形地图图片,拼接成完整地图 | https://…/z=13&x=843&y=386.png(地图瓦片的网络请求 URL) |
| 瓦片图层 | 地图底图,由小图片拼接 | L.tileLayer(url) |
| 图层 | 地图上可叠加的元素统称 | 标记、线、面都是图层 |
地图瓦片的网络请求URL(https://…/z=13&x=843&y=386.png)详解:
y=386:纵向第 386 块瓦片 x=843:横向第 843 块瓦片 z=13:Zoom 13(详细级别) …:瓦片服务器域名 https:网络协议
二、 显示地图的基本HTML
后续内容基于此进行补充解析。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>高德地图 – Leaflet</title>
<!– Leaflet CSS –>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<style>
body {
margin: 0;
padding: 0;
}
#map {
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<div id="map"></div>
<!– Leaflet JS –>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
// 初始化地图(北京天安门)
var map = L.map('map').setView([39.9042, 116.4074], 13);
// 添加高德地图瓦片
L.tileLayer('https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', {
subdomains: ['1', '2', '3', '4'],
attribution: '© 高德地图'
}).addTo(map);
</script>
</body>
</html>
效果展示: 
三、核心类与方法
2.2 地图操作
// 创建地图
var map = L.map('mapId', {
center: [39.9, 116.4], // 中心点
zoom: 13, // 初始缩放(地图第一次显示时的详细程度)
minZoom: 3, // 最小缩放
maxZoom: 18 // 最大缩放
});
// 视图控制
map.setView([lat, lng], zoom); // 设置视图
map.flyTo([lat, lng], zoom); // 平滑飞入动画
map.getZoom(); // 获取当前缩放级别
map.getCenter(); // 获取当前中心点
// 销毁地图(重要!)
map.remove();
| Vue 热更新 | 代码修改后组件重新挂载 |
| 路由切换 | 从地图页跳转到其他页面 |
| 弹窗关闭 | 地图在弹窗里,弹窗关闭 |
| 标签页切换 | 单页应用动态加载不同组件 |
| 效果 | 瞬间切换 | 平滑飞过去 |
| 动画 | 无 | 有 |
| 用户体验 | 突兀 | 流畅自然 |
| 用途 | 初始化、快速定位 | 场景切换、导航 |
3.2 图层系统
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
// 标记点
L.marker([lat, lng]).addTo(map);
// 圆形
L.circle([lat, lng], {radius: 500}).addTo(map);
// 多边形
L.polygon([[lat1,lng1], [lat2,lng2], [lat3,lng3]]).addTo(map);
// 折线
L.polyline([[lat1,lng1], [lat2,lng2]]).addTo(map);
// 矩形
L.rectangle([[lat1,lng1], [lat2,lng2]]).addTo(map);
添加高德地图瓦片实际应用:
// 加载高德地图
L.tileLayer('https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', {
subdomains: ['1', '2', '3', '4'],
attribution: '© 高德地图',
maxZoom: 17, // 最大缩放级别,因为高德地图最大级别为18,而zoomOffset为1,所以Leaflet的最大级别设置为17
minZoom: 3, // 最小缩放级别
tileSize: 256, // 瓦片大小
zoomOffset: 1 // 缩放偏移
}).addTo(map);
// URL 模板中的 {s} 会被 subdomains 数组中的值替换
'https://webrd0{s}.is.autonavi.com/…'
// 实际请求会变为:
https://webrd01.is.autonavi.com/…
https://webrd02.is.autonavi.com/…
https://webrd03.is.autonavi.com/…
https://webrd04.is.autonavi.com/…
添加标记点:
L.marker([39.9042, 116.4074]).addTo(map);
圆形:
L.circle([39.9042, 116.4074], { radius: 500 }).addTo(map);

3.3 弹出信息
// 绑定弹窗
marker.bindPopup('<b>标题</b><br>内容').openPopup();
// 绑定提示
marker.bindTooltip('提示文字').openTooltip();
实际用法:
var marker = L.marker([39.9, 116.4]).addTo(map);
marker.bindPopup(`
<div style="text-align:center;">
<h3>天安门</h3>
</div>
`).openPopup(); // 创建后直接打开

var marker = L.marker([39.9, 116.4]).addTo(map);
marker.bindTooltip('hello~').openTooltip();

| 外观 | 气泡框,带箭头 | 小标签,简约 |
| 触发方式 | 点击标记 | 鼠标悬停 |
| 关闭方式 | 点击地图其他地方或×按钮 | 鼠标移出 |
| 内容量 | 较多(HTML支持) | 较少(纯文本为主) |
| 适用场景 | 详细信息展示 | 快速预览名称 |
四、事件系统
// 地图事件
map.on('click', function(e) {
console.log('点击坐标:', e.latlng);
});
map.on('zoomend', function() {
console.log('缩放结束:', map.getZoom());
});
map.on('moveend', function() {
console.log('移动结束:', map.getCenter());
});
// 标记事件
marker.on('click', function() {
console.log('点击了标记');
});
// 解除事件
map.off('click');
实际应用:
map.on('click', function (e) {
alert('坐标: ' + e.latlng.lat.toFixed(4) + ', ' + e.latlng.lng.toFixed(4));
});
点击地图时触发:
缩放地图时触发:
map.on('zoomend', function () {
var center = map.getCenter(); // 获取地图中心坐标
alert('格式化地图中心坐标(保留4位小数): ' + center.lat.toFixed(4) + ', ' + center.lng.toFixed(4));
});
移动地图时触发:
map.on('moveend', function () {
var center = map.getCenter();
alert('移动结束,中心: ' + center.lat.toFixed(4) + ', ' + center.lng.toFixed(4));
});
点击标记点时触发:
marker.on('click', function () {
alert('点击了标记');
});

五、自定义样式
5.1 图标
// 自定义 Div 图标
var myIcon = L.divIcon({
className: 'custom-icon',
html: '<div style="background:red;width:20px;height:20px;"></div>',
iconSize: [20, 20],
iconAnchor: [10, 10]
});
L.marker([lat, lng], {icon: myIcon}).addTo(map);
5.2 样式选项
// 多边形样式
L.polygon(coords, {
color: 'red', // 边框颜色
weight: 3, // 边框宽度
opacity: 0.5, // 边框透明度
fillColor: 'blue', // 填充颜色
fillOpacity: 0.2 // 填充透明度
});
实际应用:
var simpleIcon = L.divIcon({
html: '<div style="background:red;width:20px;height:20px;"></div>',
iconSize: [20, 20]
});
// 使用
L.marker([39.9042, 116.4074], { icon: simpleIcon }).addTo(map);

六、图层控制
// 创建图层组
var layerGroup = L.layerGroup().addTo(map);
// 添加多个标记到组
layerGroup.addLayer(marker1);
layerGroup.addLayer(marker2);
// 整体控制
layerGroup.clearLayers(); // 清空所有
layerGroup.removeLayer(marker1); // 移除单个
// 图层切换(显示/隐藏)
if (map.hasLayer(layer)) {
map.removeLayer(layer);
} else {
map.addLayer(layer);
}
实际应用示例:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<style>
#map {
height: 100vh;
}
.controls {
position: fixed;
top: 10px;
left: 50%;
transform: translateX(–50%);
z–index: 1000;
background: white;
padding: 10px;
border–radius: 5px;
box–shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
button {
margin: 0 5px;
padding: 8px 15px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="controls">
<button onclick="addRandomMarker()">添加标记</button>
<button onclick="toggleMarkers()">显示/隐藏标记</button>
<button onclick="clearAllMarkers()">清除所有标记</button>
<button onclick="countMarkers()">统计标记数</button>
</div>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
// 初始化地图
var map = L.map('map').setView([39.9042, 116.4074], 13);
// 添加高德地图
L.tileLayer('https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', {
subdomains: ['1', '2', '3', '4'],
attribution: '© 高德地图'
}).addTo(map);
// 1. 创建图层组(最核心的一步)
var markerGroup = L.layerGroup().addTo(map);
// 2. 添加标记到图层组的函数
function addRandomMarker() {
// 生成随机位置(天安门附近)
var lat = 39.9042 + (Math.random() – 0.5) * 0.1;
var lng = 116.4074 + (Math.random() – 0.5) * 0.1;
// 创建标记
var marker = L.marker([lat, lng])
.bindPopup('标记 ' + (markerGroup.getLayers().length + 1));
// 添加到图层组(关键!)
markerGroup.addLayer(marker);
console.log('添加了标记,总数:', markerGroup.getLayers().length);
}
// 3. 切换显示/隐藏
function toggleMarkers() {
if (map.hasLayer(markerGroup)) {
map.removeLayer(markerGroup);
console.log('已隐藏所有标记');
} else {
map.addLayer(markerGroup);
console.log('已显示所有标记');
}
}
// 4. 清除所有标记
function clearAllMarkers() {
markerGroup.clearLayers();
console.log('已清除所有标记');
}
// 5. 统计标记数量
function countMarkers() {
var count = markerGroup.getLayers().length;
alert('当前有 ' + count + ' 个标记');
console.log('标记数量:', count);
}
// 初始化添加3个标记
addRandomMarker();
addRandomMarker();
addRandomMarker();
</script>
</body>
</html>
七、GeoJSON 数据
// 加载 GeoJSON(行政区划、边界等)
var geojsonData = {
"type": "Feature",
"properties": {"name": "区域A"},
"geometry": {
"type": "Polygon",
"coordinates": [[[lng1,lat1], [lng2,lat2], [lng3,lat3]]]
}
};
L.geoJSON(geojsonData, {
style: function(feature) {
return {color: feature.properties.color};
},
onEachFeature: function(feature, layer) {
layer.bindPopup(feature.properties.name);
}
}).addTo(map);
实际应用:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<style>
#map {
height: 100vh;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
var map = L.map('map').setView([39.9042, 116.4074], 14);
L.tileLayer('https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', {
subdomains: ['1', '2', '3', '4'],
attribution: '© 高德地图'
}).addTo(map);
// 最简单的GeoJSON数据:一个三角形
var triangle = {
"type": "Feature", // 1. 这是一个"地理要素"
"properties": { // 2. 这个要素的属性(非地理信息)
"name": "天安门三角区", // 名称:天安门三角区
"color": "blue" // 颜色:蓝色
},
"geometry": { // 3. 这个要素的地理形状(核心部分)
"type": "Polygon", // 类型:多边形
"coordinates": [[ // 坐标数组
[116.4074, 39.9042], // 点1:天安门(经度, 纬度)
[116.4100, 39.9020], // 点2:右下角
[116.4048, 39.9020], // 点3:左下角
[116.4074, 39.9042] // 点4:回到起点(闭合)
]]
}
};
// 添加到地图
L.geoJSON(triangle, { // 1. 加载三角形数据
style: { // 2. 设置外观样式
color: "blue", // 边框颜色:蓝色
fillColor: "lightblue", // 填充颜色:浅蓝色
fillOpacity: 0.4, // 填充透明度:40%(能看到下面的地图)
weight: 2 // 边框粗细:2像素
},
onEachFeature: function (feature, layer) { // 3. 设置交互功能
layer.bindPopup("区域名称: " + feature.properties.name); // 点击时弹窗显示名字
}
}).addTo(map); // 4. 添加到地图上
</script>
</body>
</html>
八、常用配置
| zoomControl | 显示缩放按钮 | true |
| attributionControl | 显示版权信息 | true |
| scrollWheelZoom | 滚轮缩放 | true |
| doubleClickZoom | 双击缩放 | true |
| dragging | 允许拖拽 | true |
// 禁用默认控件
var map = L.map('map', {
zoomControl: false,
attributionControl: false
});
// 手动添加缩放控件到右下角
L.control.zoom({position: 'bottomright'}).addTo(map);
九、坐标系注意事项
| WGS84 | GPS 标准坐标 [lng, lat] | 国际标准、Leaflet 默认 |
| GCJ-02 | 国测局坐标(火星坐标) | 高德、腾讯地图(中国) |
| BD-09 | 百度坐标 | 百度地图 |
重要:高德瓦片用 GCJ-02,但 Leaflet 默认 WGS84,直接叠加会有几百米偏差。国内项目建议统一使用同一坐标系,或使用转换库。
十、性能优化要点
十一、常用插件
| leaflet.markercluster | 标记点聚合 |
| leaflet-draw | 绘制工具(画线、画面) |
| leaflet-heat | 热力图 |
| leaflet-chinese-tms | 中国地图瓦片修正 |
| leaflet-geoman | 高级几何编辑 |
总结
通过本文学习,您已经掌握了Leaflet地图开发的核心技能。从基础的地图显示到交互功能实现,再到图层管理和数据可视化,这些知识为您构建各类WebGIS应用打下了坚实基础。记住实践是最好的学习方式,不断尝试和探索将使您的地图开发能力不断提升。




