摘要:
需求是填写数据表单时会去选择省市区+具体地址+经纬度,数据的填写与数据的回显!
vue3:
bash
安装amap/amap-jsapi-loader
npm install amap/amap-jsapi-loader
bash
<ChooseMapPoiDialog ref="chooseMapPoiRef" @confirm="selectPoi" />
bash
// 选择坐标
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.areaId
formData.value.splon = addInfo.lng
formData.value.splat = addInfo.lat
formData.value.detailAddress = addInfo.address
}
}
ChooseMapPoiDialog.vue:
bash
<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 = true
window._AMapSecurityConfig = {
securityJsCode: 'keykeykeykeykeykeykey',
}
// const { title, address, name, latitude, longitude } = data
// if (title && title.trim().length) title.value = title
if (data.address && data.address.trim().length) {
//searchKeyWord(address);
mapAddress.value = data.address
thisPosition.value = {
areaId: data.areaId,
address: data.address,
lng: data.longitude,
lat: data.latitude
}
}
if (data.latitude && data.longitude) {
latitude.value = data.latitude
longitude.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 = true
poiList.value = result.poiList.pois;
} else {
showsearchResult.value = false
poiList.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; // 区域ID
showInfoWindow(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.15
plugins: [
'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.lng
let lat = e.lnglat.lat
let 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; // 区域ID
showInfoWindow(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:
bash
<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 = this
that.placeSearchComponent.search(query, function (status, result) {
// console.log('result:',result);
if (status === 'complete' && result.info === "OK") {
that.showsearchResult = true
that.poiList = result.poiList.pois;
} else {
that.showsearchResult = false
that.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.15
plugins: [
'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.lng
let lat = e.lnglat.lat
let marker = new AMap.Marker({
position: new AMap.LngLat(lng, lat)
})
this.map.clearMap() // 清除所有覆盖物(点标志)
this.map.add(marker) // 添加点标志
let lnglat = [lng, lat]
let that = this
that.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>