一、功能概述与实现步骤

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.pswp.cn/bicheng/93632.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/93632.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/93632.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《设计模式》抽象工厂模式

1.抽象工厂模式定义 抽象工厂模式&#xff08;Abstact Factory &#xff09;&#xff1a; 提供一个创建一系列相关或者相互依赖对象的接口&#xff0c;而无须指定它们具体的类。 1.1 UML图&#xff1a;2.抽象工厂模式举例&#xff1a; 业务场景&#xff1a;需要实现一个数据访问…

git stash临时保存工作区

通过git stash 可以灵活管理临时修改&#xff0c;保持工作区整洁&#xff0c;是多人协作或多任务切换时的常用工具&#xff0c;主要用于临时保存工作区和暂存区修改的命令&#xff0c;常用于以下场景&#xff1a;&#xff08;1&#xff09;需要切换分支&#xff0c;但不想立即提…

Vue 3.5+ Teleport defer 属性详解:解决组件渲染顺序问题的终极方案

&#x1f4cb; 概述 Vue 3.5 引入了 Teleport 的 defer 属性&#xff0c;这是一个重要的延迟解析特性。传统的 Teleport 在组件挂载时会立即解析目标容器&#xff0c;而 defer 属性允许推迟 Teleport 的目标解析&#xff0c;直到应用的其他部分挂载完成。 ⚠️ 传统 Teleport …

【102页PPT】某著名企业智能制造解决方案及智能工厂产品介绍(附下载方式)

篇幅所限&#xff0c;本文只提供部分资料内容&#xff0c;完整资料请看下面链接 https://download.csdn.net/download/2501_92808811/91662620 资料解读&#xff1a;某著名企业智能制造解决方案及智能工厂产品介绍 详细资料请看本解读文章的最后内容 智能制造背景与整体规划…

Revisiting Character-level Adversarial Attacks for Language Models

文章目录**核心设计目标****关键步骤与实现细节**1. **候选位置选择&#xff08;Algorithm 1: get_top_locations&#xff09;**2. **扰动生成与筛选&#xff08;Algorithm 2: Charmer&#xff09;**3. **适配大语言模型&#xff08;LLM&#xff09;的攻击****实验中的性能表现…

(一)Python + 地球信息科学与技术 (GeoICT)=?

目录 引子 一、核心定位&#xff1a;Python 为何能重塑 GeoICT&#xff1f; 二、Python 在 GeoICT 中的关键应用领域 1. 空间数据处理&#xff08;GIS 基础&#xff09; 2. 遥感图像处理与解译 3. 空间分析与建模 4. 地学数据可视化 5. 时空大数据分析 三、Python GeoI…

OpenAI 发布了 GPT-5,有哪些新特性值得关注?国内怎么使用GPT5?

GPT-5很强&#xff0c;在LMAreana上获得了1481分&#xff0c;超过Gemini 2.5 Pro&#xff0c;夺回第一。 国内怎么使用GPT5&#xff1f;-> zhangfeidezhu.com/?p1033 这次发布的GPT-5系列包含三个模型&#xff1a; GPT-5&#xff1a;适合复杂推理、广泛的世界知识&#x…

PowerPoint和WPS演示放映PPT时如何禁止鼠标翻页

在演示播放PPT的时候&#xff0c;我们有时候会用鼠标在幻灯片上划重点&#xff0c;一不小心就点击了鼠标左键&#xff0c;而默认的鼠标左键是向下翻页&#xff08;下一步&#xff09;。可以简单设置一下&#xff0c;禁用鼠标翻页的功能&#xff0c;改为其他方式翻页。一、禁用/…

基于springboot养老院管理系统 毕业论文+项目源码及数据库文件

&#xff01;&#xff01;&#xff01; 有需要的小伙伴可以通过文章末尾名片咨询我哦&#xff01;&#xff01;&#xff01; &#x1f495;&#x1f495;作者&#xff1a;优创学社 &#x1f495;&#x1f495;个人简介&#xff1a;本人在读博士研究生&#xff0c;拥有多年程序开…

Meteodyn WT 6.7(Meteodyn)风力资源评估及微观选址软件工具

Meteodyn WT 6.7&#xff08;Meteodyn&#xff09;风力资源评估及微观选址软件工具&#xff0c;基于计算流体力学&#xff08;CFD&#xff09;技术&#xff0c;主要用于复杂地形下的风能评估和风电场选址。该软件由法国政府环境与能源署&#xff08;ADEME&#xff09;支持开发&…

