To integrate drag-based location selection using the Amap JavaScript API within a Vue 3 environment, begin by installing the official loader package:
npm install @amap/amap-jsapi-loader
The core mechanism relies on AMapUI.PositionPicker configured in dragMap mode. This allows the map viewport to move while a fixed visual indicator remains centered, triggering reverse geocoding events whenever the panning action stops.
Below is a complete Vue 3 component implementation using the Composition API. The logic isolates map initialization, handles asynchronous API loading, manages lifecycle cleanup, and binds the position picker to update a reactive list of nearby points of interest.
<template>
<section class="location-selector">
<div ref="mapContainerRef" class="viewport"></div>
<div class="results-panel">
<ul class="poi-list">
<li v-for="(place, idx) in nearbyLocations" :key="idx" class="poi-item">
<strong>{{ place.name }}</strong>
<span>{{ place.address }}</span>
</li>
</ul>
</div>
</section>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import AMapLoader from '@amap/amap-jsapi-loader';
const mapContainerRef = ref(null);
const nearbyLocations = ref([]);
let mapInstance = null;
let positionSelector = null;
const setupMap = async () => {
window._AMapSecurityConfig = {
securityJsCode: 'YOUR_SECURITY_CODE',
};
try {
const AMap = await AMapLoader.load({
key: 'YOUR_API_KEY',
version: '2.0',
plugins: ['AMap.Geolocation'],
AMapUI: {
version: '1.1',
plugins: ['misc/PositionPicker'],
},
});
mapInstance = new AMap.Map(mapContainerRef.value, {
resizeEnable: true,
zoom: 15,
viewMode: '2D',
});
const geoControl = new AMap.Geolocation({
enableHighAccuracy: true,
timeout: 8000,
buttonPosition: 'RB',
zoomToAccuracy: true,
});
mapInstance.addControl(geoControl);
geoControl.getCurrentPosition((status, res) => {
if (status === 'complete' && res.position) {
mapInstance.setCenter(res.position);
}
});
positionSelector = new AMapUI.PositionPicker({
mode: 'dragMap',
map: mapInstance,
});
positionSelector.on('success', (result) => {
if (result.regeocode && result.regeocode.pois) {
nearbyLocations.value = result.regeocode.pois.map((p) => ({
name: p.name,
address: p.address,
}));
}
});
positionSelector.on('fail', (err) => {
console.warn('Location selection failed:', err);
});
positionSelector.start();
mapInstance.on('click', (evt) => {
mapInstance.panTo(evt.lnglat);
});
} catch (err) {
console.error('Failed to initialize Amap:', err);
}
};
onMounted(() => {
setupMap();
});
onUnmounted(() => {
if (mapInstance) {
mapInstance.off('click');
mapInstance.destroy();
mapInstance = null;
}
if (positionSelector) {
positionSelector.stop();
}
});
</script>
<style scoped>
.location-selector {
display: flex;
flex-direction: column;
height: 100vh;
background: #f5f7fa;
}
.viewport {
flex: 1;
width: 100%;
min-height: 50vh;
}
.results-panel {
height: 50vh;
overflow-y: auto;
background: #ffffff;
border-top: 1px solid #e0e0e0;
padding: 1rem;
}
.poi-list {
list-style: none;
margin: 0;
padding: 0;
}
.poi-item {
padding: 0.75rem 0;
border-bottom: 1px dashed #eeeeee;
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.poi-item strong {
font-size: 0.95rem;
color: #2c3e50;
}
.poi-item span {
font-size: 0.8rem;
color: #7f8c8d;
}
</style>
The implementation hinges on three primary mechanisms:
- Asynchronous API Resolution:
@amap/amap-jsapi-loaderhandles script injection and returns a promise that resolves with theAMapnamespace. This prevents global scope pollution and ensures all requested plugins are fuly loaded before map instantiation. - PositionPicker in Drag Mode: By setting
mode: 'dragMap', the UI library locks a visual indicator to the center of the viewport. When the user stops panning, the library automatically fires a reverse geocoding request. Thesuccessevent payload containsregeocode.pois, which is mapped to a reactive array for UI rendering. - Lifecycle Management: Map instances and UI controls consume significant memory and attach global event listeners. The
onUnmountedhook explicitly detaches click handlers, stops the position picker, and callsdestroy()on the map instance to prevent memory leaks during route transitions.