uniapp地图开发(APP,H5)

2023-12-19 21:13:24

uniapp地图开发(APP,H5)

背景

最近项目中需要使用地图相关功能,需要用到聚合,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放移动端可能不适用,具体看情况而定。

尾巴

今天的文章就到这里了,希望能给大家帮助,如果喜欢我的文章,欢迎给我点赞,评论,关注,谢谢大家!

文章来源:https://blog.csdn.net/abs625/article/details/135088037
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。