计算机网络 TCP time_wait 状态 详解

TCP 的 TIME_WAIT 状态是 TCP 连接终止过程中 主动关闭连接的一方&#xff08;通常是先调用 close() 或主动发送 FIN 的一端&#xff09;进入的一个重要状态。理解其原理、副作用和优化策略对高性能网络编程和服务器调优至关重要。&#x1f50d; 一、TIME_WAIT 是什么&#xff…

《GuardHFL: Privacy Guardian for Heterogeneous Federated Learning》——论文阅读

研究背景&#xff1a;异构联邦中各客户端模型结构&#xff0c;精度&#xff0c;算力都不同&#xff0c;无法像传统联邦那样共享梯度&#xff0c;只能通过“查询-响应”使用辅助数据来训练模型。这种方法存在严重隐私问题&#xff1a;直接共享查询样本会泄露敏感信息&#xff0c…

Spring AI 进阶之路01:三步将 AI 整合进 Spring Boot

引子 当 LLM 的浪潮以不可阻挡之势席卷全球&#xff0c;从改变用户交互到重塑商业模式&#xff0c;我们每一位开发者都身处这场技术变革的中心。作为庞大的 Java 生态中的一员&#xff0c;你是否也曾思考&#xff1a;当 Python 似乎成为 AI 的“官方语言”时&#xff0c;我们这…

pycharm2025导入anaconda创建的各个AI环境

目录1.pycharm下载及安装2.导入anaconda的环境到pycharm项目中1.pycharm下载及安装 建议从官网下载&#xff0c;不要乱下载。 https://www.jetbrains.com.cn/en-us/pycharm/ 右上角可以切换中英文&#xff0c;在此切换为中文。 点击下载&#xff0c;如下页面: 点击中间下载w…

获取IPv6地址的三种方式

DHCPv6无状态自动分配IP地址Server 配置&#xff1a;<Huawei>system-view[Huawei]ipv6[Huawei]dhcp enable[Huawei]dhcpv6 pool pool1[Huawei-dhcpv6-pool-pool1]dns-server 2002::2[Huawei-dhcpv6-pool-pool1]dns-domain-name example.com[Huawei-dhcpv6-pool-pool1]qui…

[Oracle数据库] Oracle 复杂查询

对于刚接触 Oracle 数据库的初学者来说&#xff0c;简单查询&#xff08;如SELECT * FROM 表名&#xff09;可能不难掌握&#xff0c;但面对复杂业务场景时&#xff0c;就需要更强大的查询能力。本文将围绕 Oracle 复杂查询的核心知识点展开&#xff0c;包括条件逻辑、分组函数…

Redis-plus-plus API使用指南:通用操作与数据类型接口介绍

&#x1f351;个人主页&#xff1a;Jupiter.&#x1f680; 所属专栏&#xff1a;Redis 欢迎大家点赞收藏评论&#x1f60a;目录通用 API连接 Redis1. get/set2. exists 方法3. del 方法4. keys 方法5. expire 方法6. ttl 方法7. type 方法8. flushall 方法String 类型 API1. ge…

基于遗传编程的自动程序生成

这里写目录标题核心概念与工作原理1. 个体表示&#xff1a;树结构2. 初始化种群3. 适应度评估4. 选择5. 遗传操作&#xff08;繁殖&#xff09;6. 新一代种群形成7. 终止条件基于遗传编程的符号回归示例问题示例GP实现符号回归&#xff08;Deap&#xff09;GP实现符号回归&…

flowable汇总查询方式

背景&#xff1a;小程序开发申请流程。使用flowable流程框架。用户需要在后台统揽用户申请的汇总表。 设计思路&#xff1a;通过查询流程实例分页查询获取数据&#xff0c; 其中可以通过查询条件进行查询&#xff0c;查询条件是流程申请时添加到流程变量当中的&#xff0c;方便…

力扣438:找到字符串中所有的字母异位词

力扣438:找到字符串中所有的字母异位词题目思路代码题目 给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词 的子串&#xff0c;返回这些子串的起始索引。不考虑答案输出的顺序。 思路 我们先不看异位词这个条件&#xff0c;如何在字符串s中找到字符串p。我们可以…