最近项目中需要使用地图相关功能,需要用到聚合,marker拖拽,自定义marker显示内容,根据角色不同maker显示不同图标等功能。查阅了uniapp官方API关于map相关的文档,发现官方API支持有限,很多功能无法实现或者不支持。而且地图相关页面还有很多弹窗,APP端必须使用nvue才能实现同层渲染,而nvue用起来有有诸多限制,比如无法使用封装的全局方法之类的。一番摸索之后我觉得放弃官方map组件,使用renderJs配合地图商js API来实现功能。这里以高德地图为例,老规矩先上个图镇楼:
新建一个vue页面,并引入renderjs相关的script标签,模板中新增一个div标签(必须要设置id)用来承载高德地图。
模板部分:
<template>
<view class="content">
<!--这里maph可以设置为整个页面高度,或者自定义-->
<div id='container' class="map" :style="'height:' + maph + 'px;'"></div>
</view>
</template>
renderjs中mounted引入js API
...
const script = document.createElement('script');
//这里key要去高德官网去申请
script.src = 'https://webapi.amap.com/maps?v=2.0&key=you key';
script.onload = this.initAmap.bind(this);
document.head.appendChild(script);
...
主要是根据你项目的功能去调用高德地图API。上面示例图中用到了聚合,点拖拽,自定义marker上的label,自定义聚合簇样式等,更多丰富用法可以参考官方文档。
其实到这里也没有啥好说的,就一个页面,主要还是根据自己项目功能参考官方文档为主,下面就将整个页面代码贴出供大家参考:
<template>
<view class="content">
<div id='container' class="map" :style="'height:' + maph + 'px;'"></div>
</view>
</template>
<script>
export default {
data() {
return {
maph: 0
}
},
onLoad() {
this.maph = uni.getSystemInfoSync().windowHeight
},
methods: {
}
}
</script>
<script module="renderJS" lang="renderjs">
var loadSdk = false; //是否已经加载完成地图sdk
export default {
data() {
return {
map: null
}
},
mounted() {
//这里安全码也是要自己申请
window._AMapSecurityConfig = {
securityJsCode:'you code',
}
if (typeof window.AMap == 'function') {
this.initAmap();
} else {
console.log('3333333333')
// 动态引入较大类库避免影响页面展示
const script = document.createElement('script');
script.src = 'https://webapi.amap.com/maps?v=2.0&key=you key';
script.onload = this.initAmap.bind(this);
document.head.appendChild(script);
}
},
methods: {
initAmap(e, ownerVm) {
//这里id必须跟模板中的容器id一样
var map = new AMap.Map("container", {
zoom: 12, //设置地图显示的缩放级别
center: [108.939621, 34.343147], //设置地图中心点坐标
//mapStyle: 'amap://styles/whitesmoke', //设置地图的显示样式
viewMode: '2D' //设置地图模式
});
map.on('complete', () => {
console.log('加载完成')
})
map.plugin(["AMap.Scale"],function(){
var scale = new AMap.Scale();
map.addControl(scale);
});
map.plugin(["AMap.ToolBar"],function(){
//加载工具条
var tool = new AMap.ToolBar();
map.addControl(tool);
});
map.plugin(["AMap.ControlBar"],function() {
var controlBar = new AMap.ControlBar()
map.addControl(controlBar)
});
var styles = [{
url:"https://a.amap.com/jsapi_demos/static/images/blue.png",
size:new AMap.Size(32,32),
offset:new AMap.Pixel(-16,-32),
textColor: '#AACCFF'
},
{
url:"https://a.amap.com/jsapi_demos/static/images/green.png",
size:new AMap.Size(32,32),
offset:new AMap.Pixel(-16,-32),
textColor: '#FFCE88'
},
{
url:"https://a.amap.com/jsapi_demos/static/images/green.png",
size:new AMap.Size(32,32),
offset:new AMap.Pixel(-16,-32),
textColor:'#CC0066'
}];
var points = [
{lnglat: ["108.939621", "34.343147"] },
{lnglat: ["108.932621", "34.313145"] },
{lnglat: ["109.932621", "33.313147"] },
{lnglat: ["109.132621", "33.913149"] },
{lnglat: ["108.122621", "35.213148"] },
{lnglat: ["109.522621", "34.013147"] },
{lnglat: ["108.567621", "35.456127"] },
{lnglat: ["107.212621", "33.953137"] },
{lnglat: ["108.182621", "35.299147"] },
{lnglat: ["109.900621", "34.209167"] },
{lnglat: ["108.000521", "33.099014"] },
];
var cluster
// 加载点聚合插件
AMap.plugin(["AMap.MarkerCluster"], function() {
if (cluster) {
cluster.setMap(null);
}
cluster = new AMap.MarkerCluster(map, points, {
//gridSize: 80, // 聚合网格像素大小
styles: styles,
renderMarker: (content) => {
let icon = new AMap.Icon({
// 图标尺寸
size: new AMap.Size(32, 32),
// 图标的取图地址
image: './static/mark.png',
// 图标所用图片大小
imageSize: new AMap.Size(32, 32),
offset: new AMap.Pixel(-16, -32),
});
content.marker.setIcon(icon);
content.marker.setDraggable(true)
content.marker.on("dragend", res => {
console.log('dragend',res.lnglat)
})
let label = {
content: `<div style="display: flex;flex-direction: row;align-items: center;background: yellow;position:relative;margin:0;top:0;right:0;min-width:0;">
<div style="padding: 3px 10px 3px 10px;background-color: aquamarine;border-radius: 8px;margin-right: 10px;">是的发送到</div>
<div>水电费水电费</div>
</div>`,
direction: 'top'
}
content.marker.setLabel(label)
content.marker.on('click', ev => {
map.setZoomAndCenter(16, ev.target.getPosition());
})
},
//配置此回调函数,上面配置的styles会失效
renderClusterMarker: (context) => {
context.marker.setOffset(new AMap.Pixel(-20, -40))
context.marker.setContent(`<div style='background:red;color:white;border-radius: 50%;width:40px;height:40px;text-align:center;line-height:40px;'>${context.count}</div>`);
}
});
cluster.on('click', (item) => {
//此处是通过包含点的数量判断是否是聚合点,不是聚合点就执行上方单个点的点击方式
if (item.clusterData.length <= 1) {
return;
}
//这里是计算所有聚合点的中心点
let alllng = 0,
alllat = 0;
for (const mo of item.clusterData) {
alllng += mo.lnglat.lng;
alllat += mo.lnglat.lat;
}
const lat = alllat / item.clusterData.length;
const lng = alllng / item.clusterData.length;
//这里是放大地图,此处写死了每次点击放大的级别,可以根据点的数量和当前大小适应放大,体验更佳
var lnglat = new AMap.LngLat(lng, lat);
map.setZoomAndCenter(map.getZoom() + 4, lnglat);
});
});
//加载地理编码插件
AMap.plugin(["AMap.Geocoder"], () => { //加载地理编码插件
console.log('00000000000')
var geocoder = new AMap.Geocoder({
city: '010' // city 指定进行编码查询的城市,支持传入城市名、adcode 和 citycode
})
var address = '北京市海淀区苏州街';
geocoder.getLocation(address, function(status, result) {
console.log('9999999999999',result,status)
if (status === 'complete' && result.info === 'OK') {
// result中对应详细地理坐标信息
}
})
});
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
.map {
z-index: 1;
width: 750rpx;
}
.second {
position: absolute;
right: 0;
bottom: 0;
z-index: 9;
}
.amap-marker-label{
position: absolute;
z-index: 2;
border: 1px solid transparent;
background-color: #e5e5e5;
cursor: default;
padding: 3px;
font-size: 12px;
line-height: 14px;
border-radius: 10px;
}
.test {
display: flex;
flex-direction: row;
align-items: center;
background: yellow;
}
.test1 {
padding: 3px 10px 3px 10px;
background-color: aquamarine;
border-radius: 8px;
margin-right: 10px;
}
</style>
其实页面逻辑很简单,主要是涉及高德API调用来实现功能。这里还有个小bug,自定义dom label拖动地图和缩放地图可能会导致marker闪烁,我已经给官方提bug了,官方后续会修复。
使用renderjs方式理论上还可以使用百度和腾讯地图,(腾讯地图有尝试过是可以的,百度地图没试过),这种方式支持H5和APP平台,微信小程序还是只能乖乖使用官方的地图组件进行开发,如果是跨平台项目记得区分。另外各地图厂商js API其实是给PC端用的,有些API放移动端可能不适用,具体看情况而定。
今天的文章就到这里了,希望能给大家帮助,如果喜欢我的文章,欢迎给我点赞,评论,关注,谢谢大家!