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

Vue3 整合高德地图完成搜索、定位、选址功能,已封装为组件开箱即用(最新)

Vue3 整合高德地图完成搜索、定位、选址功能(最新)

  • 1、效果演示
    • 2、前端代码
      • 2.1 .env.development
      • 2.2 GaodeMap.vue
      • 2.3使用示例

1、效果演示

在这里插入图片描述

在这里插入图片描述

2、前端代码

2.1 .env.development

https://console.amap.com/dev/key/app

在这里插入图片描述

# 地图配置
VITE_AMAP_KEY = "您的高德KEY"
VITE_AMAP_SECURITY_CODE = "您的高德SECURITY_CODE"

2.2 GaodeMap.vue

<template><a-modal v-model:open="isOpen" @ok="submit" @cancel="close" width="100%" wrap-class-name="full-modal"><template #title><div ref="modalTitleRef" class="section-title">地址选择</div></template><!-- 地图容器 --><div id="container" class="map-view"></div><!-- 搜索控制面板 --><a-card class="control-panel" :bordered="false"><div><a-input-search v-model:value="searchKeyword" id="searchInput" placeholder="输入搜索关键词" enter-button@search="handleKeywordSearch" style="border-radius: 10px;" /></div><a-divider class="my-3" /><span class="mb-2">当前选定位置:</span><a-tag class="mt-2" color="#87d068"style="white-space: normal;word-wrap: break-word; overflow-wrap: break-word;font-size: 16px;padding: 8px;">{{ currentAddress }}</a-tag></a-card><div id="searchResults" style="z-index: 100 !important;max-height: 750px;border-radius: 10px;"></div></a-modal>
</template><script setup>
import locationPng from "./location.png"const props = defineProps({center: {type: Array,default: () => ["105.085476", "29.613052"], // 默认内江中心点}
});const isOpen = ref(false);
const onOpen = (record) => {isOpen.value = true;setTimeout(() => {initMap();}, 200);
}
const searchKeyword = ref("内江");
/*** 地图相关*/import AMapLoader from '@amap/amap-jsapi-loader';
const map = ref();// 地图常量配置
const currentPosition = ref([]) 			// 当前位置
const currentAddress = ref("暂无地址")		// 当前定位地址
const provinceCityDistrictInfo = ref("")		// 当前定位地址
const currentMarker = ref()					// 当前marker// 封装定位逻辑
function handleLocation(geolocation, AMap) {geolocation.getCurrentPosition((status, result) => {if (status === 'complete') {console.log('定位成功:', result)currentPosition.value = [result.position.lng, result.position.lat];getAddress(result.position.lng, result.position.lat, AMap)} else {console.warn('定位失败:', result.message)}})
}// 解析地址
function getAddress(lng, lat, AMap) {const geocoder = new AMap.Geocoder({radius: 1000,extensions: 'all',})geocoder.getAddress([lng, lat], (status, result) => {console.log(result);if (status === 'complete' && result.regeocode) {let res = result.regeocode.addressComponent;provinceCityDistrictInfo.value = res.province + res.city + res.district;currentAddress.value = result.regeocode.formattedAddress;searchKeyword.value = result.regeocode.formattedAddress;handleKeywordSearch();}})
}const poiPicker = ref(null);
const placeSearch = ref(null);
// 初始化地图
const initMap = () => {const container = document.getElementById('container');if (!container) {console.error("地图容器不存在,无法初始化");return;}window._AMapSecurityConfig = {securityJsCode: import.meta.env.VITE_AMAP_SECURITY_CODE,};AMapLoader.load({key: import.meta.env.VITE_AMAP_KEY,version: '2.0',plugins: ['AMap.Geocoder','AMap.Circle','AMap.Geolocation','AMap.CitySearch','AMap.CircleEditor','AMap.PlaceSearch','AMap.AutoComplete',],AMapUI: { // 重点就是这个version: '1.1',plugins: ['misc/PoiPicker'], // 需要加载的 AMapUI ui插件},}).then((AMap) => {const centerLngLat = new AMap.LngLat(...props.center)map.value = new AMap.Map("container", {// 设置地图容器idviewMode: "3D", // 是否为3D地图模式zoom: 10, // 初始化地图级别center: centerLngLat, // 初始化地图中心点位置});AMapUI.loadUI(['misc/PoiPicker'], (PoiPicker) => {poiPicker.value = new PoiPicker({input: 'searchInput',placeSearchOptions: {map: map.value,pageSize: 10},searchResultsContainer: 'searchResults'});console.log(poiPicker.value);poiPicker.value.on('poiPicked', (poiResult) => {const poi = poiResult.item;console.log(poi);getAddress(poi.location.lng, poi.location.lat, AMap)});poiPicker.value.searchByKeyword(searchKeyword.value.trim());});// 我的位置 添加定位控件并自动定位const geolocation = new AMap.Geolocation({enableHighAccuracy: true, // 是否使用高精度定位timeout: 10000,           // 超过10秒未获取到定位则自动失败buttonPosition: 'RB',     // 定位按钮位置(右下角)showMarker: true,         // 显示定位点showCircle: true,         // 显示定位精度圆panToLocation: true,      // 定位成功后将地图中心移动到定位位置zoomToAccuracy: true      // 定位成功后调整地图视野范围使定位位置及精度范围可见});map.value.addControl(geolocation);// 获取当前位置并判断是否在圈内handleLocation(geolocation, AMap)// ✅ 监听定位成功geolocation.on('complete', (result) => {console.log('完整定位结果:', result);currentPosition.value = [result.position.lng, result.position.lat];console.log("当前定位坐标", currentPosition.value)getAddress(result.position.lng, result.position.lat, AMap)})map.value.on('click', function (ev) {// 触发事件的地理坐标,AMap.LngLat 类型var lnglat = ev.lnglat;// 如果已经有 marker,先删除if (currentMarker.value) {map.value.remove(currentMarker.value);}currentPosition.value = [lnglat.lng, lnglat.lat];getAddress(lnglat.lng, lnglat.lat, AMap)//创建 AMap.Icon 实例:const icon = new AMap.Icon({size: new AMap.Size(32, 32), //图标尺寸imageSize: new AMap.Size(32, 32),  // 图片的原始尺寸(必须与图片文件实际尺寸一致)image: locationPng, //Icon 的图像});// 创建新的 markercurrentMarker.value = new AMap.Marker({position: lnglat,map: map.value,icon: icon, //添加 icon 图标 URLtitle: currentAddress.value,offset: new AMap.Pixel(-13, -30), //偏移量label: {content: currentAddress.value == '暂无地址' ? '请尝试再次点击' : currentAddress.value, 		// 文本内容direction: 'top', 					// 文本显示在标记的上方offset: new AMap.Pixel(0, -5),		// 偏移量,调整文本位置}});});}).catch((e) => {console.error("地图初始化失败:", e);});
};const handleKeywordSearch = () => {const keyword = searchKeyword.value.trim();if (!keyword) return;poiPicker.value.searchByKeyword(keyword);poiPicker.value.showSearchResults();
};// 声明 emit 事件
const emit = defineEmits(['address'])
const submit = () => {let res = {currentPosition: currentPosition.value,currentAddress: currentAddress.value,provinceCityDistrictInfo: provinceCityDistrictInfo.value}console.log(res);emit('address', res);isOpen.value = false;
}const close = () => {map.value.destroy()map.value = null
}// 抛出函数
defineExpose({onOpen
})
</script><style lang="less" scoped>
.gaode-map-container {position: relative;overflow: "hidden";width: 100%;height: 100%;border-radius: 8px;padding: "48px";text-align: "center";
}.map-view {width: 100%;height: 100%;border-radius: 10px;margin-top: 10px;
}.control-panel {position: absolute;top: 70px;left: 30px;width: 320px;z-index: 10;border-radius: 10px;
}.panel-header {display: flex;justify-content: space-between;align-items: center;
}.current-position {padding: 8px;background-color: #f9f9f9;border-radius: 4px;
}/*** 搜索相关*/#outer-box {height: 100%;padding-right: 300px;
}#container {height: 100%;width: 100%;
}#panel {position: absolute;top: 0;bottom: 0;right: 0;height: 100%;overflow: auto;width: 300px;z-index: 999;border-left: 1px solid #eaeaea;background: #fff;
}#searchBar {height: 30px;background: #ccc;
}#searchInput {width: 100%;height: 30px;line-height: 30%;-webkit-box-sizing: border-box;box-sizing: border-box;border: none;border-bottom: 1px solid #ccc;padding: 0 5px;
}#searchResults {top: 70px;right: 40px;position: absolute;overflow: auto;height: calc(100% - 30px);
}.amap_lib_placeSearch,
.amap-ui-poi-picker-sugg-container {border: none !important;
}.amap_lib_placeSearch .poibox.highlight {background-color: #CAE1FF;
}.poi-more {display: none !important;
}::v-deep(.amap-marker-label) {background-color: rgba(255, 255, 255, 0.9) !important;border: 1px solid #409EFF !important;/* 使用主色调边框 */border-radius: 4px !important;padding: 4px 8px !important;font-size: 13px !important;font-weight: 500 !important;/* 注意:font-weight 使用数字值 */color: #333 !important;box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15) !important;white-space: nowrap !important;
}.section-title {font-size: 16px;font-weight: 500;color: rgba(0, 0, 0, 0.85);padding-left: 8px;border-left: 4px solid #1890ff;
}
</style>

