根据经纬度展示地图,点击选择经纬度按钮打开弹窗(选择地点组件更新,可搜索或自己点击)
父组件
<template>
<div>
<el-row :gutter="24">
<el-col :span="6">
<el-form-item label="经纬度" prop="latLng">
<el-input v-model="latLng" placeholder="请选择经纬度" @clear="clearLatLng" clearable />
</el-form-item>
</el-col>
<el-col :span="6">
<el-button type="primary" @click="openChoose">选择经纬度</el-button>
</el-col>
</el-row>
<lat-lng-area ref="latLngArea"></lat-lng-area>
<lat-lng-choose ref="latLngChoose" @chooseSuccess="chooseSuccess"></lat-lng-choose>
</div>
</template>
<script setup>
import LatLngChoose from "../../latLngChoose/latLngChoose.vue";
import LatLngArea from "../../latLngChoose/latLngArea.vue";
import {useRoute} from "vue-router";
const route = useRoute()
const emit = defineEmits(['success'])
const latLngChoose = ref(null)
const latLngArea = ref(null)
const props = defineProps({
latLng: {
type: String,
default: ''
},
})
const latLng = ref('')
//经纬度
function clearLatLng(){
emit('success', latLng.value)
}
const chooseSuccess = (getLatLng) =>{
latLng.value = getLatLng
emit('success', latLng.value)
}
//经纬度弹窗
const openChoose = ()=>{
nextTick(()=>{
if(latLngChoose.value){
latLngChoose.value.show(latLng.value)
}
})
}
function changeLatLng(value){
console.log(value)
if(value){
latLng.value = value
nextTick(()=>{
if(latLngArea.value){
latLngArea.value.show(latLng.value)
}
})
}else{
latLng.value = value
if(latLngArea.value){
latLngArea.value.resetMapState()
}
}
}
watch(() => props.latLng, value => changeLatLng(value))
</script>
<style scoped>
</style>
展示经纬度位置
<template>
<div>
<div id="map_container" ref="map" style="height: 500px"></div>
</div>
</template>
<script setup>
import { ref, nextTick } from 'vue'
const map = ref(null)
//地图实例
const mapInstance = ref(null)
const poiPickerInstance = ref(null)
const markerInstance = ref(null)
const infoWindowInstance = ref(null)
let initialLatLng = ''
const show = (value)=>{
initialLatLng = value
resetMapState()
makeLat()
}
// 统一清理函数
const resetMapState = () => {
if (poiPickerInstance.value) {
poiPickerInstance.value.destroy()
poiPickerInstance.value = null
}
clearMapOverlays()
}
// 清理函数
const clearMapOverlays = () => {
// 移除标记
if (markerInstance.value) {
markerInstance.value.setMap(null) // 关键:从地图移除
markerInstance.value = null
}
// 关闭信息窗口
if (infoWindowInstance.value) {
infoWindowInstance.value.close() // 关键:关闭窗口
infoWindowInstance.value = null
}
}
const makeLat = () => {
nextTick(() => {
AMapUI.loadUI(['misc/PoiPicker'], function(PoiPicker) {
poiPickerInstance.value = new PoiPicker({
placeSearchOptions: {
map: mapInstance.value,
pageSize: 10
},
});
poiPickerReady(poiPickerInstance.value);
})
function poiPickerReady(poiPicker) {
window.poiPicker=null
window.poiPicker = poiPicker;
markerInstance.value =null
markerInstance.value = new AMap.Marker();
infoWindowInstance.value = null
infoWindowInstance.value = new AMap.InfoWindow({
offset: new AMap.Pixel(0, -20),
isCustom: true, // 使用自定义窗体
autoMove: true, // 是否自动调整窗体到视野内
});
if (initialLatLng) {
const position = new AMap.LngLat(...initialLatLng.split(',').map(Number));
mapInstance.value.setCenter(position);
markerInstance.value.setMap(mapInstance.value);
markerInstance.value.setPosition(position);
// 使用地理编码服务获取地址信息
const geocoder = new AMap.Geocoder();
geocoder.getAddress(position, (status, result) => {
if (status === 'complete' && result.info === 'OK') {
const address = result.regeocode;
infoWindowInstance.value.setContent(`
<div style="
padding: 12px 16px;
width: 280px;
background: white;
border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
transition: all 0.3s ease;
">
<h4 style="
margin: 0 0 6px 0;
padding-bottom: 4px;
border-bottom: 1px solid #eee;
color: #333;
font-size: 15px;
">📌 位置信息</h4>
<div style="
font-size: 13px;
line-height: 2;
color: #666;
">
<div><b>经纬度:</b>${initialLatLng}</div>
<div><b>详细地址:</b>${address.formattedAddress}</div>
</div>
</div>
`);
infoWindowInstance.value.setMap(mapInstance.value);
infoWindowInstance.value.setPosition(position);
infoWindowInstance.value.open(mapInstance.value, position);
}
});
}
}
});
}
onMounted(()=>{
// 创建地图实例
mapInstance.value= new AMap.Map(map.value, {
zoom: 11,
center: [120.30548699999986, 31.86],
});
})
defineExpose({
show,resetMapState
})
</script>
<style>
/* 移除高德地图相关元素 */
.dg, .main, .a{
display: none;
}
.amap-logo, .amap-copyright {
display: none !important;
}
</style>
<style scoped>
html,
body,
#container {
width: 100%;
height: 100%;
margin: 0px;
font-size: 13px;
}
.pickerBox {
position: absolute;
z-index: 9999;
top: 30px; /* 调整位置避免重叠 */
right: 20px;
width: 280px;
}
/* 添加深度选择器处理第三方样式 */
:deep(.amap-layers) {
z-index: 1;
}
:deep(.amap-markers) {
z-index: 999;
}
#pickerInput {
width: 200px;
padding: 5px 5px;
}
.poiInfo {
background: #fff;
}
.amap_lib_placeSearch .poibox.highlight {
background-color: #CAE1FF;
}
.amap_lib_placeSearch .poi-more {
display: none!important;
}
</style>
选择地点
<template>
<el-dialog
title="选择经纬度"
v-model="visible"
width="900px"
append-to-body
destroy-on-close
@close="cancel"
>
<div id="pickerBox">
<input id="pickerInput" placeholder="输入关键字选取地点" />
</div>
<div id="container" style="height: 400px"></div>
<div class="input-card">
<label style="color: grey">
可点击地图或搜索后选择具体位置以获取准确经纬度
</label>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="cancel">取 消</el-button>
<el-button type="primary" @click="submitForm">确 定</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { ref, nextTick } from 'vue'
const visible = ref(false)
const getLatLng = ref('') // 最终经纬度字符串
let initialLatLng = '' // 父组件传入的初始值
let mapObj = null
let currentMarker = null
let infoWindow = null
/* 用于回显/保存的完整信息 */
let currentName = '' // 地点名称
let currentAddress = '' // 详细地址
const emits = defineEmits(['chooseSuccess'])
const show = (latLng) => {
initialLatLng = latLng || ''
visible.value = true
nextTick(() => makeLat())
}
const cancel = () => { visible.value = false }
const submitForm = () => {
if (getLatLng.value) {
/* 把完整信息一起回传,父组件可按需取用 */
emits('chooseSuccess', getLatLng.value)
}
cancel()
}
/* 统一清除旧标记 & 窗体 */
const clearOverlay = () => {
if (currentMarker) { currentMarker.setMap(null); currentMarker = null }
if (infoWindow) { infoWindow.close(); infoWindow = null }
}
/* 创建单个标记 + 信息窗体(点击地图 & 搜索 POI 共用) */
const drawPoint = (lng, lat, name = '', address = '') => {
clearOverlay()
const position = new AMap.LngLat(lng, lat)
currentMarker = new AMap.Marker({ position, map: mapObj })
const titleStr = name || '地图选点'
const addrStr = address || `${lng},${lat}`
infoWindow = new AMap.InfoWindow({
offset: new AMap.Pixel(0, -20),
isCustom: true,
autoMove: true,
content: `
<div style="padding:12px 16px;width:280px;background:#fff;border-radius:8px;box-shadow:0 2px 12px rgba(0,0,0,.1)">
<h4 style="margin:0 0 6px;padding-bottom:4px;border-bottom:1px solid #eee;color:#333;font-size:15px">📌 ${titleStr}</h4>
<div style="font-size:13px;line-height:2;color:#666">
<div><b>经纬度:</b>${lng},${lat}</div>
<div><b>详细地址:</b>${addrStr}</div>
</div>
</div>`
})
infoWindow.open(mapObj, position)
/* 保存到变量,供确定/回显使用 */
getLatLng.value = `${lng},${lat}`
currentName = name
currentAddress = address
}
/* 初始化地图 & 事件 */
const makeLat = () => {
nextTick(() => {
mapObj = new AMap.Map('container', {
zoom: 11,
center: initialLatLng ? initialLatLng.split(',') : [120.30548699999986, 31.86]
})
/* 点击地图选点 */
mapObj.on('click', (e) => {
const lng = e.lnglat.getLng()
const lat = e.lnglat.getLat()
/* 逆地理编码 -> 获取地址描述 */
const geocoder = new AMap.Geocoder({ radius: 1000, extensions: 'base' })
geocoder.getAddress([lng, lat], (status, result) => {
let addr = ''
if (status === 'complete' && result.info === 'OK') {
addr = result.regeocode.formattedAddress
}
drawPoint(lng, lat, '', addr)
})
})
/* 搜索面板 */
AMapUI.loadUI(['misc/PoiPicker'], (PoiPicker) => {
const poiPicker = new PoiPicker({
input: 'pickerInput',
placeSearchOptions: { map: mapObj, pageSize: 10 }
})
poiPicker.on('poiPicked', (poiResult) => {
const { name, location, address } = poiResult.item
drawPoint(location.lng, location.lat, name, address)
mapObj.setCenter(location)
})
})
/* 初始值回显 */
if (initialLatLng) {
const [lng, lat] = initialLatLng.split(',').map(Number)
/* 同样逆地理编码,拿到地址,保证回显时三项完整 */
const geocoder = new AMap.Geocoder({ radius: 1000, extensions: 'base' })
geocoder.getAddress([lng, lat], (status, result) => {
let addr = ''
if (status === 'complete' && result.info === 'OK') addr = result.regeocode.formattedAddress
drawPoint(lng, lat, '', addr)
})
}
})
}
defineExpose({ show })
</script>
<style>
.amap-logo,
.amap-copyright {
display: none !important;
}
</style>