一、功能概述
本文将分步骤讲解如何使用uni-app框架在微信小程序中实现以下功能:
-
显示基础地图
-
绘制特定区域范围(以郑州市为例)
-
实现点击地图添加标记点
-
限制标记点只能在指定区域内添加
-
显示选中位置的坐标信息
二、分步骤实现
步骤1:搭建基础地图
1.1 添加map组件
在页面template中添加map组件:
html<template> <view class="container"> <map id="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位置):
javascript<script setup> import { ref } from 'vue' const center = ref({ latitude: 34.747, // 纬度 longitude: 113.625 // 经度 }) </script>
步骤2:绘制郑州市范围
2.1 定义郑州市边界坐标
javascriptconst 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组件 绘制限制范围
javascriptconst polygons = ref([{ points: zhengzhouPolygon, strokeWidth: 2, strokeColor: "#1E90FF", fillColor: "#1E90FF22" }])
更新map组件:
html<map ... :polygons="polygons" ></map>
步骤3:实现点击添加标记功能
3.1 初始化markers和选中点
javascriptconst markers = ref([]) const selectedPoint = ref(null) const isInZhengzhou = ref(false)
3.2 实现点击事件处理
javascriptconst handleMapTap = (e) => { const { latitude, longitude } = e.detail selectedPoint.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:实现点在多边形内判断(射线法)
javascriptfunction isPointInPolygon(point, polygon) { const x = point.longitude, y = point.latitude let inside = false for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) { const xi = polygon[i].longitude, yi = polygon[i].latitude const xj = polygon[j].longitude, yj = polygon[j].latitude const intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi) if (intersect) inside = !inside } return inside }
步骤5:添加信息显示区域
html<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>
添加样式:
css<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>
三、完整代码
javascript<template> <view class="container"> <map id="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.latitude let inside = false for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) { const xi = polygon[i].longitude, yi = polygon[i].latitude const xj = polygon[j].longitude, yj = polygon[j].latitude const 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.detail selectedPoint.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 如果不传 会展示系统默认的标记点,如果要根据经纬度获取地名则需要申请对接地图的接口才能实现
四、实现效果