2.3使用示例

<template><a-input-search v-model:value="formData.address" placeholder="请输入地址" allow-clear enter-button="选择地址" @search="mapRef.onOpen()" /><GaodeMapTemplate ref="mapRef" @address="handleUpdateAddress" />
</template>
import GaodeMapTemplate from "./map/GaodeMap.vue";
const mapRef = ref(null)
const handleUpdateAddress = (res) => {formData.value.address = res.currentAddress;			// 地址formData.value.longitude = res.currentPosition[0];		// 经度formData.value.latitude = res.currentPosition[1];		// 纬度formData.value.level4Street = res.provinceCityDistrictInfo;  // 省市区
}
http://www.dtcms.com/a/328495.html

相关文章:

  • 前端对接豆包AI(vue3+TS版本)
  • 力扣-739.每日温度
  • Leetcode-138. 复制带随机指针的链表
  • AI智能体的“四大支柱”:CAP框架核心层、执行层、约束层、操作层详解​
  • 手机蓝牙无感开锁在智能柜锁与智能箱包中的整体解决方案
  • Iptables 详细使用指南
  • 10-docker基于dockerfile自动制作镜像
  • 计算机网络摘星题库800题笔记 第5章 传输层
  • Ansible 详细笔记
  • _init__.py的作用
  • 电路板的GND与外壳地EARTH通过电容电阻相连
  • 操作系统1.6:虚拟机
  • 图形设计器-Qt Designer (一)包含 LinuxCNC 小部件
  • 基于LLVM的memcpy静态分析工具:设计思路与原理解析(C/C++代码实现)
  • 浏览器面试题及详细答案 88道(12-22)
  • word——选项自动对齐(针对试卷中选项对齐)
  • 2025牛客暑期多校训练营3(FDJAEHB)
  • SuperMap GIS基础产品FAQ集锦(20250811)
  • 多级库存预警:浪智WMS智慧化系统的实时监控体系
  • 启保停-----------单相照明灯的接法
  • LaTex论文审稿修改
  • Day 10-2: Mini-GPT完整手写实战 - 从组件组装到文本生成的端到端实现
  • Jmeter性能测试过程中遇到connection reset的解决方案
  • 深入解析 React 中的 useRef Hook
  • 【c++】反向赋值:颠覆传统的数据交互范式
  • day49 力扣42. 接雨水 力扣84.柱状图中最大的矩形
  • 《疯狂Java讲义(第3版)》学习笔记ch1
  • 【C#补全计划】StringBuilder
  • dify是什么?
  • 每日任务day0812:小小勇者成长记之挤牛奶