现在客户来了一个项目简况:有一个业务场景是添加门店的地址和经纬度,地址可以输入,参考用经纬度当然不行,目前有最好方式就是让用户在地图上搜索或者直接点击获取点的经纬度等详细信息。现在我们就看具体的内容。
登录高德开放平台
创建应用,添加Key,选择Web端(JS API),生成Key和安全密钥
引入地图 JSAPI
项目中使用了官方推荐的 JSAPILoader 来加载地图
安装官方 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 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>加点料:当系统适配了暗黑模式,就通过监听当前暗黑模式状态,当然来动态切换地图浅色主题和深色主题,从而实现地图暗黑模式的适配,这就留给大家自行探索了。欢迎大家关注更多精彩内容。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/128216.html
摘要:五六月份推荐集合查看最新的请点击集前端最近很火的框架资源定时更新,欢迎一下。苏幕遮燎沈香宋周邦彦燎沈香,消溽暑。鸟雀呼晴,侵晓窥檐语。叶上初阳乾宿雨,水面清圆,一一风荷举。家住吴门,久作长安旅。五月渔郎相忆否。小楫轻舟,梦入芙蓉浦。 五、六月份推荐集合 查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 苏...
摘要:五六月份推荐集合查看最新的请点击集前端最近很火的框架资源定时更新,欢迎一下。苏幕遮燎沈香宋周邦彦燎沈香,消溽暑。鸟雀呼晴,侵晓窥檐语。叶上初阳乾宿雨,水面清圆,一一风荷举。家住吴门,久作长安旅。五月渔郎相忆否。小楫轻舟,梦入芙蓉浦。 五、六月份推荐集合 查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 苏...
摘要:安装并引入依赖包这里是说明文档下载依赖包在需要用到的模块引入检查是否引入成功可以在引入的模块中执行控制台显示以上代码表示引入成功配置微信所有需要使用的页面必须先注入配置信息,否则将无法调用开启调试模式调用的所有的返回值会 1.安装并引入JS-SDK依赖包 这里是JS-SDK说明文档 1.1 npm 下载依赖包 npm install weixin-js-sdk --save 1.2.在...
摘要:当属性为合法地名字符串时例外,因为百度地图会根据地名自动调整的值由于百度地图只有一种加载方式,因此组件及其所有子组件的渲染只能是异步的。 在使用vue做项目的时候,有用到百度地图,使用了vue-baidu-map插件,包括拾取位置坐标,搜索位置等 1.引入方式 showImg(https://segmentfault.com/img/bVbv0hs?w=835&h=531); 可在ap...
阅读 925·2023-03-27 18:33
阅读 1178·2023-03-26 17:27
阅读 1120·2023-03-26 17:14
阅读 1061·2023-03-17 21:13
阅读 948·2023-03-17 08:28
阅读 2621·2023-02-27 22:32
阅读 1899·2023-02-27 22:27
阅读 2936·2023-01-20 08:28