功能: 1. 根据省市区获取对于的经纬度,设置为地图的center 2. 如果传入了经纬度,则在地图中反显 3. 根据输入内容,调用接口,获取关联关键字的地址列表,点击列表项后,根据地址经纬度,设置地图的center,并显示选中地址的标记 // index.html < script src= "https://map.qq.com/api/gljs?v=1.exp&key=腾讯KEY&libraries=drawing,geometry,autocomplete,convertor" > < / script> < template> < el- dialog v- model= "visible" title= "选择位置" width= "60%" > < div style= "margin-bottom: 8px; display: flex; align-items: center; gap: 8px" > < el- select v- model= "searchKey" filterable remote reserve- keyword placeholder= "搜索地址/关键字,按回车搜索" @change= "handleSelect" : remote- method= "remoteMethod" : loading= "loading" value- key= "address" style= "width: 240px" > < el- option v- for = "(item, index) in options" : key= "index" : label= "item.address" : value= "item" > < div style= "display: flex; align-items: center; gap: 4px" > < span> { { item. address} } < / span> < ! -- < span style= "color: var(--el-text-color-secondary)" > { { item. latitude. toFixed ( 6 ) } } , { { item. longitude. toFixed ( 6 ) } } < / span> -- > < / div> < / el- option> < / el- select> < div style= "margin-left: 12px" > < div> < span style= "color: var(--el-text-color-secondary)" > 坐标< / span> : < strong v- if = "selected.lat" > { { selected. lat. toFixed ( 6 ) } } , { { selected. lng. toFixed ( 6 ) } } < / strong> < span v- else > 未选中< / span> < / div> < ! -- < div style= "max-width: 520px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap" > 地址: { { selected. address|| '无' } } < / div> -- > < / div> < / div> < div ref= "mapContainer" style= "width: 100%; height: 520px; border: 1px solid #eee" > < / div> < template #footer> < div style= "text-align: right" > < el- button @click= "handleCancel" > 取消< / el- button> < el- button type= "primary" : disabled= "!selected.lat" @click= "handleConfirm" > 确认< / el- button> < / div> < / template> < / el- dialog> < / template> < script setup lang= "ts" > import { ref, reactive, computed, nextTick, onBeforeUnmount, watch} from 'vue' ; import { ElMessage} from 'element-plus' ; import type{ PropType} from 'vue' ; import { getGeocoder, GetSuggestion} from '/@/api/store' ; const props= defineProps ( { modelValue : { type : Objectas PropType< { lat? : number; lng? : number; address? : string} > , default : ( ) => ( { } ) , } , initZoom : { type : Number, default : 15 } , } ) ; const emit= defineEmits ( [ 'update:modelValue' , 'confirm' , 'cancel' ] ) ; const options= ref< { address : string; latitude: number; longitude: number} [ ] > ( [ ] ) ; const visible= ref ( false ) ; const mapContainer= ref< HTMLDivElement| null > ( null ) ; const mapInstance : any= ref ( null ) ; // 地图实例 const marker : any= ref ( null ) ; // 地图上的 marker 实例 // let geocoder: any = null; // 地图上的 geocoder 实例 const searchKey= ref ( { } ) ; const selected= reactive ( { lat : 0 as number| null , lng : 0 as number| null , address : '' } ) ; const loading= ref ( false ) ; const remoteMethod = ( query : string) => { console. log ( '🚀 ~ remoteMethod ~ query:' , query) ; if ( query) { loading. value= true ; if ( ! mapInstance. value) { ElMessage. error ( '地图尚未初始化' ) ; return ; } try { GetSuggestion ( { keyword : query} ) . then ( ( res : any) => { console. log ( '🚀 ~ remoteMethod ~ res:' , res) ; if ( res. data&& res. data. result) { options. value= res. data. result; console. log ( '🚀 ~ remoteMethod ~ options.value:' , options. value) ; } else { ElMessage. error ( '地址解析失败,未返回有效坐标' ) ; } } ) . finally ( ( ) => { loading. value= false ; } ) ; } catch ( e) { console. error ( 'getLocation error' , e) ; ElMessage. error ( '搜索失败' ) ; } } else { options. value= [ ] ; } } ; function handleSelect ( ) { console. log ( '111111111111111' , searchKey. value) ; // selectNow.value = selectNow.value.address; selected. address= searchKey. value. address; selected. lat= searchKey. value. latitude; selected. lng= searchKey. value. longitude; nextTick ( ( ) => { addMarker ( new TMap. LatLng ( selected. lat, selected. lng) ) ; // mapInstance.value.clearMarkers(); // 清除之前的标记 mapInstance. value. setCenter ( new TMap. LatLng ( selected. lat, selected. lng) ) ; } ) ; } function openDialog ( data : any) { console. log ( 'searchKey111111111111111' , searchKey) ; searchKey. value= { } ; options. value= [ ] ; visible. value= true ; initMap ( data) ; } const TMap= ( windowas any) . TMap; // 初始化地图 async function initMap ( data : any) { console. log ( '🚀 ~ initMap ~ data:' , data) ; await nextTick ( ) ; if ( ! TMap) { ElMessage. error ( '未检测到腾讯地图 SDK,请确认已在 index.html 中引入' ) ; return ; } let defaultCenter : any; // 1. 确定中心点坐标 if ( ! data. lat&& ! data. lng&& data. address) { console. log ( '适配:使用地址解析' ) ; // 调用地址解析接口,根据地址获取坐标 try { const res : any= await getGeocoder ( { address : data. address} ) ; if ( res. data&& res. data. result) { defaultCenter= new TMap. LatLng ( res. data. result. latitude, res. data. result. longitude) ; } else { ElMessage. error ( '地址解析失败,未返回有效坐标' ) ; return ; } } catch ( error) { console. error ( '地址解析出错' , error) ; ElMessage. error ( '地址解析出错' ) ; return ; } } else if ( data. lat&& data. lng) { console. log ( '直接使用传入的经纬度' ) ; defaultCenter= new TMap. LatLng ( data. lat, data. lng) ; } else { // 如果既没有坐标也没有地址,设置一个默认中心点(例如北京) defaultCenter= new TMap. LatLng ( 39.98412 , 116.307484 ) ; } // 2. 初始化或更新地图 if ( ! mapInstance. value) { // 首次初始化 mapInstance. value= new TMap. Map ( mapContainer. valueas HTMLElement, { center : defaultCenter, zoom : props. initZoom, } ) ; } else { // 如果地图实例已存在,先清理旧的标记,再更新中心点和缩放级别 if ( marker. value) { marker. value. setMap ( null ) ; marker. value= null ; } mapInstance. value. setCenter ( defaultCenter) ; mapInstance. value. setZoom ( props. initZoom) ; } // 3. 绑定点击事件(每次重新绑定确保逻辑最新) // 注意:腾讯地图的 on 方法通常会覆盖之前的同名事件监听,但为了保险起见,先 off 再 on console. log ( '🚀 ~ initMap ~ mapInstance.value:' , mapInstance. value) ; // mapInstance.value.off('click'); mapInstance. value. on ( 'click' , ( e : any) => { addMarker ( e. latLng) ; } ) ; // 4. 如果有初始坐标,添加标记 if ( data. lat&& data. lng) { addMarker ( new TMap. LatLng ( data. lat, data. lng) ) ; } } function addMarker ( latLng : any) { // 如果已存在marker,则先移除 if ( marker. value) { marker. value. setMap ( null ) ; marker. value= null ; } selected. lat= latLng. lat; selected. lng= latLng. lng; // 创建新的marker marker. value= new TMap. MultiMarker ( { map : mapInstance. value, styles : { // 定义marker样式 marker : new TMap. MarkerStyle ( { width : 25 , height : 35 , anchor : { x : 12.5 , y : 35 } , } ) , } , geometries : [ { position : latLng, id : 'marker1' , } , ] , } ) ; } function handleConfirm ( ) { const payload= { lat : selected. latas number, lng : selected. lngas number} ; emit ( 'update:modelValue' , payload) ; emit ( 'confirm' , payload) ; visible. value= false ; } function handleCancel ( ) { // 还原为父级传入值 if ( props. modelValue&& props. modelValue. lat&& props. modelValue. lng) { selected. lat= props. modelValue. lat; selected. lng= props. modelValue. lng; selected. address= props. modelValue. address|| '' ; } else { selected. lat= null ; selected. lng= null ; selected. address= '' ; } emit ( 'cancel' ) ; searchKey. value= { } ; visible. value= false ; } onBeforeUnmount ( ( ) => { try { const TMap= ( windowas any) . TMap; if ( TMap&& TMap. maps&& mapInstance) { mapInstance. value. off ( 'click' ) ; searchKey. value= { } ; options. value= [ ] ; } } catch ( error) { console. error ( '地图销毁出错' , error) ; } } ) ; defineExpose ( { openDialog, } ) ; < / script> < style scoped> . location- picker{ display : flex; align- items: center; } < / style>