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

Vue 3 + 高德地图实战:打造全能定位与搜索组件

在前端开发中地图功能往往是复杂业务场景的核心需求。无论是外卖配送、打卡签到还是物流追踪都需要精准的定位和便捷的地点搜索能力。本文将基于Vue 3和高德地图 JS API 2.0详细解析如何实现一个集点击地图定位、关键词搜索联想、经纬度精确定位于一体的地图组件。1. 项目准备与环境配置1.1 安装依赖我们需要使用官方推荐的加载器amap/amap-jsapi-loader来异步加载高德地图 SDK避免全局污染并更好地管理生命周期。npm install amap/amap-jsapi-loader1.2 获取 Key 与安全密钥在高德开放平台创建应用获取Key和安全密钥 (Security Code)。注意自高德地图 JS API 2.0 起必须配合安全密钥使用否则无法加载地图。2. 核心架构设计我们的组件主要包含以下模块地图容器用于渲染地图实例。工具栏输入经纬度、设置半径、清除标记。搜索栏支持关键词输入下拉展示搜索建议POI。信息展示区显示当前选中位置的详细地址。3. 关键功能实现详解3.1 初始化地图与安全配置在onMounted中我们首先处理 Mock 数据对地图请求的影响开发环境中常见坑点然后配置安全密钥并加载地图。// 解决 Mock.js拦截高德地图请求导致白屏的问题 window.XMLHttpRequest window._XMLHttpRequest || window.XMLHttpRequest; window.fetch window._fetch || window.fetch; // 配置安全密钥 window._AMapSecurityConfig { securityJsCode: AMAP_SECURITY_CODE, }; // 加载地图 AMapLoader.load({ key: AMAP_KEY, version: 2.0, plugins: [ AMap.Scale, // 比例尺 AMap.ToolBar, // 工具条 AMap.Geocoder, // 地理编码/逆地理编码 a AMap.PlaceSearch, // 地点搜索服务 ], }) .then((AMap) { // 初始化地图实例 const map new AMap.Map(container, { viewMode: 3D, zoom: 11, center: [116.397428, 39.90923], // 默认北京 resizeEnable: true, }); // 添加控件 map.addControl(new AMap.Scale()); map.addControl(new AMap.ToolBar()); mapInstance.value map; });3.2 点击地图与逆地理编码用户点击地图任意位置时我们需要做三件事获取经纬度。添加标记点Marker和范围圈Circle。通过逆地理编码将坐标转换为人类可读的地址字符串。// 地图点击事件 map.on(click, (e) { const point e.lnglat; const lng point.lng; const lat point.lat; // 更新双向绑定的数据 longitude.value lng; latitude.value lat; // 添加标记和圆圈 addMarker([lng, lat]); // 逆地理编码获取地址详情 reverseGeocode({ lng, lat }); }); // 逆地理编码函数 const reverseGeocode (point) { const geocoder new AMap.Geocoder(); geocoder.getAddress([point.lng, point.lat], (status, result) { if (status complete result.info OK) { // 获取格式化地址 currentLocation.value result.geocodes[0].formattedAddress; } else { currentLocation.value 坐标: ${point.lng}, ${point.lat}; } }); };3.3 智能搜索与联想PlaceSearch这是提升用户体验的关键。我们使用AMap.PlaceSearch插件来实现“边输边搜”的效果。实现逻辑监听输入框的 input 事件。当输入字符大于 2 时调用placeSearch.search()。将返回的 POI兴趣点数据格式化渲染到下拉列表中。用户点击某一项时地图自动定位到该点。const handleSearchInput (value) { if (!mapInstance.value || !value || value.length 2) { searchTips.value []; return; } const placeSearch new AMap.PlaceSearch({ city: 全球, citylimit: false, // 允许全国搜索 pageSize: 10, extensions: all, // 返回详细信息 }); placeSearch.search(value, (status: string, result: any) { if (status complete result.poiList) { searchTips.value result.poiList.pois.map((poi) ({ name: poi.name, district: ${poi.pname}${poi.cityname}${poi.adname}, address: poi.address, location: poi.location, // AMap.LngLat 对象 })); } else { searchTips.value []; } }); }; // 选择搜索结果 const selectSearchResult (item) { searchAddress.value item.name; searchTips.value []; // 隐藏列表 const lng item.location.lng; const lat item.location.lat; // 地图视角切换 mapInstance.value.setCenter([lng, lat]); mapInstance.value.setZoom(15); // 更新状态 longitude.value lng; latitude.value lat; addMarker([lng, lat]); currentLocation.value item.district item.address; };3.4 经纬度手动定位与范围绘制除了鼠标操作业务场景中常需要直接输入坐标进行定位。同时为了模拟“电子围栏”或“打卡范围”我们需要绘制一个圆形覆盖物。const locateByCoordinate () { const lng parseFloat(longitude.value); const lat parseFloat(latitude.value); if (isNaN(lng) || isNaN(lat)) { ElMessage.error(请输入有效的经纬度); return; } const center [lng, lat]; mapInstance.value.setCenter(center); mapInstance.value.setZoom(15); addMarker(center); // 绘制圆形范围 createCircle(center, radius.value); reverseGeocode({ lng, lat }); }; // 创建圆形覆盖物 const createCircle (center, radiusVal) { clearCircleOnly(); // 先清除旧圆圈 const circle new AMap.Circle({ center: center, radius: parseFloat(radiusVal), // 单位米 strokeColor: #0091ff, strokeWeight: 2, fillColor: rgba(0, 145, 255, 0.1), fillOpacity: 0.5, }); mapInstance.value.add(circle); };4. UI 交互细节优化4.1 下拉列表样式为了让搜索体验更像原生 App我们使用绝对定位将下拉列表悬浮在输入框下方并添加了阴影和滚动条限制。.search-tips-list { position: absolute; top: 100%; left: 0; width: 100%; max-height: 300px; overflow-y: auto; background: #fff; border: 1px solid #dcdfe6; z-index: 1000; li { padding: 10px 15px; cursor: pointer; :hover { background-color: #f5f7fa; color: #409eff; } } }4.2 清理机制在添加新标记或圆圈前务必清除旧的覆盖物防止地图元素堆积导致性能下降或视觉混乱。const clearAll () { clearCircleOnly(); if (currentMarker.value) { mapInstance.value.remove(currentMarker.value); currentMarker.value null; } // 重置其他状态... };5. 常见问题与避坑指南Mock.js 冲突现象引入 Mock.js 后地图瓦片加载失败页面白屏。解决如代码所示在加载地图前备份并恢复原生的XMLHttpRequest和fetch。地图容器尺寸问题现象地图只显示左上角一小块。解决确保父容器有明确的高度。如果在 Tab 切换或动态显示中初始化地图需在 DOM 更新后调用map.resize()。安全密钥配置现象控制台报错INVALID_USER_SCODE。解决确保window._AMapSecurityConfig在AMapLoader.load之前执行且密钥正确。6. 总结通过本文的实践我们构建了一个功能完备的高德地图组件。它不仅实现了基础的地图展示还结合了PlaceSearch和Geocoder提供了强大的搜索与反查能力。核心亮点响应式数据绑定Vue 3ref与地图状态实时同步。用户体验优化搜索联想、自动缩放、清晰的状态反馈。健壮性处理了 Mock 冲突、无效坐标校验及覆盖物清理。你可以在此基础上继续扩展例如添加路径规划、多点标记聚合等功能以满足更复杂的业务需求。
http://www.zskr.cn/news/1351961.html

