背景
最近产品要在地图上显示出来各个点位的经纬度和名称信息,点击后将 marker 移动至地图中心,同时缩放地图。
知识点
| 属性 | 说明 |
|---|---|
| id | 地图组件的id,必填,在这里主要是用来获取地图上下文 mapContext 对象 |
| scale | 缩放级别,在这里主要是用来点击callout后缩放级别 |
| show-location | 显示带有方向的当前定位点, 和将地图中心移动到当前定位点 moveToLocation 方法结合使用 |
| longitude | 中心经度,点击 callout 变更为选中 marker 的经度 |
| latitude | 中心纬度,点击 callout 变更为选中 marker 的纬度 |
| markers | 标记点 |
| markertap | marker 的点击事件,和下方 calloutTap 事件一致 |
| calloutTap | callout 的点击事件,点击之后 marker 移动至地图中心,并缩放地图 |
createMapContext
使用 createMapContext 获取 map 上下文,第一个参数就是该地图组件的 id ,第二个参数传入组件实例this ,以操作组件内 <map> 组件,详情可查看
那这里为什么需要 this 呢?毕竟微信小程序中的 createMapContext 不需要
这是因为在 uni-app 中,组件实例的生命周期和小程序页面的生命周期是不同的。在小程序中,一个页面是一个独立的 JavaScript 文件,而在 uni-app 中,一个页面可能包含多个组件,这些组件有自己的数据和生命周期。因此,如果要在组件中使用 createMapContext 方法来创建地图上下文,就需要将组件实例作为第二个参数传递给该方法,以便在组件内部访问到地图上下文对象。
因此,将组件实例作为第二个参数传递给 uni.createMapContext 方法,可以确保在组件内部正确地创建和管理地图上下文对象,并且可以避免不同组件之间的地图上下文对象混淆的问题。同时,也方便了组件内部对地图上下文对象的调用和管理。
moveToLocation
moveToLocation会获取定位权限,并且需要在 show-location 配合使用,也就是设置为true
移动至地图中心
两种方式
- 动态设置
map组件上的longitude和latitude,缺点是没有移动的动画,很生硬 - 使用
moveToLocation方法继续进行移动,动画很流畅
所以这里采用了第二种方案
设置地图scale
在 iOS 上设置 scale ,它会根据当前的经纬度进行缩放,也就是 map组件 上的 longitude 和latitude ,由于动态设置经纬度会导致失去移动的动画,所以我们这里先调用 moveToLocation 方法将 marker 移动至地图中心,300ms (这里的300ms是我多次尝试出来的,并不是官方的,这里的时间按需设置) 之后移动动画完成再去设置经纬度,这样既有移动的动画,又可以进行正常缩放了
安卓一切正常
实现
<template>
<map id="myMap" :scale="scale" :show-location="true" :longitude="longitude" :latitude="latitude" :markers="markers" @markertap="calloutTap" @callouttap="calloutTap" />
</template>
<script>
export default {
data() {
return {
longitude: 116.397428, //中心点经度
latitude: 39.90923, //中心点纬度
markers: [] ,//所有点位信息
mapContext: null, //map上下文
scale: 10, //默认缩放级别
};
},
mounted() {
//获取map上下文
const mapContext = uni.createMapContext('myMap', this);
this.mapContext = mapContext;
//模拟请求
setTimeout(() => {
//对markers进行赋值
this.markers = [
{
id: 1,
longitude: 116.397428,
latitude: 39.90923,
callout: {
content: '标记1',
color: '#ffffff',
fontSize: 14,
borderRadius: 4,
bgColor: '#3cc51f',
padding: 8,
display: 'ALWAYS',
},
},
{
id: 2,
longitude: 116.407428,
latitude: 39.90923,
callout: {
content: '标记2',
color: '#ffffff',
fontSize: 14,
borderRadius: 4,
bgColor: '#3cc51f',
padding: 8,
display: 'ALWAYS',
},
},
{
id: 3,
longitude: 116.397428,
latitude: 39.91923,
callout: {
content: '标记3',
color: '#ffffff',
fontSize: 14,
borderRadius: 4,
bgColor: '#3cc51f',
padding: 8,
display: 'ALWAYS',
},
},
];
//将中心点经纬度设置成第一个点位的经纬度
this.longitude = this.markers[0].longitude;
this.latitude = this.markers[0].latitude;
//获取所有点的经纬度
const points = this.markers.map((marker) => ({ latitude: marker.latitude, longitude: marker.longitude }));
// 缩放视野展示所有经纬度 [上,右,下,左]
this.mapContext.includePoints({
points,
padding: [150, 150, 150, 150], // 设置地图边缘与 marker 的间距
});
}, 2000);
},
methods: {
//点击气泡,找到被点击的marker
calloutTap(e) {
const { markerId } = e.detail;
const marker = this.markers.find((m) => m.id === markerId);
marker && this.moveMarkerToCenter(marker);
},
moveMarkerToCenter(marker) {
//将marker移动至中心点
this.mapContext.moveToLocation({
longitude: marker.longitude,
latitude: marker.latitude,
success: (res) => {
//这里加300ms的延时是为了防止和moveToLocation功能冲突,保留地图移动的动画
const timer = setTimeout(() => {
this.longitude = marker.longitude;
this.latitude = marker.latitude;
clearTimeout(timer);
//进行缩放,设置为16
this.scale = 16;
}, 300);
},
});
},
},
};
</script>
<style lang="scss" scoped>
#myMap {
width: 100vw;
height: 100vh;
}
</style>
在上述代码中,我们在 mounted 钩子函数中获取了地图的上下文对象 mapContext,发起请求为markers赋值,调用includePoints方法来缩放视野展示点位等
在 calloutTap 方法中,通过 e.markerId 获取到当前点击的标记点的 id,然后在 markers 数组中查找该标记点,获取它的经纬度,将其作为参数传递给 moveToLocation 方法,以使地图移动到该标记点的位置并缩放地图
最终效果如下图所示
结语
到这里,我们已经完成了在 Uniapp 微信小程序中绘制标记点和气泡,并实现标记点和气泡的点击事件,以及点击后将标记点移动到地图中心的功能。
都已经看到了这里了,麻烦各位大佬点个赞咯,谢谢!
祝大家都变得更强!