01 · NOTES / WebGIS 开发
第 03 节 · 标记与图标
2026 年 9 月 1 日
第 03 节 · 标记与图标
📌 版本信息:Leaflet 1.9.4(2026-08-29 核对) 📚 来源:Leaflet Icon 文档 | DivIcon 🎯 地图上的"要素"从标记开始:默认图标、自定义图片、HTML 图标三种形态全覆盖。
一、这一节的目标
- 精通
L.marker的常用 options(draggable / opacity / title / zIndexOffset) - 掌握三种图标方案:默认 Icon(含打包器碎图修复)/ L.icon 图片 / L.divIcon(HTML/CSS 图标——最灵活)
- 理解
iconAnchor与popupAnchor的锚点数学 - 完成兴趣点标记页
二、marker 的常用 options
const marker = L.marker([30.5929, 114.3052], {
draggable: true, // 可拖动(拖完 marker.getLatLng() 拿新位置——选点功能的基础)
autoPan: true, // 拖到边缘时地图自动平移
opacity: 0.9,
title: '悬停提示(原生 title)',
alt: '无障碍描述',
zIndexOffset: 1000, // 重叠时谁在上(越大越上)
riseOnHover: true, // 悬停置顶
}).addTo(map);
marker.getLatLng(); // → LatLng 对象(.lat / .lng)
marker.setLatLng([新纬, 新经]); // 移动
marker.on('dragend', (e) => console.log(e.target.getLatLng())); // 拖完回调——"点选坐标"组件的雏形
三、三种图标方案
// ① 默认图标——打包器(Vite/webpack)下会"碎图"!
// 原因:Leaflet 内部用相对路径找图标图片,打包后路径失效。
// 修法 A(推荐 CDN 图标):import 'leaflet/dist/leaflet.css' 之外再修 icon 路径:
L.Icon.Default.mergeOptions({
iconRetinaUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png',
iconUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png',
shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png',
});
// 修法 B(Vite 官方思路):import markerIcon from 'leaflet/dist/images/marker-icon.png' 再 L.icon 引用
// ② L.icon:自定义图片(图标、照片、emoji 贴图)
const photoIcon = L.icon({
iconUrl: 'https://picsum.photos/seed/poi/48/48', // 图片地址
iconSize: [48, 48], // 图片显示尺寸
iconAnchor: [24, 48], // ★ 锚点:图片上"正对地理坐标"的那个点(像素偏移)
// [24,48]=底部中点——大头针的"针尖"在图底中间
popupAnchor: [0, -48], // 弹窗从"锚点"再偏移(-48=图片上方,弹窗才不会盖住图)
className: 'poi-img', // 挂 CSS(圆角/边框:.poi-img { border-radius:50%; border:2px solid #fff })
});
L.marker([30.59, 114.31], { icon: photoIcon }).addTo(map);
// ③ L.divIcon:HTML/CSS 当图标(最灵活:任意 DOM 都能当标记)
const htmlIcon = L.divIcon({
html: `<div class="poi-pin">
<span>武</span>
<b class="pulse"></b> <!-- 配 CSS 动画做"脉冲光环" -->
</div>`,
className: '', // 默认类清空(否则有白底样式)
iconSize: [40, 40],
iconAnchor: [20, 20], // 中心对准坐标
});
// CSS 示例:
// .poi-pin { display:grid; place-items:center; width:40px; height:40px; border-radius:50%;
// background:#1677ff; color:#fff; font-weight:bold; border:3px solid #fff; }
// .pulse { position:absolute; inset:0; border-radius:50%; animation:pulse 1.5s infinite; }
// @keyframes pulse { to { box-shadow: 0 0 0 18px rgba(22,119,255,0); } }
选型:系统图标→①;图片素材→②;动态文字/状态/动效→③(divIcon 是"状态化标记"的最优解:颜色表状态、数字表数量、CSS 动画表告警)。
四、动手跟练:03 · 兴趣点标记页
配套文件:05-leaflet/examples/03-兴趣点标记页.html
步骤:
- 完成 7 个 TODO:默认图标 + 碎图修复、照片图标(iconAnchor 换成中心/底部对比)、divIcon 文字标记(城市首字)、divIcon 脉冲告警标记(CSS 动画)、可拖动标记 + dragend 显示新坐标、点击地图动态打点(预告第 06 节事件)、批量标记循环生成(数据驱动)
- 锚点实验:同一图片分别用 iconAnchor [0,0] / [24,48],肉眼理解"锚点=图片钉在地理坐标上的那根针"
通关标准:
- 三种图标方案都实现
- 锚点数学能讲清(含 popupAnchor 联动)
- divIcon+CSS 动画的告警标记完成
五、自测题
- 打包器下默认图标碎图的根因与两种修法?
- iconAnchor 与 popupAnchor 的参照物分别是什么?
- divIcon 相比图片图标的最大优势?
- "点选坐标"组件用什么事件?
- zIndexOffset 解决什么?
参考答案
- 内部相对路径在打包后失效;修法:mergeOptions 指向 CDN/正确路径,或 import 图片资源引用。
- iconAnchor=图标图片内部相对左上角的偏移(钉尖位置);popupAnchor=相对锚点的弹窗偏移。
- 任意 HTML/CSS——动态内容、状态色、动画都能当图标。
- marker 的 dragend(e.target.getLatLng())。
- 同位置多标记重叠时的上下顺序。
六、下一步
标记会放了 → 第 04 节:弹窗与提示——点击之后看什么。