相关文章:

  • 2026年多门店商城小程序怎么做
  • 告别一堆转接头!一个自研小工具搞定USB、网口、485、232、TTL互转(附配置教程)
  • 保姆级教程:在YOLOv5s.yaml里给YOLOv5 V7.0模型加上SimAM注意力(附代码)
  • 减速机:以“减速”之名,行“增力”之实的机械智慧
  • 【c++面向对象编程】第46篇:CRTP(奇异递归模板模式):静态多态的妙用
  • 国产多模态大模型 vs DALL-E:本土化突围与全球竞技
  • 别再只调样式了!深入理解鸿蒙ArkTS中Slider的四种交互状态(Begin/Moving/End/Click)
  • 手把手教你用C语言写一个简易的SMTP邮件内容解析器(基于libnids抓包库)
  • 【c++面向对象编程】第44篇:typename与class的区别,依赖类型名与template消除歧义
  • 告别开发依赖!SAP顾问必学的SQ01/SQ02/SQ03实战:5步搞定自定义报表
  • DocKit v1.0 发布 — AI 原生 NoSQL 桌面客户端,支持 Elasticsearch、OpenSearch 和 DynamoDB,本地优先,Apache 2.0 开源
  • 21.jdbc 学习笔记:从原理到实践的全流程梳理
  • 20.MySQL事务隔离级别示例详解(脏读、不可重复读、幻读)
  • 化妆品俄罗斯 Honest Sign诚实标签采集技术方案解析
  • Klogg实战:5分钟搞定海量日志中的Error排查(颜色标记+正则过滤技巧)
  • 炉石传说佣兵战记自动化脚本完整指南:5步轻松实现自动战斗
  • RK3588/3568嵌入式视觉开发:为什么我选择OpenCV 3.4.3 + FFmpeg 4.2.9这个“经典组合”?
  • 避开RK3566以太网PHY调试的那些‘坑’:从硬件C15到DTS配置的完整避坑指南
  • 众汇量化以多策略融合与智能投研打造高质量投资体系
  • 告别 GPU 独占时代:用 HAMi 实现训练推理一体化——博维智慧 GPU 虚拟化实战
  • 复合AI系统基准测试与优化实践指南
  • BE-ToF技术:突破传统飞行时间成像的深度感知新方案
  • Vue3 + TypeScript实战:封装一个带实时预览的企业级图片裁剪组件(附完整源码)
  • 在树莓派上玩转framebuffer:手把手教你用C语言点亮第一块屏幕(附完整代码)
  • 麒麟KYLINOS权限设置避坑指南:从图形界面到命令行的完整流程与常见错误排查
  • 为什么你的 Agent 总是跑着跑着就废了?聊聊 Loop 设计里那些坑(文末赠书)
  • 终极RPG Maker游戏资源解密工具:无需安装的浏览器解决方案
  • 告别Python版本冲突!用Anaconda的conda命令5分钟搞定Python 3.8专属虚拟环境
  • MCB900评估板电容选型与电源滤波设计解析
  • 别再复制粘贴了!手把手教你用LaTeX的algorithmicx宏包写出漂亮的算法伪代码