基于uni-app+vue3实现的微信小程序地图范围限制与单点标记功能实现指南
一、功能概述
本文将分步骤讲解如何使用uni-app框架在微信小程序中实现以下功能:
显示基础地图
绘制特定区域范围(以郑州市为例)
实现点击地图添加标记点
限制标记点只能在指定区域内添加
显示选中位置的坐标信息
二、分步骤实现
步骤1:搭建基础地图
1.1 添加map组件
在页面template中添加map组件:
<template><view class="container"><mapid="map"style="width: 100%; height: 80vh":latitude="center.latitude":longitude="center.longitude":show-location="true":enable-zoom="true":enable-scroll="true"@tap="handleMapTap"></map></view> </template>
1.2 设置地图中心点
在script部分设置地图初始中心点(xxx位置):
<script setup> import { ref } from 'vue'const center = ref({latitude: 34.747, // 纬度longitude: 113.625 // 经度 }) </script>
步骤2:绘制郑州市范围
2.1 定义郑州市边界坐标
const zhengzhouPolygon = [{latitude: 34.936, longitude: 112.842}, // 西北角{latitude: 34.936, longitude: 114.023}, // 东北角{latitude: 34.524, longitude: 114.023}, // 东南角{latitude: 34.524, longitude: 112.842}, // 西南角{latitude: 34.936, longitude: 112.842} // 闭合多边形 ]
2.2 添加polygons属性到map组件 绘制限制范围
const polygons = ref([{points: zhengzhouPolygon,strokeWidth: 2,strokeColor: "#1E90FF",fillColor: "#1E90FF22" }])
更新map组件:
<map...:polygons="polygons" ></map>
步骤3:实现点击添加标记功能
3.1 初始化markers和选中点
const markers = ref([]) const selectedPoint = ref(null) const isInZhengzhou = ref(false)
3.2 实现点击事件处理
const handleMapTap = (e) => {const { latitude, longitude } = e.detailselectedPoint.value = { latitude, longitude }// 判断是否在郑州范围内isInZhengzhou.value = isPointInPolygon({latitude, longitude}, zhengzhouPolygon)if (isInZhengzhou.value) {// 在范围内,添加标记markers.value = [{id: 1,latitude,longitude,iconPath: '/static/location.png', // 替换为你的标记图标路径width: 30,height: 30,title: "选择的位置"}]} else {// 不在范围内,清除标记并提示markers.value = []uni.showToast({title: "请选择郑州市范围内的位置",icon: "none",duration: 2000})} }
步骤4:实现点在多边形内判断(射线法)
function isPointInPolygon(point, polygon) {const x = point.longitude, y = point.latitudelet inside = falsefor (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {const xi = polygon[i].longitude, yi = polygon[i].latitudeconst xj = polygon[j].longitude, yj = polygon[j].latitudeconst intersect = ((yi > y) !== (yj > y)) &&(x < (xj - xi) * (y - yi) / (yj - yi) + xi)if (intersect) inside = !inside}return inside }
步骤5:添加信息显示区域
<view class="info-box" v-if="selectedPoint"><text>已选位置:</text><text>纬度: {{selectedPoint.latitude.toFixed(6)}}</text><text>经度: {{selectedPoint.longitude.toFixed(6)}}</text><text v-if="!isInZhengzhou" class="error">当前位置不在郑州范围内!</text> </view>
添加样式:
<style scoped> .container {padding: 20rpx; }.info-box {margin-top: 20rpx;padding: 20rpx;background-color: #f5f5f5;border-radius: 10rpx; }.info-box text {display: block;margin: 10rpx 0;font-size: 28rpx; }.error {color: #ff0000;font-weight: bold; } </style>
三、完整代码
<template><view class="container"><mapid="map"style="width: 100%; height: 80vh":latitude="center.latitude":longitude="center.longitude":polygons="polygons":markers="markers"@tap="handleMapTap":show-location="true":enable-zoom="true":enable-scroll="true"></map><view class="info-box" v-if="selectedPoint"><text>已选位置:</text><text>纬度: {{selectedPoint.latitude.toFixed(6)}}</text><text>经度: {{selectedPoint.longitude.toFixed(6)}}</text><text v-if="!isInZhengzhou" class="error">当前位置不在郑州范围内!</text></view></view> </template><script setup> import { ref } from 'vue'// 郑州市边界坐标 const zhengzhouPolygon = [{latitude: 34.936, longitude: 112.842},{latitude: 34.936, longitude: 114.023},{latitude: 34.524, longitude: 114.023},{latitude: 34.524, longitude: 112.842},{latitude: 34.936, longitude: 112.842} ]// 地图中心点(郑州二七塔) const center = ref({latitude: 34.747,longitude: 113.625 })// 多边形配置 const polygons = ref([{points: zhengzhouPolygon,strokeWidth: 2,strokeColor: "#1E90FF",fillColor: "#1E90FF22" }])// 标记点 const markers = ref([]) const selectedPoint = ref(null) const isInZhengzhou = ref(false)// 判断点是否在多边形内 function isPointInPolygon(point, polygon) {const x = point.longitude, y = point.latitudelet inside = falsefor (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {const xi = polygon[i].longitude, yi = polygon[i].latitudeconst xj = polygon[j].longitude, yj = polygon[j].latitudeconst intersect = ((yi > y) !== (yj > y)) &&(x < (xj - xi) * (y - yi) / (yj - yi) + xi)if (intersect) inside = !inside}return inside }// 处理地图点击 const handleMapTap = (e) => {const { latitude, longitude } = e.detailselectedPoint.value = { latitude, longitude }isInZhengzhou.value = isPointInPolygon({latitude, longitude}, zhengzhouPolygon)if (isInZhengzhou.value) {markers.value = [{id: 1,latitude,longitude,iconPath: '/static/location.png',width: 30,height: 30,title: "选择的位置"}]} else {markers.value = []uni.showToast({title: "请选择郑州市范围内的位置",icon: "none",duration: 2000})} } </script><style scoped> .container {padding: 20rpx; }.info-box {margin-top: 20rpx;padding: 20rpx;background-color: #f5f5f5;border-radius: 10rpx; }.info-box text {display: block;margin: 10rpx 0;font-size: 28rpx; }.error {color: #ff0000;font-weight: bold; } </style>
通过以上步骤,我们完整实现了一个限制区域范围的单点标记功能。开发者可以根据实际需求调整区域范围或扩展更多功能。。。ps:markers中的iconpath 如果不传 会展示系统默认的标记点,如果要根据经纬度获取地名则需要申请对接地图的接口才能实现
四、实现效果