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

1、准备工作

需要在 高德开发平台 申请自己的 key密钥
Vue3使用高德地图、搜索、地图选点、以及省市区三级联动_第1张图片
这里的 Key 名称大家可以随意填写

Vue3使用高德地图、搜索、地图选点、以及省市区三级联动_第2张图片
申请完之后我们得到 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文件

效果展示
Vue3使用高德地图、搜索、地图选点、以及省市区三级联动_第3张图片

补充

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

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

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

你可能感兴趣的:(Vue,javascript,vue.js,前端)