一、功能概述
本文將分步驟講解如何使用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 如果不傳 會展示系統默認的標記點,如果要根據經緯度獲取地名則需要申請對接地圖的接口才能實現
四、實現效果