4. 标记与覆盖物:添加/删除标记点、自定义标记图标、气泡弹窗(callout)、覆盖物(圆形/多边形/折线)
好,咱们今天聊点实在的。地图上光有底图肯定不够,你得往上面「画东西」。标记点、气泡、各种形状的覆盖物,这些才是地图应用的灵魂。我做了这么多年小程序地图开发,可以说,覆盖物玩得转不转,直接决定了你的产品体验好不好。
说白了,标记就是地图上的大头针,覆盖物就是各种图形。但你别小看它们,里面的坑可不少。来,我带你一个个过。
4.1 标记点(Marker)的添加与删除
添加标记点,最基础的操作。微信小程序里用 markers 属性,直接往 <map> 组件上一绑就行。
// 添加单个标记点
Page({
data: {
markers: [{
id: 1,
latitude: 39.915,
longitude: 116.404,
title: '天安门'
}]
}
})
嗯,这里要注意。每个标记点必须有一个唯一的 id。为什么?因为你要删除它的时候,得靠这个 id 来定位。我曾经在项目里吃过这个亏,忘了设 id,结果删除逻辑怎么都跑不对,排查了半天。
删除标记点就更简单了,从数组里移除对应的项就行:
// 删除 id 为 1 的标记点
removeMarker() {
let markers = this.data.markers
markers = markers.filter(item => item.id !== 1)
this.setData({ markers })
}
我个人习惯把标记点的增删改查封装成一个独立的方法,方便复用。你想想看,如果每个页面都写一遍过滤逻辑,后期维护起来得多痛苦。
for 循环生成 id,别用手动编号。我一般用时间戳加随机数,保证不重复。
4.2 自定义标记图标
默认的大头针太丑了,对吧?微信小程序支持自定义图标,用 iconPath 属性指定图片路径就行。
markers: [{
id: 1,
latitude: 39.915,
longitude: 116.404,
iconPath: '/images/custom_marker.png',
width: 30,
height: 30
}]
这里有几个坑,我得跟你说道说道。
- 图片尺寸: 建议用 30-50px 的图标,太大了会遮挡地图内容。
- 图片格式: 支持 png、jpg,但推荐用 png,带透明背景效果更好。
- 路径问题: 必须用项目内的本地路径,不支持网络图片。我刚开始做的时候,直接塞了个 CDN 链接,结果图标死活不显示,查文档才发现这个限制。
如果你需要动态改变图标颜色,比如根据状态显示红绿点,我建议准备多套图标文件,用条件判断切换 iconPath。别想着用 CSS 去改,地图组件不支持那玩意儿。
anchor 属性:anchor: {x: 0.5, y: 1}。这个细节很容易被忽略,但效果差别很大。
4.3 气泡弹窗(Callout)
点击标记点弹出信息,这就是 callout。微信小程序里叫「气泡」,用 callout 属性配置。
markers: [{
id: 1,
latitude: 39.915,
longitude: 116.404,
title: '天安门',
callout: {
content: '这里是天安门广场\n开放时间:全天',
padding: 10,
borderRadius: 5,
display: 'ALWAYS' // 始终显示
}
}]
display 属性有三个值:ALWAYS(始终显示)、BYCLICK(点击显示)、BYTOUCH(触摸显示)。我个人建议用 BYCLICK,用户体验最好。始终显示的话,地图上会密密麻麻全是文字,看着就头疼。
气泡的内容支持换行,用 \n 就行。但要注意,content 是纯文本,不支持富文本。如果你想展示带样式的信息,比如加粗、颜色,那就得用自定义气泡了。
自定义气泡用 customCallout 属性,配合 slot 插槽实现。不过说实话,这个功能在微信小程序里支持得不太好,我建议能用默认气泡就用默认的,省得折腾。
callout 的点击事件是 bindcallouttap,不是 bindmarkertap。这两个事件容易搞混,你一定要注意。
4.4 覆盖物:圆形、多边形、折线
覆盖物就是在地图上画图形。微信小程序提供了三种:圆形、多边形、折线。它们各自有对应的属性。
4.4.1 圆形覆盖物
用 circles 属性,适合表示范围,比如周边搜索的结果。
circles: [{
latitude: 39.915,
longitude: 116.404,
radius: 1000, // 半径,单位米
color: '#FF0000AA', // 边框颜色,支持透明度
fillColor: '#FF000033', // 填充颜色
strokeWidth: 2
}]
颜色值支持 8 位十六进制,后两位是透明度。比如 #FF000033 表示红色,透明度 20%。这个设计挺巧妙的,不用额外传 opacity 参数。
4.4.2 多边形覆盖物
用 polygons 属性,适合圈定不规则区域,比如小区范围、商圈边界。
polygons: [{
points: [
{latitude: 39.915, longitude: 116.404},
{latitude: 39.925, longitude: 116.414},
{latitude: 39.935, longitude: 116.404}
],
fillColor: '#00FF0033',
strokeColor: '#00FF00',
strokeWidth: 2
}]
注意,points 数组至少需要 3 个点,不然构不成多边形。而且最后一个点不需要和第一个点重复,组件会自动闭合。
4.4.3 折线覆盖物
用 polyline 属性,适合画路线、轨迹。
polyline: [{
points: [
{latitude: 39.915, longitude: 116.404},
{latitude: 39.920, longitude: 116.410},
{latitude: 39.925, longitude: 116.415}
],
color: '#0000FF',
width: 4,
dottedLine: false // 是否虚线
}]
折线有个很实用的属性 arrowLine,可以显示方向箭头。我在地图导航项目里就用它来指示行进方向,效果很直观。
4.5 综合示例:一个完整的地图标注场景
来,咱们写一个完整的例子。假设你要做一个「附近停车场」的功能,展示停车场位置、价格信息,并且用圆形表示服务范围。
Page({
data: {
markers: [{
id: 1,
latitude: 39.915,
longitude: 116.404,
iconPath: '/images/parking.png',
width: 40,
height: 40,
callout: {
content: 'A停车场\n价格:5元/小时\n空位:12个',
padding: 8,
borderRadius: 8,
display: 'BYCLICK'
}
}, {
id: 2,
latitude: 39.920,
longitude: 116.410,
iconPath: '/images/parking.png',
width: 40,
height: 40,
callout: {
content: 'B停车场\n价格:8元/小时\n空位:3个',
padding: 8,
borderRadius: 8,
display: 'BYCLICK'
}
}],
circles: [{
latitude: 39.915,
longitude: 116.404,
radius: 500,
color: '#00FF00AA',
fillColor: '#00FF0022',
strokeWidth: 2
}, {
latitude: 39.920,
longitude: 116.410,
radius: 500,
color: '#FF0000AA',
fillColor: '#FF000022',
strokeWidth: 2
}]
}
})
你看,这样组合起来,用户一眼就能看到附近有哪些停车场,点击标记还能看到详细信息。圆形覆盖物则直观地展示了每个停车场的服务范围。
嗯,关于标记和覆盖物,核心内容就这些。说白了就是三件事:放标记、画图形、配气泡。但每个细节都值得你花时间去打磨。我做了这么多项目,最大的体会就是:地图上的每一个像素,都代表着用户体验。别偷懒,多调调样式,多测测边界情况,你的产品会感谢你的。