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实现压缩图片预览并上传功能(promise封装)

    vue实现压缩图片预览并上传功能(promise封装)

    这篇文章主要为大家详细介绍了vue实现压缩图片预览并上传功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • JS图片懒加载库VueLazyLoad详解

    JS图片懒加载库VueLazyLoad详解

    这篇文章主要为大家介绍了JS图片懒加载库VueLazyLoad示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • vue3封装计时器组件的方法

    vue3封装计时器组件的方法

    这篇文章主要为大家详细介绍了vue3封装计时器组件的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • 解决在Vue中使用axios POST请求变成OPTIONS的问题

    解决在Vue中使用axios POST请求变成OPTIONS的问题

    这篇文章主要介绍了解决在Vue中使用axios POST请求变成OPTIONS的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • vue使用better-scroll实现横向滚动的方法实例

    vue使用better-scroll实现横向滚动的方法实例

    这几天研究项目时,看到了 better-scroll 插件,看着感觉功能挺强,这篇文章主要给大家介绍了关于vue使用better-scroll实现横向滚动的相关资料,需要的朋友可以参考下
    2021-06-06
  • Vue Prop属性功能与用法实例详解

    Vue Prop属性功能与用法实例详解

    这篇文章主要介绍了Vue Prop属性功能与用法,结合实例形式较为详细的分析了vue.js中Prop属性的功能、原理、使用方法及相关操作注意事项,需要的朋友可以参考下
    2019-02-02
  • 解决Vue router-link绑定事件不生效的问题

    解决Vue router-link绑定事件不生效的问题

    这篇文章主要介绍了解决Vue router-link绑定事件不生效的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-07-07
  • 面试题:react和vue的区别分析

    面试题:react和vue的区别分析

    这篇文章主要介绍了react和vue的区别分析,在面试中经常会遇到,小编通过实例文字相结合的形式给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-04-04
  • VUE div click无效的问题及解决

    VUE div click无效的问题及解决

    这篇文章主要介绍了VUE div click无效的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • 详解如何编写一个Vue3响应式系统

    详解如何编写一个Vue3响应式系统

    这篇文章主要为大家学习介绍了如何编写一个Vue3响应式系统,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解一下
    2023-07-07

最新评论