Vue3使用高德地图、搜索、地图选点、以及省市区三级联动

1、准备工作

需要在 高德开发平台 申请自己的 key密钥
在这里插入图片描述
这里的 Key 名称大家可以随意填写

在这里插入图片描述
申请完之后我们得到 key密钥
在这里插入图片描述

vue中使用需要安装**@amap/amap-jsapi-loader --save** 官方文档

npm i @amap/amap-jsapi-loader --save

2、代码实现

首先我们需要三个文件,一个 index.vue 一个用来存放省市区的 index.js 文件
一个 map.vue 地图组件

index.vue 代码

<template>
    <el-form :model="form" ref="formRef" class="box-from" label-width="95px" label-position="right">
        <el-form-item label="省市区">
            <el-select v-model="form.province" style="width: 180px;" placeholder="请选择省份" clearable @change="provinceChange"
                @clear="provinceClear">
                <el-option v-for="item in province" :key="item.code" :label="item.value" :value="item.value" />
            </el-select>
            <el-select v-model="form.city" style="width: 180px; margin-left: 5px;" placeholder="请选择市" clearable
                @change="cityChange" :disabled="form.province === ''" @clear="cityClear">
                <el-option v-for="item in city" :key="item.code" :label="item.value" :value="item.value" />
            </el-select>
            <el-select v-model="form.area" style="width: 180px; margin-left: 5px;" placeholder="请选择区" clearable
                :disabled="form.city === ''">
                <el-option v-for="item in area" :key="item.code" :label="item.value" :value="item.value" />
            </el-select>
        </el-form-item>
        <el-form-item label="详细地址">
            <el-input style="width: 500px;" type="textarea" v-model="form.address" placeholder="请输入详细地址"
                clearable></el-input>
            <el-button @click="addressMap" style="margin-left: 5px;">地图跳转</el-button>
        </el-form-item>
        <el-form-item label="地图选择">
            <Map :addressClick="addressClick" ref="mapRef"></Map>
        </el-form-item>
    </el-form>
</template>

<script setup lang="ts">
import {
      
       reactive, ref, toRefs, onMounted } from 'vue';
import {
      
       provinceData } from './index'

const state = reactive({
      
      
    // 表单
    province: provinceData,
    city: [] as any,
    area: [] as any,
    form: {
      
      
        province: '',
        city: '',
        area: '',
        address: ''
    },
})

const {
      
       form, province, city, area } = toRefs(state)

const mapRef = ref('') as any

onMounted(() => {
      
      
	// 这里传后台获取的经纬度
    mapRef.value.fixed(100.179253, 27.096143)
})

// 省份
function provinceChange(value: any) {
      
      
    state.province.forEach(item => {
      
      
        if (item.value === value) {
      
      
            state.city = item.children
        }
    })
}

// 市
function cityChange(value: any) {
      
      
    state.province.forEach(item => {
      
      
        if (item.value === state.form.province) {
      
      
            item.children.forEach(text => {
      
      
                if (text.value === value) {
      
      
                    state.area = text.children
                }
            })
        }
    })
}

// 省清空
function provinceClear() {
      
      
    state.form.city = ""
    state.form.area = ""
}

// 市清空
function cityClear() {
      
      
    state.form.area = ""
}

// 详细地址跳转地图
function addressMap() {
      
      
    mapRef.value.toGetCoordinate(state.form.address)
}


// 地图选位置
// 把获取的信息同步到三级联动
function addressClick(item: any, lng: any, lat: any) {
      
      
    if (item.regeocode.addressComponent.city === '') {
      
      
        state.form.city = item.regeocode.addressComponent.province
    } else {
      
      
        state.form.city = item.regeocode.addressComponent.city
    }
    state.form.province = item.regeocode.addressComponent.province
    state.form.area = item.regeocode.addressComponent.district
    state.form.address = item.regeocode.formattedAddress
    state.province.forEach(item => {
      
      
        if (item.value === state.form.province) {
      
      
            state.city = item.children
            item.children.forEach(text => {
      
      
                if (text.value === state.form.city) {
      
      
                    state.area = text.children
                }
            })
        }
    })
}
</script>

<style lang="scss" scoped></style>

map.vue 代码

<template>
    <div style="width: 100%;">
        <div id="container" class="map"></div>
        <div class="search-box">
            <el-select v-model="address" clearable placeholder="请输入关键词" style="width: 400px;" :remote-method="remoteMethod"
                filterable remote @change="currentSelect" class="one-text" size="default">
                <el-option v-for="(item, index) in areaList" :key="index" :label="item.district + item.name"
                    :value="item.district + item.name">
                    <span>{
   
   { item.district }}</span> <span>{
   
   { item.name }}</span>
                </el-option>
            </el-select>
        </div>
    </div>
</template>

<script setup>
import {
      
       reactive, ref, toRefs, onMounted, nextTick, defineProps } from 'vue';
import AMapLoader from "@amap/amap-jsapi-loader";
const props = defineProps({
      
      
    addressClick: Function,
})
onMounted(() => {
      
      
    window._AMapSecurityConfig = {
      
      
        securityJsCode: '这里放key的安全密钥',
    }
    initMap()
})

