当前位置: 首页 > news >正文

基于Uni-app+vue3实现微信小程序地图固定中心点范围内拖拽选择位置功能(分步骤详解)

一、功能概述与实现步骤

1.1 功能需求

  • 显示地图并固定中心点标记

  • 绘制服务区域多边形边界

  • 实时检测拖拽后位置是否在服务区内

  • 提供位置确认和超出范围提示功能

1.2 实现步骤分解

第一步:初始化地图基础配置
  1. 创建Map组件并设置基本属性

  2. 定义服务区域多边形坐标

  3. 设置地图初始中心点

第二步:实现地图交互逻辑
  1. 监听地图拖拽事件

  2. 获取拖拽后中心点坐标

  3. 判断坐标是否在服务区内

第三步:实现覆盖层UI
  1. 固定中心点标记

  2. 位置信息显示面板

  3. 操作按钮(确认/返回服务区)

    二、分步骤代码实现

    2.1 第一步:地图基础配置

    <template><view class="map-container"><mapid="map"style="width: 100%; height: 80vh":latitude="center.latitude":longitude="center.longitude":polygons="polygons"@regionchange="handleMapDrag":show-location="true"><!-- 覆盖层将在第三步添加 --></map></view>
    </template><script setup>
    import { ref, onMounted } from "vue";// 服务区域边界坐标
    const serviceAreaPolygon = [{ latitude: 34.808, longitude: 113.55 },{ latitude: 34.805, longitude: 113.58 },// ...其他坐标点{ latitude: 34.808, longitude: 113.55 } // 闭合多边形
    ];// 中心点位置
    const center = ref({latitude: 34.747, longitude: 113.625
    });// 多边形配置
    const polygons = ref([{points: serviceAreaPolygon,strokeWidth: 2,strokeColor: "#1E90FF",fillColor: "#1E90FF22"
    }]);// 初始化地图上下文
    const mapContext = ref(null);
    onMounted(() => {mapContext.value = uni.createMapContext("map");
    });
    </script>

    2.2 第二步:地图交互逻辑实现

    // 当前坐标点
    const currentPos = ref({ ...center.value });
    // 是否在服务区内
    const isInServiceArea = ref(true);// 地图拖拽事件处理
    const handleMapDrag = (e) => {if (e.type === "end") {mapContext.value.getCenterLocation({success: (res) => {currentPos.value = {latitude: res.latitude,longitude: res.longitude};// 判断是否在服务区内isInServiceArea.value = isPointInPolygon(currentPos.value,serviceAreaPolygon);}});}
    };// 射线法判断点是否在多边形内
    function isPointInPolygon(point, polygon) {const { latitude, longitude } = point;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 > latitude) !== (yj > latitude))&& (longitude < (xj - xi) * (latitude - yi) / (yj - yi) + xi);if (intersect) inside = !inside;}return inside;
    }

    2.3 第三步:覆盖层UI实现

    <!-- 在map标签内添加 -->
    <cover-view class="center-marker"></cover-view><cover-view class="info-box" :class="{ 'out-of-range': !isInServiceArea }"><cover-view v-if="isInServiceArea">当前位置在服务区域内</cover-view><cover-view v-else class="error">当前选择位置超出服务区域</cover-view><cover-view class="coords">纬度: {{ currentPos.latitude.toFixed(6) }} 经度: {{ currentPos.longitude.toFixed(6) }}</cover-view><cover-view v-if="!isInServiceArea" class="recenter-btn" @tap="centerToServiceArea">查看最近的服务区域</cover-view><cover-view v-else class="confirm-btn" @tap="confirmLocation">确定上车位置</cover-view>
    </cover-view>

    2.4 第四步:业务功能完善

    // 返回服务区中心
    const centerToServiceArea = () => {const center = getPolygonCenter(serviceAreaPolygon);currentPos.value = { ...center };isInServiceArea.value = true;mapContext.value.moveToLocation({latitude: center.latitude,longitude: center.longitude});
    };// 计算多边形中心点
    function getPolygonCenter(polygon) {let latSum = 0, lngSum = 0;polygon.forEach(point => {latSum += point.latitude;lngSum += point.longitude;});return {latitude: latSum / polygon.length,longitude: lngSum / polygon.length};
    }// 确认位置
    const confirmLocation = () => {uni.showToast({title: `位置已确认: ${currentPos.value.latitude.toFixed(6)}, ${currentPos.value.longitude.toFixed(6)}`,icon: "none"});// 实际业务中可以触发回调或跳转
    };

    三、完整实现代码

    <template><view class="map-container"><mapid="map"style="width: 100%; height: 80vh":latitude="center.latitude":longitude="center.longitude":polygons="polygons"@regionchange="handleMapDrag":show-location="true"><cover-view class="center-marker"></cover-view><cover-view class="info-box" :class="{ 'out-of-range': !isInServiceArea }"><cover-view v-if="isInServiceArea">当前位置在服务区域内</cover-view><cover-view v-else class="error">当前选择位置超出服务区域</cover-view><cover-view class="coords">纬度: {{ currentPos.latitude.toFixed(6) }} 经度: {{ currentPos.longitude.toFixed(6) }}</cover-view><cover-view v-if="!isInServiceArea" class="recenter-btn" @tap="centerToServiceArea">查看最近的服务区域</cover-view><cover-view v-else class="confirm-btn" @tap="confirmLocation">确定上车位置</cover-view></cover-view></map></view>
    </template><script setup>
    import { ref, onMounted } from "vue";// 服务区域边界
    const serviceAreaPolygon = [{ latitude: 34.808, longitude: 113.55 },{ latitude: 34.805, longitude: 113.58 },{ latitude: 34.79, longitude: 113.61 },{ latitude: 34.765, longitude: 113.625 },{ latitude: 34.735, longitude: 113.62 },{ latitude: 34.71, longitude: 113.6 },{ latitude: 34.7, longitude: 113.57 },{ latitude: 34.715, longitude: 113.54 },{ latitude: 34.75, longitude: 113.53 },{ latitude: 34.808, longitude: 113.55 }
    ];const center = ref(getPolygonCenter(serviceAreaPolygon));
    const currentPos = ref({ ...center.value });
    const isInServiceArea = ref(true);
    const mapContext = ref(null);const polygons = ref([{points: serviceAreaPolygon,strokeWidth: 2,strokeColor: "#1E90FF",fillColor: "#1E90FF22"
    }]);onMounted(() => {mapContext.value = uni.createMapContext("map");
    });const handleMapDrag = (e) => {if (e.type === "end") {mapContext.value.getCenterLocation({success: (res) => {currentPos.value = {latitude: res.latitude,longitude: res.longitude};isInServiceArea.value = isPointInPolygon(currentPos.value,serviceAreaPolygon);}});}
    };function isPointInPolygon(point, polygon) {const { latitude, longitude } = point;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 > latitude) !== (yj > latitude))&& (longitude < (xj - xi) * (latitude - yi) / (yj - yi) + xi);if (intersect) inside = !inside;}return inside;
    }function getPolygonCenter(polygon) {let latSum = 0, lngSum = 0;polygon.forEach(point => {latSum += point.latitude;lngSum += point.longitude;});return {latitude: latSum / polygon.length,longitude: lngSum / polygon.length};
    }const centerToServiceArea = () => {const center = getPolygonCenter(serviceAreaPolygon);currentPos.value = { ...center };isInServiceArea.value = true;mapContext.value.moveToLocation({latitude: center.latitude,longitude: center.longitude});
    };const confirmLocation = () => {uni.showToast({title: `位置已确认: ${currentPos.value.latitude.toFixed(6)}, ${currentPos.value.longitude.toFixed(6)}`,icon: "none"});
    };
    </script><style scoped>
    .map-container {width: 100%;height: 100vh;position: relative;
    }.center-marker {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);width: 20px;height: 20px;background-color: #5ca7fc;border-radius: 50%;border: 2px solid white;z-index: 999;
    }.info-box {position: absolute;top: 20%;left: 50%;transform: translateX(-50%);background: rgba(255, 255, 255, 0.9);padding: 12px 16px;border-radius: 8px;width: 80%;box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }.info-box.out-of-range {background: rgba(255, 240, 240, 0.9);
    }.coords {font-size: 12px;color: #666;margin: 8px 0;
    }.error {color: #f56c6c;font-weight: bold;
    }.recenter-btn, .confirm-btn {margin-top: 10px;padding: 8px 12px;border-radius: 4px;text-align: center;font-size: 14px;
    }.recenter-btn {background: #606266;color: white;
    }.confirm-btn {background: #409eff;color: white;
    }
    </style>

    四、总结

    本文分步骤详细讲解了如何使用Uni-app实现地图位置选择功能,从基础配置到完整实现,重点介绍了:

  • 地图基础配置方法

  • 多边形区域绘制与判断

  • 交互逻辑的实现

  • 覆盖层UI的开发技巧

  • .moveToLocation移动api 只有在真机才能实现,微信开发者工具不支持

  • 可直接复制完整代码到单页测试运行,欢迎补充问题

