<!-- @format --> <template> <div style="display: flex; width: 100%"> <a-form-item-rest> <div class="rightBox"> <div class="inputArea"> <div style="margin-right: 10px">经度</div> <div class="longitude"> <ns-input v-model:value="longLatTudeobj.longitude" type="number" class="input" placeholder="请输入经度" :disabled="viewOnly" @change="inputChange('longitude', $event)" /> </div ><div style="margin: 0 10px">纬度</div> <div class="latitude"> <ns-input v-model:value="longLatTudeobj.latitude" type="number" class="input" placeholder="请输入纬度" :disabled="viewOnly" @change="inputChange('latitude', $event)" /> </div> </div> <div class="inputSearch" style="margin: 15px 0 15px 0"> <label style="margin-right: 10px">地址</label> <ns-input v-model:value="longLatTudeobj.address" class="inputAdress" :disabled="viewOnly" placeholder="请输入地址" /> <ns-button type="primary" @click="onSearch" :disabled="viewOnly">查询</ns-button> </div> <div class="mapArea"> <div id="map-container"></div> <div v-if="isShowResult" id="map-result" style="overflow: auto"></div> </div> </div> </a-form-item-rest> </div> </template> <script lang="ts"> import { defineComponent, watch, ref, reactive, onMounted, onBeforeUnmount, nextTick } from 'vue'; import AMapLoader from '@amap/amap-jsapi-loader'; import { shallowRef } from 'vue'; import { isArray, isEqual, isEmpty } from 'lodash-es'; export default defineComponent({ name: 'NsMapV2', props: { defaultValue: { type: Array, default: () => { return []; }, }, viewOnly: { type: Boolean, default: false, }, value: { type: Array, default: () => { return []; }, }, fieldMap: { type: Object || Array, default: () => { return []; }, }, formModel: { type: Object || Array, }, //兼容v1写法 longitude: { type: String, default: '', }, latitude: { type: String, default: '', }, defaultAddress: { type: String, default: '', }, //兼容v1写法end }, emits: ['change', 'updata:longLat'], setup(props, { emit }) { let map: Recordable; let geoc: any, localSearch: any, Amap: any; const isShowResult = ref(false); const hasload = ref(false); const longLatTudeobj = ref({ longitude: '', latitude: '', address: '', }); const delay = (time) => { return new Promise((resolve, reject) => { setTimeout(() => { resolve(map); }, time); }); }; const circleDelay = async () => { let res = await delay(100); if (res) { return res; } else { return circleDelay(); } }; //更新值 const updateValue = async (event) => { if (!map) { //循环等待map初始化 await circleDelay(); } if (isArray(event)) { if (!event.length) return; longLatTudeobj.value['latitude'] = event[0] || ''; longLatTudeobj.value['longitude'] = event[1] || ''; longLatTudeobj.value['address'] = event[2] || ''; if (longLatTudeobj.value['latitude'] && longLatTudeobj.value['longitude']) { map.clearMap(); getAddressBylnglat(longLatTudeobj.value, (res) => { longLatTudeobj.value.address = res; }); addMark({ position: [event[1], event[0]] }); map.setFitView(); } } }; const resultPanelClick = (data: { [x: string]: string }) => { if (data && data['location']) { if (data['location']) { const location = data['location']; // 当前marker的经纬度信息 longLatTudeobj.value.longitude = location['lng'].toFixed(6); longLatTudeobj.value.latitude = location['lat'].toFixed(6); } if (data['address']) { longLatTudeobj.value.address = data['address']; } } }; //搜索 const onSearch = () => { isShowResult.value = true; map.clearMap(); if (!localSearch) return; localSearch.search(longLatTudeobj.value.address, (status: string, result: Recordable) => { if (status == 'complete' && result.info == 'OK') { const resultPoi = result['poiList']['pois']; if (resultPoi && resultPoi instanceof Array && resultPoi.length > 0) { const pois = result.poiList.pois; for (let i = 0; i < pois.length; i++) { const poi = pois[i]; const marker = []; marker[i] = addMark({ position: poi.location, // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9] title: poi.name, }); } map.setFitView(); } } else { } }); }; //初始化 const initMap = async () => { AMapLoader.load({ key: '2694972059c3b978de5d7e073efdfc64', // 申请好的Web端开发者Key,首次调用 load 时必填 version: '1.4.15', plugins: ['AMap.Geocoder', 'AMap.PlaceSearch'], }) .then((AMap) => { Amap = AMap; // 需要传入AMap ,否则方法无法调用 map = new AMap.Map('map-container', { // center: [117.000923, 36.675807], resizeEnable: true, zoom: 12, }); //精准搜索插件 geoc = new AMap.Geocoder({ city: '021', }); //模糊匹配插件 AMap.service('AMap.PlaceSearch', function () { // 回调函数 // 实例化PlaceSearch localSearch = new AMap.PlaceSearch({ pageSize: 5, // 每页显示多少行 pageIndex: 1, // 显示的下标从那个开始 type: '', // 类别,可以以|后面加其他类 city: '021', panel: 'map-result', // 服务显示 的面板 autoFitView: true, }); }); if (AMap.event) { // 搜索结果列表的点标记 AMap.event.addListener(localSearch, 'listElementClick', (e) => { resultPanelClick(e['data']); }); // 标记物点击 AMap.event.addListener(localSearch, 'markerClick', (e) => { // console.log('搜索结果标记物点击'); resultPanelClick(e['data']); }); } //不可编辑状态 if (!props.viewOnly) { map.on('click', (e) => { map.clearMap(); getAddressByaddress(e, (res) => { longLatTudeobj.value.address = res; longLatTudeobj.value.latitude = e.lnglat['lat'].toFixed(6); longLatTudeobj.value.longitude = e.lnglat['lng'].toFixed(6); }); addMark({ position: e.lnglat, }); map.setFitView(); }); } }) .catch((e) => {}); }; //根据经纬度搜索 const getAddressBylnglat = (event, callBack) => { geoc.getAddress(event.lnglat, (status, result) => { if (status == 'complete' && result.info == 'OK') { const addComp = result['regeocode']['addressComponent']; let address = addComp.province + addComp.city + addComp.district + addComp.street + addComp.streetNumber; callBack(address, result); } }); }; //根据关键字搜索 const getAddressByaddress = (event, callBack) => { geoc.getAddress(event.lnglat, function (status, result) { if (status == 'complete' && result.info == 'OK') { const addComp = result['regeocode']['addressComponent']; let address = addComp.province + addComp.city + addComp.district + addComp.street + addComp.streetNumber; callBack(address, result); } }); }; //添加点标记 const addMark = (data: Recordable) => { let marker = new Amap.Marker(data); map.add(marker); }; onMounted(async () => { await initMap(); if (props.value.length) { updateValue(props.value); } if (props.defaultValue.length) { updateValue(props.defaultValue); } }); onBeforeUnmount(() => { map.destroy(); // localSearch.render.markerList.clear(); isShowResult.value = false; }); watch( () => props.value, (newv, oldv) => { if (!isEqual(newv, oldv) && !isEqual(newv, longLatTudeobj.value)) { updateValue(newv); } }, { immediate: true, }, ); watch( () => longLatTudeobj.value, (newv, oldv) => { if (newv) { emit('change', [newv['latitude'], newv['longitude'], newv['address']]); } }, { deep: true, }, ); watch( () => props.formModel, (newv, oldv) => { if (!isEmpty(newv) && props.fieldMap.length && !hasload.value) { if (isArray(props.value) && !isEmpty(props.value)) { return; } let longitude = []; props.fieldMap.forEach((el, i) => { longitude[i] = newv[el]; }); updateValue(longitude); hasload.value = true; } }, { immediate: true, }, ); //兼容老的处理方法 watch( // () => [props.latitude, props.longitude, props.defaultAddress], // ([latitude, longitude, defaultAddress]) => { console.log(latitude, longitude, defaultAddress); if (latitude && longitude) { updateValue([latitude, longitude, defaultAddress]); } }, { deep: true, immediate: true, }, ); return { map, isShowResult, longLatTudeobj, onSearch, }; }, }); </script> <style lang="less" scoped> input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { -webkit-appearance: none; } #map-container { height: 400px; } .leftBox, .rightBox { flex: 1; } .inputArea { display: flex; line-height: 30px; } .inputSearch { .inputAdress { width: 344px; margin-right: 10px; } } </style>