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()
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'], },}).then((AMap) => {const centerLngLat = new AMap.LngLat(...props.center)map.value = new AMap.Map("container", {viewMode: "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, 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) {var lnglat = ev.lnglat;if (currentMarker.value) {map.value.remove(currentMarker.value);}currentPosition.value = [lnglat.lng, lnglat.lat];getAddress(lnglat.lng, lnglat.lat, AMap)const icon = new AMap.Icon({size: new AMap.Size(32, 32), imageSize: new AMap.Size(32, 32), image: locationPng, });currentMarker.value = new AMap.Marker({position: lnglat,map: map.value,icon: icon, title: 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();
};
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;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;
}