五、实现效果

http://www.xdnf.cn/news/1310167.html

相关文章:

  • MySQL 配置性能优化赛技术文章
  • 基于Python3.10.6与jieba库的中文分词模型接口在Windows Server 2022上的实现与部署教程
  • Flutter开发 网络请求
  • ESP32-S3_ES8311音频输出使用
  • 【嵌入式C语言】六
  • 【读论文】医疗AI大模型:百川开源Baichuan-M2
  • 第二十五天:构造函数/析构函数/拷贝构造
  • 开发一款多商户电商APP要多久?功能拆解与源码技术落地方案
  • 迭代器模式及优化
  • 模式匹配自动机全面理论分析
  • 【Web后端】Django、flask及其场景——以构建系统原型为例
  • AI 搜索时代:引领变革,重塑您的 SEO 战略
  • 基于uni-app+vue3实现的微信小程序地图范围限制与单点标记功能实现指南
  • Matplotlib直线绘制:从基础到三维空间的高级可视化
  • 数组名本质与指针运算揭秘
  • List容器:特性与操作使用指南
  • 零基础学习人工智能的完整路线规划
  • 民法学学习笔记(个人向) Part.5
  • 学习游戏制作记录(制作系统与物品掉落系统)8.16
  • MySQL查询性能慢时索引失效的排查与优化实践
  • Redis缓存
  • 【OpenGL】LearnOpenGL学习笔记09 - 材质、光照贴图
  • 登录与登录校验:Web安全核心解析
  • 【昇腾】单张48G Atlas 300I Duo推理卡MindIE+WebUI方式跑7B大语言模型_20250816
  • 如何在FastAPI中玩转APScheduler,实现动态定时任务的魔法?
  • 【wmi异常】关于taskkill命令提示“错误:找不到” 以及无法正常获取设备机器码的处理办法
  • pytorch例子计算两张图相似度
  • PHP反序列化的CTF题目环境和做题复现第2集_POP链构造
  • 利用Qwen大模型进行c++11并发库的学习,与时俱进!!!!
  • AI安全增强核心技术:提示词防火墙、置信度过滤与知识蒸馏防御