Vue3管理后台项目使用高德地图选点的实现

 更新时间:2022年07月12日 09:29:35   作者:三锤  
本文主要介绍了Vue3管理后台项目使用高德地图选点的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

最近在做的管理后台项目中有一个业务场景是添加门店的地址和经纬度,地址可以输入,但经纬度这样处理却不合适,最好是让用户在地图上搜索或者直接点击获取点的经纬度等详细信息。因为我们的app中使用了高德地图,所以管理后台我也选用高德地图来实现上面的业务需求,下面来看一下具体的使用流程吧。

获取地图Key

  • 登录高德开放平台
  • 创建应用,添加Key,选择Web端(JS API),生成Key和安全密钥

引入地图 JSAPI

项目中使用了官方推荐的 JSAPI Loader 来加载地图

  • 安装官方 npm 包 @amap/amap-jsapi-loader
  • 配置安全密钥(不安全的方式),其它配置方式在这里
<script setup>
import AMapLoader from '@amap/amap-jsapi-loader';
window._AMapSecurityConfig = {
  securityJsCode: '你申请的安全密钥',
};
</script>

初始化地图

  • 创建一个id为mapContainer的div元素
  • 调用initMap方法初始化相关地图插件
<script setup>
const map = shallowRef(null);
let AMapObj;
function initMap() {
   AMapLoader.load({
     key: '你申请的Key', 
     version: '2.0',
   }).then(AMap => {
        AMapObj = AMap;
        map.value = new AMap.Map('mapContainer');
      })
}
</script>

地图选点

项目中提供搜索选点和直接点击地图选点两种方法

  • 搜索选点:使用 element-plus 的 autocomplete 组件结合地图搜索服务实现下拉选择地点
  • 点击选点:借助地图点击事件获取地点的经纬度信息,然后使用地图逆地理编码api解析出地址信息 选择地点之后同步绘制 marker 标记,同时将 marker 移动到地图中心点并设置缩放比例

组件化使用

为了方便一整套逻辑的复用,我将以上流程全部封装到一个组件中,通过 v-model 绑定所选地点的详细信息,方便选择地点之后将信息同步到父组件。

下面贴出组件全部的代码

<template>
<div class="map-wrapper">
    <div id="mapcontainer"></div>
    <div class="search-box">
        <el-autocomplete
            v-model="keyword"
            :fetch-suggestions="handleSearch"
            :trigger-on-focus="false"
            clearable
            placeholder="输入城市+关键字搜索"
            @select="handleSelect"
            style="width: 300px"
        />
        <el-input
            v-model="location.longitude"
            placeholder="点击地图选择经度"
            maxlength="15"
            readonly
            style="width: 150px; margin: 0 5px"
        ></el-input>
        <el-input
            v-model="location.latitude"
            placeholder="点击地图选择纬度"
            maxlength="15"
            readonly
            style="width: 150px"
        ></el-input>
    </div>
</div>
</template>