const state = reactive({
      
      
    map: null,
    placeSearch: null,
    autoComplete: null,
    marker: null,
    form: {
      
      
        address: '',
        lng: '',
        lat: '',
    },
    areaList: [],
    address: ''
})

const {
      
       areaList, address } = toRefs(state)

function initMap(arr) {
      
      
    AMapLoader.load({
      
      
        key: "这里放你申请的key",
        version: "2.0",
        plugins: ["AMap.ToolBar", "AMap.ControlBar", 'AMap.AutoComplete', 'AMap.PlaceSearch', 'AMap.Geocoder', 'AMap.Marker'],
    }).then((AMap) => {
      
      
        state.map = new AMap.Map('container', {
      
      
            viewMode: "3D",  //  是否为3D地图模式
            zoom: 15,
            center: arr,
            resizeEnable: true
        });
        // 地图放大缩小插件
        let toolBar = new AMap.ToolBar({
      
      
            position: {
      
      
                top: '120px',
                right: '51px'
            }
        })
        // 3D地图插件
        let controlBar = new AMap.ControlBar({
      
      
            position: {
      
      
                top: '20px',
                right: '20px',
            },
        });

        state.geoCoder = new AMap.Geocoder({
      
      
            city: '010', //城市设为北京,默认:“全国”
            radius: 1000 //范围,默认:500
        })

        // 正向地理编码
        state.geocoder = new AMap.Geocoder({
      
      
            city: state.address
        })

        state.autoComplete = new AMap.AutoComplete({
      
       city: '全国' });

        state.map.on('click', (e) => {
      
       // 点击地图事件
            if (!e && !e.lnglat) {
      
      
                return
            }
            state.form.lng = e.lnglat.lng
            state.form.lat = e.lnglat.lat
            removeMarker() // 先删除地图上标记点
            setMapMarker() // 在添加新的标记点
        })
        state.map.addControl(toolBar);   // 添加右上角的放大缩小
        state.map.addControl(controlBar);   // 添加右上角的放大缩小
    }).catch((e) => {
      
      
        console.error(e);  //加载错误提示
    }).finally(() => {
      
      
        removeMarker()
        setMapMarker()
    })
}

function setMapMarker() {
      
      
    if (state.form.lng == '' && state.form.lat == '') {
      
      
        return
    }
    state.map.setFitView()
    state.marker = new AMap.Marker({
      
      
        map: state.map,
        position: [state.form.lng, state.form.lat],
    })
    toGetAddress()
    state.map.setFitView()
    state.map.add(state.marker)
}

function removeMarker() {
      
      
    if (state.marker) {
      
      
        state.map.remove(state.marker)
    }
}

function toGetAddress() {
      
      
    let lnglat = [state.form.lng, state.form.lat]
    state.geoCoder.getAddress(lnglat, (status, result) => {
      
      
        if (status === 'complete' && result.regeocode) {
      
      
            props.addressClick(result, state.form.lng, state.form.lat) // 返回位置信息以及经纬度
        }
    })
}

function remoteMethod(query) {
      
      
    if (query !== '') {
      
      
        setTimeout(() => {
      
      
            state.autoComplete.search(query, (status, result) => {
      
      
                state.areaList = result.tips
            })
        }, 500)
    } else {
      
      
        state.areaList = []
    }
}
function currentSelect(val) {
      
      
    if (!val) {
      
      
        return
    }
    toGetCoordinate(val)
}

function toGetCoordinate(address) {
      
      
    state.geocoder.getLocation(address, function (status, result) {
      
      
        if (status === 'complete' && result.info === 'OK') {
      
      
            initMap([result.geocodes[0].location.lng, result.geocodes[0].location.lat])
            state.form.lng = result.geocodes[0].location.lng
            state.form.lat = result.geocodes[0].location.lat
            state.form.address = result.geocodes[0].formattedAddress
        }
    })
    nextTick(function () {
      
      
        removeMarker()
        setMapMarker()
    })
}

function fixed(lng, lat) {
      
      
    initMap([lng, lat])
    state.form.lng = lng
    state.form.lat = lat
}


// 暴露方法
defineExpose({
      
      
    fixed,
    toGetCoordinate
});
</script>



<style scoped lang="scss">
.map {
      
      
    width: 100%;
    height: 400px;
}

.search-box {
      
      
    position: absolute;
    z-index: 9;
    top: 20px;
    left: 20px;

    ::v-deep(.el-select) {
      
      
        width: 320px;
        border-radius: 50px;
        overflow: hidden;

        .el-input__wrapper {
      
      
            border-radius: 50px;
        }
    }
}
</style>

index.js 代码

这里我以文件的形式上传了,大家直接下载即可 省市区三级联动index.js文件

效果展示
在这里插入图片描述

补充

因为高德地图的搜索每天有限制,可能导致地图上面的搜索无法使用
但是
可以在详细地址那里填写地址信息点击后面按钮跳转地图 (注意:既然是详细地址建议跳转时添加上省市区)

替换自己的key和密钥可以直接使用,如有问题可以私信。

如果对你有帮助麻烦点个赞咯~

猜你喜欢

转载自blog.csdn.net/m0_67584973/article/details/129879071