摘要:
需求是填写数据表单时会去选择省市区+具体地址+经纬度,数据的填写与数据的回显!
vue3:
安装amap/amap-jsapi-loader
npm install amap/amap-jsapi-loader
<ChooseMapPoiDialog ref="chooseMapPoiRef" @confirm="selectPoi" />
// 选择坐标
const chooseMapPoiRef = ref()
const openChooseMap = async () => {chooseMapPoiRef.value.open({title: '选择坐标',areaId: formData.value.areaId,address: formData.value.detailAddress,latitude: formData.value.splat,longitude: formData.value.splon})
}const selectPoi = async (addInfo) => {if (addInfo) {formData.value.areaId = addInfo.areaIdformData.value.splon = addInfo.lngformData.value.splat = addInfo.latformData.value.detailAddress = addInfo.address}
}
ChooseMapPoiDialog.vue:
<template><Dialog v-model="dialogVisible" title="选择坐标" width="65%" :close-on-click-modal="false"><div class="dialogModel"><div class="flex" style="margin-top: -10px;margin-bottom: 10px;"><el-input v-model="mapAddress" placeholder="请输入内容" class="!w-240px !mr-10px" /><el-button type="primary" @click="searchInputKeyword"><Icon class="mr-5px" icon="ep:search" />查询</el-button></div><div class="flex !mb-10px"><div class="!w-240px"><div class="searchResModel"><div class="searchResItem" @click="mapValueChangeNew(item.id)" v-for="(item, index) in poiList" :key="index"><p class="poiName">{{ item.name }}</p><p class="poiAddress">{{ item.address }}</p></div></div></div><div style="flex:1;padding-left: 10px;box-sizing:border-box; width: calc(100% - 250px);"><div class="mapModel"><div id="container" class="map" style="height:500px"></div></div></div></div></div><!-- 底部对话框操作按钮 --><template #footer><el-button type="primary" @click="onSelectAddress">确 定</el-button><el-button @click="dialogVisible = false">取 消</el-button></template></Dialog>
</template>
<script lang="ts" setup>
import AMapLoader from "@amap/amap-jsapi-loader";defineOptions({ name: 'ChooseMapPoiDialog' })const message = useMessage() // 消息弹窗
const loading = ref(false)
const title = ref()
const showsearchResult = ref(false)
const thisPosition = ref({areaId: "",address: "",lat: "",lng: ""
})
const poiList = ref<[]>([])
const mapAddress = ref()
const visible = ref()
const latitude = ref()
const longitude = ref()
const mapValue = ref()
const autoCompleteComponent = ref()const map = ref()
const address = ref()
const placeSearchComponent = ref()
const geocoder = ref()/** 打开弹窗 */
const dialogVisible = ref(false)
const open = (data: any) => {dialogVisible.value = truewindow._AMapSecurityConfig = {securityJsCode: 'keykeykeykeykeykeykey',}// const { title, address, name, latitude, longitude } = data// if (title && title.trim().length) title.value = titleif (data.address && data.address.trim().length) {//searchKeyWord(address);mapAddress.value = data.addressthisPosition.value = {areaId: data.areaId,address: data.address,lng: data.longitude,lat: data.latitude}}if (data.latitude && data.longitude) {latitude.value = data.latitudelongitude.value = data.longitude}visible.value = true;nextTick(() => initMap())// activeAppLink.value.path = link}
defineExpose({ open })const close = async () => {visible.value = false;
}
// 初始化搜索
const mapSearchInit = async () => {let autoOptions = {input: "tipInput",}let autoCompleteComponent = new AMap.Autocomplete(autoOptions);autoCompleteComponent.value = autoCompleteComponent;// 注册placeSearch组件placeSearchComponent.value = new AMap.PlaceSearch();if (mapAddress.value) {searchKeyWord(mapAddress.value)}
}const searchInputKeyword = async () => {searchKeyWord(mapAddress.value);
}// 根据输入内容查询
const searchKeyWord = async (query) => {placeSearchComponent.value.search(query, function (status, result) {if (status === 'complete' && result.info === "OK") {showsearchResult.value = truepoiList.value = result.poiList.pois;} else {showsearchResult.value = falsepoiList.value = []message.error("没有查到结果")}})}const mapValueChange = async () => {let items = poiList.value.find((item) => {return item["id"] == mapValue.value})if (items) { markerResult(items) }
}const mapValueChangeNew = async (id) => {let items = poiList.value.find((item) => {return item["id"] == id});if (items)markerResult(items)
}//选择搜索的内容
const markerResult = async (data) => {console.log("data", data)showsearchResult.value = false;address.value = data.name;var marker = new AMap.Marker({position: [Number(data.location.lng), Number(data.location.lat)],})map.value.clearMap() // 清除所有覆盖物(点标志)console.log("marker", marker)map.value.add(marker) // 添加点标志showInfoWindow(marker);setTimeout(() => {map.value.setCenter(data.location);map.value.setZoom(18);}, 50)let lnglat = [data.location.lng, data.location.lat]geocoder.value.getAddress(lnglat, function (status, result) {if (status === 'complete' && result.regeocode) {address.value = result.regeocode.formattedAddress;// adcode.value = result.regeocode.addressComponent.adcode; // 区域IDshowInfoWindow(marker); //自定义信息窗体thisPosition.value = {areaId: parseInt(result.regeocode.addressComponent.adcode),address: data.address + data.name,lng: data.location.lng,lat: data.location.lat};//that.$emit("select", that.thisPosition) //返回给父组件} else {message.error('根据经纬度查询地址失败')}})
}const initMap = () => {AMapLoader.load({// key: "keykeykeykeykeykeykey", // 申请好的Web端开发者Key,首次调用 load 时必填key: "keykeykeykeykeykeykey",version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15plugins: ['AMap.ToolBar','AMap.Scale','AMap.Geolocation','AMap.PlaceSearch','AMap.AutoComplete','AMap.Geocoder','AMap.CitySearch','AMap.DistrictSearch'],resizeEnable: true,}).then((AMap) => {const initParams = {viewMode: "3D", //是否为3D地图模式zoom: 18, //初始化地图级别};if (longitude.value && latitude.value) {initParams.center = [longitude.value, latitude.value]}console.log("initParams", initParams)map.value = new AMap.Map("container", initParams);geocoder.value = new AMap.Geocoder()map.value.addControl(new AMap.Scale()) // 在图面添加比例尺控件,展示地图在当前层级和纬度下的比例尺map.value.addControl(new AMap.ToolBar()) //在图面添加鹰眼控件,在地图右下角显示地图的缩略图handleClick(AMap) //地图选点mapSearchInit();if (longitude.value && latitude.value) {let marker = new AMap.Marker({position: new AMap.LngLat(longitude.value, latitude.value)})map.value.clearMap() // 清除所有覆盖物(点标志)map.value.add(marker) // 添加点标志}}).catch(e => {console.log(e);})
}//点击地图获取地理位置
const handleClick = async () => {map.value.on('click', (e) => {console.log("e", e)let lng = e.lnglat.lnglet lat = e.lnglat.latlet marker = new AMap.Marker({position: new AMap.LngLat(lng, lat)})map.value.clearMap() // 清除所有覆盖物(点标志)map.value.add(marker) // 添加点标志let lnglat = [lng, lat]geocoder.value.getAddress(lnglat, function (status, result) {if (status === 'complete' && result.regeocode) {address.value = result.regeocode.formattedAddress;// adcode.value = result.regeocode.addressComponent.adcode; // 区域IDshowInfoWindow(marker); //自定义信息窗体thisPosition.value = {areaId: parseInt(result.regeocode.addressComponent.adcode),address: address.value,lng: lng,lat: lat};//that.$emit("select", that.thisPosition) //返回给父组件} else {message.error('根据经纬度查询地址失败')}})// 获取点击位置的区域ID// const districtSearch = new AMap.DistrictSearch({// level: "district",// });// districtSearch.search("中国", (status, result) => {// if (status === "complete") {// for (let i = 0; i < result.districtList[0].districtList.length; i++) {// const polygon = new AMap.Polygon({// path: result.districtList[0].districtList[i].boundaries,// strokeWeight: 2,// strokeColor: "#ff33ff",// fillColor: "#f5deb3",// fillOpacity: 0.35,// });// polygon.setMap(map);// // if (polygon.contains(e.lnglat)) {// console.log("点击的区域ID:", result.districtList[0].districtList[i].adcode);// // break;// // }// }// } else {// console.error("获取区域信息失败");// }// });})
}
//新增标记
const showLocation = async (data) => {let marker = new AMap.Marker({position: new AMap.LngLat(data[0], data[1]) //参数为经纬度})map.value.clearMap() // 清除所有覆盖物(点标志)map.value.add(marker) // 添加点标志showInfoWindow(marker); //自定义信息窗体
}//自定义信息窗体
const showInfoWindow = async (marker) => {let infoWindow = new AMap.InfoWindow({isCustom: true, //是否自定义信息窗体content: `<div style="background-color: white;padding: 0 5px; border-radius: 5px;border: 1px solid #cccccc;"> 地址:${address.value}</div>`,closeWhenClickMap: true,zIndex: 999,offset: new AMap.Pixel(16, -35)});infoWindow.open(map.value, marker.getPosition())
}const emit = defineEmits<{(e: 'confirm')
}>()
const onSelectAddress = () => {if (!thisPosition.value.address) {message.error('先选择经纬度')return;}emit('confirm', thisPosition.value)dialogVisible.value = false
}/** 初始化 **/
onMounted(() => {})
</script><style lang="scss" scoped>
.searchResModel {height: 500px;overflow-y: scroll;
}.searchResItem {padding: 10px 0;border-bottom: 1px solid #ccc;cursor: pointer;
}.searchResItem .poiName {font-size: 14px;font-weight: bolder;padding: 0;margin: 0;width: 100%;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 1;-webkit-box-orient: vertical;word-break: break-all;
}.searchResItem .poiAddress {font-size: 12px;color: #8c8c8c;padding: 0;margin-top: 4px;margin-bottom: 0;width: 100%;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 2;-webkit-box-orient: vertical;word-break: break-all;
}.mapModel {height: 500px;
}.map_search_result {position: absolute;top: 80px;left: 40px;background-color: rgba(255, 255, 255, .9);z-index: 1000;
}.map_search_result ul li {}.input-card {bottom: 40px;
}.input-item {height: auto;
}.map {height: 100%;
}
</style>
vue2:
<template>
<el-dialog v-model="visible" align-center :append-to-body="false" :modal-append-to-body="false" draggable :title="title" width="1200px" @close="close"><div class="dialogModel"><div class="flex-x-left" style="margin-top: -10px;margin-bottom: 10px;"><div style="width: 240px;"><el-input v-model="mapAddress" placeholder="请输入内容"></el-input></div><div style="flex:1;margin-left: 10px;"><com-button icon="Search" type="primary" @click="searchInputKeyword">查询</com-button></div></div><div class="flex-x-left" style="margin-bottom: 10px;"><div style="width: 240px;"><div class="searchResModel"><div class="searchResItem" @click="mapValueChangeNew(item.id)" v-for="(item, index) in poiList"><p class="poiName">{{item.name}}</p><p class="poiAddress">{{item.address}}</p></div></div></div><div style="flex:1;padding-left: 10px;box-sizing:border-box; width: calc(100% - 250px);"><div class="mapModel"><div id="container" class="map" style="height:500px"></div></div></div></div></div><template #footer><el-button type="default" @click="close">关闭</el-button><el-button type="primary" @click="onSelectAddress">确定</el-button></template>
</el-dialog>
</template><script>
import AMapLoader from "@amap/amap-jsapi-loader";
window._AMapSecurityConfig = {securityJsCode: 'keykeykeykeykeykeykeykeykey',
}
export default {name: "ChooseMapPoi",data: function () {return {loading: false,showsearchResult: false,thisPosition: {address: "",lat: "",lng: ""},poiList: [],mapAddress: "",mapValue: "",visible: false,title: '选择坐标',latitude: 0,longitude: 0};},computed: {saveText: function () {return this.saveLoading ? "保存中..." : "保存";},},methods: {// options: {address}show(options) {const {title,address,name,latitude,longitude} = options;if (title && title.trim().length) this.title = title;if (address && address.trim().length) {//this.searchKeyWord(address);this.mapAddress = address;this.thisPosition = {address: address,lng: longitude,lat: latitude};}if(latitude && longitude){this.latitude = latitude;this.longitude = longitude;}this.visible = true;this.$nextTick(() => {this.initMap();})},close() {this.visible = false;},/** 初始化搜索 */mapSearchInit() {let autoOptions = {input: "tipInput",}let autoCompleteComponent = new AMap.Autocomplete(autoOptions);this.autoCompleteComponent = autoCompleteComponent;// 注册placeSearch组件this.placeSearchComponent = new AMap.PlaceSearch();// console.log('this.mapAddress2', this.mapAddress);if (this.mapAddress != '') {this.searchKeyWord(this.mapAddress);}},searchInputKeyword() {this.searchKeyWord(this.mapAddress);},//根据输入内容查询searchKeyWord(query) {let that = thisthat.placeSearchComponent.search(query, function (status, result) {// console.log('result:',result);if (status === 'complete' && result.info === "OK") {that.showsearchResult = truethat.poiList = result.poiList.pois;} else {that.showsearchResult = falsethat.poiList = []that.$message({message: "没有查到结果",type: "warning",});}})},mapValueChange() {let that = this;let items = this.poiList.find((item) => {return item["id"] == that.mapValue});if (items)this.markerResult(items);},mapValueChangeNew(id) {let that = this;let items = this.poiList.find((item) => {return item["id"] == id});if (items)this.markerResult(items);},//选择搜索的内容markerResult(data) {this.showsearchResult = false;this.address = data.name;var marker = new AMap.Marker({position: [Number(data.location.lng), Number(data.location.lat)],});this.map.clearMap() // 清除所有覆盖物(点标志)this.map.add(marker) // 添加点标志this.showInfoWindow(marker);setTimeout(() => {this.map.setCenter(data.location);this.map.setZoom(18);}, 50)this.thisPosition = {address: data.address + data.name,lng: data.location.lng,lat: data.location.lat};},onSelectAddress() {if (!this.thisPosition.address) {this.$message.error('先选择经纬度');return;}this.$emit("selectPoi",this.thisPosition)this.close();},initMap() {AMapLoader.load({// key: "keykeykeykeykeykeykey", // 申请好的Web端开发者Key,首次调用 load 时必填key: "keykeykeykeykeykeykey",version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15plugins: ['AMap.ToolBar','AMap.Scale','AMap.Geolocation','AMap.PlaceSearch','AMap.AutoComplete','AMap.Geocoder','AMap.CitySearch'],resizeEnable: true,}).then((AMap) => {const that = this;const initParams = {viewMode: "3D", //是否为3D地图模式zoom: 18, //初始化地图级别};if(this.longitude && this.latitude){initParams.center = [this.longitude,this.latitude]}that.map = new AMap.Map("container", initParams);that.geocoder = new AMap.Geocoder()that.map.addControl(new AMap.Scale()) // 在图面添加比例尺控件,展示地图在当前层级和纬度下的比例尺that.map.addControl(new AMap.ToolBar()) //在图面添加鹰眼控件,在地图右下角显示地图的缩略图that.handleClick(AMap) //地图选点that.mapSearchInit();if(this.longitude && this.latitude){let marker = new AMap.Marker({position: new AMap.LngLat(this.longitude, this.latitude)})this.map.clearMap() // 清除所有覆盖物(点标志)this.map.add(marker) // 添加点标志}}).catch(e => {console.log(e);})},//点击地图获取地理位置handleClick() {this.map.on('click', (e) => {let lng = e.lnglat.lnglet lat = e.lnglat.latlet marker = new AMap.Marker({position: new AMap.LngLat(lng, lat)})this.map.clearMap() // 清除所有覆盖物(点标志)this.map.add(marker) // 添加点标志let lnglat = [lng, lat]let that = thisthat.geocoder.getAddress(lnglat, function (status, result) {if (status === 'complete' && result.regeocode) {that.address = result.regeocode.formattedAddress;that.showInfoWindow(marker); //自定义信息窗体that.thisPosition = {address: that.address,lng: lng,lat: lat};//that.$emit("select", that.thisPosition) //返回给父组件} else {that.$message.error('根据经纬度查询地址失败')}})})},//新增标记showLocation(data) {let marker = new AMap.Marker({position: new AMap.LngLat(data[0], data[1]) //参数为经纬度})this.map.clearMap() // 清除所有覆盖物(点标志)this.map.add(marker) // 添加点标志this.showInfoWindow(marker); //自定义信息窗体},//自定义信息窗体showInfoWindow(marker) {let infoWindow = new AMap.InfoWindow({isCustom: true, //是否自定义信息窗体content: `<div style="background-color: white;padding: 0 5px; border-radius: 5px;border: 1px solid #cccccc;"> 地址:${this.address}</div>`,closeWhenClickMap: true,zIndex: 999,offset: new AMap.Pixel(16, -35)});infoWindow.open(this.map, marker.getPosition());},},// mounted(){// const recaptchaScript = document.createElement("script");// recaptchaScript.setAttribute(// "src",// "https://webapi.amap.com/loader.js"// );// document.head.appendChild(recaptchaScript);// }
};
</script><style lang="scss">.searchResModel {height: 500px;overflow-y: scroll;
}.searchResItem {padding: 10px 0;border-bottom: 1px solid #ccc;cursor: pointer;
}.searchResItem .poiName {font-size: 14px;font-weight: bolder;padding: 0;margin: 0;width: 100%;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 1;-webkit-box-orient: vertical;word-break: break-all;
}.searchResItem .poiAddress {font-size: 12px;color: #8c8c8c;padding: 0;margin-top: 4px;margin-bottom: 0;width: 100%;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 2;-webkit-box-orient: vertical;word-break: break-all;
}.mapModel {height: 500px;
}.map_search_result {position: absolute;top: 80px;left: 40px;background-color: rgba(255, 255, 255, .9);z-index: 1000;
}.map_search_result ul li {}.input-card {bottom: 40px;
}.input-item {height: auto;
}.map {height: 100%;
}
</style>