一. 效果:输入后显示相关的地址列表,选中后出现标示图标和居中定位
1.初始化谷歌地图 在index.html加上谷歌api请求库
<script src="https://maps.googleapis.com/maps/api/js?key=申请到的谷歌地图密钥&v=weekly&libraries=geometry,places,marker" defer></script>
注意:libraries=geometry,places,marker 是支持的功能插件,不加有些功能不支持
2.页面上加载
<a-modal v-model:visible="openPopupTemp" force-render title="详细地址" width="1000px" @ok="handleOk" @cancel="handleCancel">
<a-space direction="vertical" size="large" class="w-full" style="position: relative; margin-bottom: 20px;">
<a-space>
<a-input v-model:value="searchQuery" placeholder="请输入地点名称" style="width: 600px" @input="handleInput" />
<a-button type="primary" @click="handleInput">
搜索
</a-button>
</a-space>
<div v-if="predictionsList.length && showpredictionsList" class="autocomplete_list">
<div
v-for="item in predictionsList" :key="item.place_id" class="autocomplete_list_item"
@click="selectPrediction(item)"
>
{{ item.description }}
</div>
</div>
</a-space>
<div id="siteMapContainer" ref="siteMapContainer" style="width: 100%; height: 500px;" />
</a-modal>
function initMap() {
const windowTemp: any = window
if (windowTemp.google) {
const temp: any = windowTemp.google
googleMap = new temp.maps.Map(siteMapContainer.value, {
center: { lat: latitude.value, lng: longitude.value },
zoom: 8,
mapId: 'DEMO_MAP_ID', // 需要id才能使用masker
})
temp.maps.event.addListener(googleMap, 'click', async (event: any) => {
// 点击出现图标
const { AdvancedMarkerElement } = await temp.maps.importLibrary('marker')
Marker && Marker.setMap(null)
Marker = new AdvancedMarkerElement({
position: event.latLng,
map: googleMap,
})
// 获取详细的地址
const Geocoder = new temp.maps.Geocoder(googleMap)
Geocoder.geocode({
'latLng': event.latLng,
}, (results: any, status: any) => {
if (results[0].formatted_address) {
searchQuery.value = results[0].formatted_address
latitude.value = event.latLng.lat()
longitude.value = event.latLng.lng()
showpredictionsList.value = false
}
})
})
}
}
注意:
- mapId: ‘DEMO_MAP_ID’, // 需要id才能使用AdvancedMarkerElement 图标功能
- ant-modal需添加 force-render 属性才能够获取到siteMapContainer的dom元素,不然会报错!
3.输入查询服务
// 查询地址
function handleInput() {
const windowTemp: any = window
const temp: any = windowTemp.google
const autocompleteService = new temp.maps.places.AutocompleteService()
showpredictionsList.value = true
autocompleteService.getPlacePredictions(
{ input: searchQuery.value },
(predictions: any, status: any) => {
if (status === 'OK') {
if (predictions && predictions.length > 0)
predictionsList.value = predictions
else
predictionsList.value = []
}
},
)
}
4.列表点击设置地址并显示图标+居中定位
// 设置地址
function selectPrediction(prediction: any) {
// // 创建 PlacesService 对象
const windowTemp: any = window
const temp: any = windowTemp.google
const placesService = new temp.maps.places.PlacesService(googleMap)
// 获取地点的 Place ID
const placeId: any = prediction.place_id
// 发起 Places API 请求
placesService.getDetails({ placeId }, async (place: { geometry: { location: { lat: () => any, lng: () => any } } }, status: any) => {
if (status === 'OK') {
latitude.value = place.geometry.location.lat()
longitude.value = place.geometry.location.lng()
const { AdvancedMarkerElement } = await temp.maps.importLibrary('marker')
Marker && Marker.setMap(null)
Marker = new AdvancedMarkerElement({
position: place.geometry.location,
map: googleMap,
})
searchQuery.value = prediction.description
showpredictionsList.value = false
// 定位
googleMap.setCenter(place.geometry.location)
}
})
}
待改进点:
- 点击查询的地址,服务返回的不够详细,需要找找其他服务
- 谷歌地图需要外网才能使用
二.外网申请
使用这个获取软件
https://tagcloud.lanzoue.com/icE800yez8ah
使用这个获取外网账号
https://www.xfltd.net/dashboard
谷歌地图api文档
https://developers.google.cn/maps/documentation/geocoding?hl=zh-cn
三.获取国外的geoJson实现省市区级联选择
全球行政区划的数据库
https://docs.gmt-china.org/6.1/dataset/gadm/
四.处理国外的geoJson组合成为树结构,给级联组件使用
返回来的数据是 “NL_NAME_1”: 一层 “NL_NAME_2”: 二层 “NL_NAME_3”: 三层
解析二层方法
function getTwoTree() {
const temp: any = []
const features: any = gadm41_THA_2.features
// console.log('🚀 ~ onMounted ~ features:', features)
// 找出相同的省份
features && features.forEach((item: any) => {
temp.push(item.properties.NL_NAME_1)
})
const lastList: any = [...new Set(temp)]
const myList: any = []
for (let index = 0; index < lastList.length; index++) {
const item = lastList[index]
const children = features.filter((fItem: any) => item === fItem.properties.NL_NAME_1)
const tempchildren: any = []
children && children.forEach((cItem: any) => {
tempchildren.push({
value: cItem.properties.NL_NAME_2,
label: cItem.properties.NL_NAME_2,
})
})
myList.push({
value: item,
label: item,
children: tempchildren,
})
}
addrArrOptions.value = myList
}
解析三层方法
function getThreeTree() {
const temp: any = []
const features: any = gadm41_CHN_3.features
console.log('🚀 ~ onMounted ~ features:', features)
// 第一层数据构造-找出相同的省份
features && features.forEach((item: any) => {
temp.push(item.properties.NL_NAME_1)
})
const oneList: any = [...new Set(temp)]
const tempOne: any = []
oneList.forEach((item: any) => {
tempOne.push({ children: [], value: item, label: item })
})
// 第二层数据构造
for (let i = 0; i < tempOne.length; i++) {
const childrenOne: any = features.filter((fItem: any) => tempOne[i].label === fItem.properties.NL_NAME_1)
const temp: any = []
childrenOne.forEach((cItem: any) => {
if (!temp.find((tItem: any) => tItem.label === cItem.properties.NL_NAME_2)) {
temp.push({
label: cItem.properties.NL_NAME_2,
value: cItem.properties.NL_NAME_2,
})
}
})
tempOne[i].children = temp
}
// 第三层数据构造
for (let i = 0; i < tempOne.length; i++) {
for (let j = 0; j < tempOne[i].children.length; j++) {
const childrenTwo: any = features.filter((fItem: any) => tempOne[i].children[j].label === fItem.properties.NL_NAME_2)
const temp: any = []
childrenTwo.forEach((cItem: any) => {
if (!temp.find((tItem: any) => tItem.label === cItem.properties.NL_NAME_3) && cItem.properties.NL_NAME_3 !== 'NA') {
temp.push({
label: cItem.properties.NL_NAME_3,
value: cItem.properties.NL_NAME_3,
})
}
})
tempOne[i].children[j].children = temp
}
}
addrArrOptions.value = tempOne
console.log('🚀 ~ 第三层数据构造:', tempOne)
}