<script setup>
import AMapLoader from '@amap/amap-jsapi-loader';
window._AMapSecurityConfig = {
    securityJsCode: '你申请的安全密钥',
};
const props = defineProps({
    modelValue: {
        type: Object,
        default() {
            return {};
        },
    },
});
const emit = defineEmits(['update:modelValue']);
const map = shallowRef(null);
// 地点
const location = computed({
    get() {
       return props.modelValue;
    },
    set(val) {
       emit('update:modelValue', val);
    },
});
watch(location, (val) => {
    if (val.longitude && val.latitude) {
        drawMarker();
    }
  }
);
const keyword = ref('');
let placeSearch, AMapObj, marker, geocoder;
function initMap() {
    AMapLoader.load({
    key: '', // 申请好的Web端Key,首次调用 load 时必填
    version: '2.0'
    }).then(AMap => {
        AMapObj = AMap;
        map.value = new AMap.Map('mapcontainer');
        // 添加点击事件
        map.value.on('click', onMapClick);
        if (location.value.longitude) {
          drawMarker();
        }
        AMap.plugin(
            ['AMap.ToolBar','AMap.Scale','AMap.Geolocation','AMap.PlaceSearch', 'AMap.Geocoder'],
            () => {
            // 缩放条
            const toolbar = new AMap.ToolBar();
            // 比例尺
            const scale = new AMap.Scale();
            // 定位
            const geolocation = new AMap.Geolocation({
            enableHighAccuracy: true, //是否使用高精度定位,默认:true
            timeout: 10000, //超过10秒后停止定位,默认:5s
            position: 'RT', //定位按钮的停靠位置
            buttonOffset: new AMap.Pixel(10, 20), //定位按钮与设置的停靠位置的偏移量,默认:Pixel(10, 20)
            zoomToAccuracy: true, //定位成功后是否自动调整地图视野到定位点
        });
        geocoder = new AMap.Geocoder({
            city: '全国',
        });
        map.value.addControl(geolocation);
        map.value.addControl(toolbar);
        map.value.addControl(scale);
        placeSearch = new AMap.PlaceSearch({
            map: map.value,
            city: '',
            pageSize: 30, // 单页显示结果条数
            pageIndex: 1, // 页码
            citylimit: false, // 是否强制限制在设置的城市内搜索
            autoFitView: true,
        });
      }
    );
})
}
onMounted(() => {
    initMap();
});
// 搜索地图
function handleSearch(queryString, cb) {
    placeSearch.search(queryString, (status, result) => {
        if (result && typeof result === 'object' && result.poiList) {
            const list = result.poiList.pois;
            list.forEach(item => {
                item.value = item.name;
                item.label = item.name;
            });
            cb(list);
        } else {cb([])}
    });
}
// 点击地图
function onMapClick(e) {
    const { lng, lat } = e.lnglat;
    // 逆地理编码
    geocoder.getAddress([lng, lat], (status, result) => {
        if (status === 'complete' && result.info === 'OK') {
            const { addressComponent, formattedAddress } = result.regeocode;
            let { city, province, district } = addressComponent;
            if (!city) {
                // 直辖市
                city = province;
            }
            location.value = {
                longitude: lng,
                latitude: lat,
                address: formattedAddress,
                zone: [province, city, district],
            };
        }
    });
}
// 点击搜索项
function handleSelect(item) {
    const { pname, cityname, adname, address, name } = item;
    const { lng, lat } = item.location;
    location.value = {
        longitude: lng,
        latitude: lat,
        address,
        zone: [pname, cityname, adname],
        name,
    };
    map.value.setZoomAndCenter(16, [lng, lat]);
}
// 绘制地点marker
function drawMarker(val) {
    const { longitude, latitude } = location.value || val;
    if (marker) {
       marker.setMap(null);
    }
    marker = new AMapObj.Marker({
        position: new AMapObj.LngLat(longitude, latitude),
        anchor: 'bottom-center',
    });
    map.value.add(marker);
    map.value.setZoomAndCenter(16, [longitude, latitude]);
}
</script>

<style lang="scss" scoped>
.map-wrapper {
    position: relative;
    width: 100%;
    height: 400px;
    #mapcontainer {
        width: 100%;
        height: 100%;
    }
    .search-box {
        position: absolute;
        top: 10px;
        left: 10px;
        z-index: 1;
        display: flex;
        align-items: center;
    }
}
</style>

拓展

如果系统适配了暗黑模式,可以通过监听当前暗黑模式状态,来动态切换地图浅色主题和深色主题,从而实现地图暗黑模式的适配,这就留给大家自行探索了。

到此这篇关于Vue3管理后台项目使用高德地图选点的实现的文章就介绍到这了,更多相关Vue3 高德地图选点内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vue axios基于常见业务场景的二次封装的实现

    vue axios基于常见业务场景的二次封装的实现

    这篇文章主要介绍了vue axios基于常见业务场景的二次封装的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-09-09
  • 解决安装arco-design-pro-vue失败问题

    解决安装arco-design-pro-vue失败问题

    这篇文章主要为大家介绍了解决安装arco-design-pro-vue失败的问题方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • Vue指令指令大全

    Vue指令指令大全

    本文为大家介绍了VUE中内置指令包括:v-text,v-html,v-show,v-if,v-else,v-else-if,v-for,v-on,v-bind,v-model,v-pre,v-cloak,v-once
    2019-02-02
  • vue2.0的虚拟DOM渲染思路分析

    vue2.0的虚拟DOM渲染思路分析

    vue2.0采用了虚拟DOM来代替对真实DOM的操作,最后通过某种机制来完成对真实DOM的更新,渲染视图。这篇文章主要介绍了vue2.0的虚拟DOM渲染,需要的朋友可以参考下
    2018-08-08
  • vue 解决文本框被键盘遮住的问题

    vue 解决文本框被键盘遮住的问题

    今天小编就为大家分享一篇vue 解决文本框被键盘遮住的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-11-11
  • vue3中的组件间的传值(props)

    vue3中的组件间的传值(props)

    这篇文章主要介绍了vue3中的组件间的传值(props)问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • vue axios整合使用全攻略

    vue axios整合使用全攻略

    这篇文章主要介绍了vue axios整合使用全攻略,需要的朋友可以参考下
    2018-05-05
  • Vue.js更改调试地址端口号的实例

    Vue.js更改调试地址端口号的实例

    今天小编就为大家分享一篇Vue.js更改调试地址端口号的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • Vue中使用Sortable的示例代码

    Vue中使用Sortable的示例代码

    这篇文章主要介绍了Vue中使用Sortable的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • Intellij IDEA搭建vue-cli项目的方法步骤

    Intellij IDEA搭建vue-cli项目的方法步骤

    这篇文章主要介绍了Intellij IDEA搭建vue-cli项目的方法步骤,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-10-10

最新评论