先介绍一下功能以及技术
使用uniapp开发的微信小程序,其中的地图页面使用自带的map组件,展示一些标点,点击标点展示气泡弹窗展示相关信息,其中加入了点聚合功能。
成品截图:
下面介绍一下功能实现过程以及问题原因
1. 首先是实现地图的基础功能,以及在地图标点。这方面就不细说了,主要是根据uniapp文档实现的。
2. 点聚合功能的实现:
这里参考了大佬的文章以及文档中的案例,这里简单介绍一下实现过程:
<map :longitude="longitude" :latitude="latitude" :scale="scale" style="width: 100%; height: 100vh;" show-location='true' id="map"></map>
这是组件结构。
this._mapContext = uni.createMapContext("map", this);
js中首先获取地图实例:
this._mapContext.initMarkerCluster({
enableDefaultStyle: false, // 是否使用默认样式
zoomOnClick: true, // 点击聚合的点,是否改变地图的缩放级别
gridSize: 50, // 聚合计算时网格的像素大小,默认60
success(res) {
console.log("聚合创建初始化成功");
},
fail(err) {
console.log("聚合创建失败");
}
});
this._mapContext.on("markerClusterCreate", (res) => {
console.log("缩放或拖动导致新的聚合簇产生时触发", res);
if(this.showCalloutInfo.isShow) {
this.closeAllCollout();
}
const clusters = res.clusters
const markers = clusters.map(cluster => {
const {
center,
clusterId,
markerIds
} = cluster
return {
...center,
width: 0,
height: 0,
clusterId, // 必须
label: {
...
}
}
})
this._mapContext.addMarkers({
markers,
clear: false,
complete(res) {
console.log('clusterCreate addMarkers', res)
}
})
});
this.addMarkers();
获取地图实例后通过实例调用聚合点初始化方法initMarkerCluster,然后监听事件设置聚合点样式,
addMarkers() {
this._mapContext.addMarkers({
markers: this.markers,
clear: false,
complete(res) {
console.log('addMarkers', res)
}
})
},
最后调用this.addMarkers()方法设置我们本该渲染的正常标点。
以上过程实现了uniapp中map组件内的点聚合功能。
3. 接下来是标点上方气泡框的实现
气泡弹窗的实现主要是参考微信文档的自定义callout,使用插槽形式,下面简单介绍一下。
this.markers = this.propertyList.map((item, index) => {
return {
id: +index,
longitude: item.longitude,
latitude: item.latitude,
// title: item.storeName,
joinCluster: true,
// clusterId: item.id,
width: 40,
height: 40,
iconPath: 'https://aaa/bbb/ccc/aaaaaaaa.png',
customCallout: {
display: 'ALWAYS',
goodsName: item.goodsName,
thumbnail: item.thumbnail,
price: item.price,
anchorY: -20,
anchorX: 0,
}
}
})
(坑1:这里的iconPath属性值必须为网络资源,不然在真机上不能正常显示)
这里是我们给map组件提供的markers的数据,通过设置customCallout属性实现微信小程序中可以使用插槽自定义callout样式,附一张文档截图:
this.ids = this.propertyList.map((item, index) => {
index,
});
这里的ids是遍历插槽中的cover-view并将marker-id属性与标点中id绑定使用的
通过以上两步的设置我们就实现了点聚合以及气泡弹窗的展示。
坑2:markers.customCallout.display这个属性
在设置为"ALWAYS"时在微信开发者工具中可以正常看到,但是将其设置为“BYCLICK”时微信开发者工具无法正常首先点击显示的效果,只有真机实测时才可以实现。
问题出现
当以上设置完成后我们通过真机去预览callout的效果时发现手机上不出现callout框,display属性无论设置为哪个值都没有效果。
博主找了好久最后锁定了问题的关键:
在实现点聚合功能时最后是通过地图实例的addMarkers方法去添加标点到地图上的,地图在初始化渲染到页面上时###因为异步添加标点到页面上导致插槽内的marker-id添加到页面时无法与标点匹配###导致的不能正常渲染到页面上的问题。简单来说就是----dom结构没有与数据绑定导致的结果(我知道没有dom结构,只是便于理解
解决
解决就很好解决了,我们直接在map里加上markers属性值就好了,完整代码:
<map v-if="showMap" :longitude="longitude" :latitude="latitude" :scale="scale" style="width: 100%; height: 100vh;"
show-location='true' id="map" @callouttap="calloutTap" @markertap="markerTap" :markers="markers">
<cover-view slot="callout">
<block v-for="(item, index) in ids" :key="index">
<cover-view :marker-id="item.index" style="background-color: #fff; border: 1px solid #ccc; width: 400rpx;" v-show="item.isShow">
<cover-view style="padding: 20rpx;font-size:30rpx; color:#333;">
<cover-view style="margin-bottom: 20rpx; width: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-weight: bold; font-size: 28rpx;">
商品名称:{{ markers[item.index].customCallout.goodsName }}
</cover-view>
<cover-view style="display: flex; justify-content: space-around; align-items: center; margin-bottom: 20rpx;">
<cover-image style="width: 100rpx; height: 10s0rpx;" :src="markers[item.index].customCallout.thumbnail" mode="widthFix" />
<cover-view style="margin:10rpx 0 0;">价格:
<cover-view class='windowInfoPrice' style="display: inline;">
{{ markers[item.index].customCallout.price }} 万元
</cover-view>
<cover-view class="checkInfo" style="text-align: right; margin-top: 20rpx;">查看详情>></cover-view>
</cover-view>
</cover-view>
</cover-view>
</cover-view>
</block>
</cover-view>
</map>
大佬文章:uniapp中map使用点聚合渲染marker覆盖物_uniapp map 点聚合-CSDN博客
最后特别鸣谢 《Google前端工程师架构交流群》——杰哥力挽狂澜 大佬的指导