文章目录
- 1、引入高德地图的准备工作
- 2、高德地图 JS API 使用方式
- 2.1 JS API Loader
- 2.1.1 使用 script 标签加载loader
- 2.1.2 NPM 安装loader
- 2.2 script 标签加载 JS API 脚本
- 2.2.1 同步加载
- 2.2.2 异步加载
- 3、在 vue3 项目中使用
- 3.1 安装 js api loader
- 3.2 在组件中使用
- 4、实际应用
- 4.1 点击地图获取经纬度、设置地图中心点、添加 marker、获取省市区及详细地址
- 4.1.1 准备变量
- 4.1.2 地图点击事件的监听
- 4.1.3 地图添加 marker
- 4.1.4 地图清理 marker的方式
- 4.1.5 调整地图中心点
- 4.1.6 根据经纬度获取详细位置
- 4.2 搜索地点 点击后获取所有信息、设置地图中心点、marker
- 4.2.1 增加输入框、变量
- 4.2.2 POI 搜索
- 4.2.3 处理 点击每个POI 跳转
- 6、完整代码
- 7、总结
1、引入高德地图的准备工作
1、成为 开发者
需要在这个网址上,
注册高德开放平台
的 账号。 高德开放平台官网
2、创建应用
3、创建 Key
找到刚刚创建的应用,然后点击
添加Key
, 选择web端 js api
,这个地方,需要自己起一个名字,然后提交
即可
成功
提交
以后,会在刚刚创建的应用里面,显示出来对应的key
和密钥
2、高德地图 JS API 使用方式
高德地图的加载方式有好几种,高德地图官方 JS API 引入方式
2.1 JS API Loader
这种方式是官方
推荐
的引入方式 ,这种方式主要分为以下俩种
2.1.1 使用 script 标签加载loader
<script src="https://webapi.amap.com/loader.js"></script>
<script type="text/javascript">
window._AMapSecurityConfig = {
securityJsCode: "「你申请的安全密钥」",
};
AMapLoader.load({
key: "替换为你申请的 key", //申请好的 Web 端开发 Key,首次调用 load 时必填
version: "2.0", //指定要加载的 JS API 的版本,缺省时默认为 1.4.15
plugins: ["AMap.Scale"], //需要使用的的插件列表,如比例尺'AMap.Scale',支持添加多个如:['AMap.Scale','...','...']
AMapUI: {
//是否加载 AMapUI,缺省不加载
version: "1.1", //AMapUI 版本
plugins: ["overlay/SimpleMarker"], //需要加载的 AMapUI ui 插件
},
Loca: {
//是否加载 Loca, 缺省不加载
version: "2.0", //Loca 版本
},
})
.then((AMap) => {
var map = new AMap.Map("container"); //"container"为 <div> 容器的 id
map.addControl(new AMap.Scale()); //添加比例尺组件到地图实例上
})
.catch((e) => {
console.error(e); //加载错误提示
});
</script>
2.1.2 NPM 安装loader
npm i @amap/amap-jsapi-loader --save
这种方式更多常见于
工程化项目
中 ,下面演示的时候,也是使用这种方式进行安装 , 也可以使用pnpm
都可以
import AMapLoader from "@amap/amap-jsapi-loader";
window._AMapSecurityConfig = {
securityJsCode: "「你申请的安全密钥」",
};
AMapLoader.load({
key: "替换为你申请的 key", //申请好的 Web 端开发者 Key,首次调用 load 时必填
version: "2.0", //指定要加载的 JS API 的版本,缺省时默认为 1.4.15
plugins: ["AMap.Scale"], //需要使用的的插件列表,如比例尺'AMap.Scale',支持添加多个如:['AMap.Scale','...','...']
})
.then((AMap) => {
var map = new AMap.Map("container"); //"container"为 <div> 容器的 id
})
.catch((e) => {
console.log(e);
});
2.2 script 标签加载 JS API 脚本
2.2.1 同步加载
<!-- 需要设置元素的宽高样式 -->
<div id="container"></div>
<script type="text/javascript">
window._AMapSecurityConfig = {
securityJsCode: "「你申请的安全密钥」",
};
</script>
<script
type="text/javascript"
src="https://webapi.amap.com/maps?v=2.0&key=你申请的key值"
></script>
<script type="text/javascript">
//地图初始化应该在地图容器 <div> 已经添加到 DOM 树之后
var map = new AMap.Map("container", {
zoom: 12,
});
</script>
2.2.2 异步加载
我们项目中就是用的这个方式,但是这个方式会出现
略微的卡顿
,因为浏览器要下载下来这个js 文件,然后解析
<script>
//设置你的安全密钥
window._AMapSecurityConfig = {
securityJsCode: "「你申请的安全密钥」",
};
//声明异步加载回调函数
window.onLoad = function () {
var map = new AMap.Map("container"); //"container"为<div>容器的id
};
var url ="https://webapi.amap.com/maps?v=2.0&key=你申请的key值&callback=onLoad";
var jsapi = document.createElement("script");
jsapi.charset = "utf-8";
jsapi.src = url;
document.head.appendChild(jsapi);
</script>
3、在 vue3 项目中使用
3.1 安装 js api loader
安装 npm 包
npm i @amap/amap-jsapi-loader --save
3.2 在组件中使用
新建一个空白的 vue 组件,里面要写一个 div ,然后设置以下,ID ,然后处理以下这个DIV 的样式,要保证有高度,然后就引入,具体的代码如下
<template>
<div id="MapContainer" ref="mapContainerRef"></div>
</template>
<script setup>
import { onMounted, onUnmounted, ref } from "vue";
import AMapLoader from "@amap/amap-jsapi-loader";
let map = null;
const mapContainerRef = ref(null);
onMounted(() => {
console.log("mapContainerRef", mapContainerRef);
window._AMapSecurityConfig = {
securityJsCode: "", // 「你申请的安全密钥」
};
AMapLoader.load({
key: "", // 申请好的Web端开发者Key,首次调用 load 时必填
version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
})
.then((AMap) => {
map = new AMap.Map("MapContainer", {
// map = new AMap.Map(mapContainerRef.value, {
viewMode: "3D", // 是否为3D地图模式
zoom: 11, // 初始化地图级别
center: [116.397428, 39.90923], // 初始化地图中心点位置
defaultCursor: "pointer",
});
})
.catch((e) => {
console.log(e);
});
});
onUnmounted(() => {
map?.destroy();
});
</script>
<style scoped>
#MapContainer {
width: 100%;
height: 800px;
}
</style>
注意
new AMap.Map
的第一个参数,可以是 DOM元素
或者此元素的ID
,在vue中你可以使用ID
或者ref
来操作这个
defaultCursor
这个属性是配置用户鼠标移入到地图上,显示的图标,就是 css 的cursor: pointer;
4、实际应用
以下列举,我在
实际开发
中,遇到的一些需求点
4.1 点击地图获取经纬度、设置地图中心点、添加 marker、获取省市区及详细地址
需求
:用户 点击地图上的一个后,要添加一个 定位的图标 ,然后 显示出来 用户点击的经纬度、省市区、详细地址。具体的效果看下面这个GIF
4.1.1 准备变量
代码编写
先初始化一个对象,用来存放这些信息
let positionInfo = ref({
lng: 0, // 经度
lat: 0, // 纬度
provinceCode: "", // 省份编号
provinceName: "", // 省份名称
cityCode: "", // 市编号
cityName: "", // 市名称
countyCode: "", // 区编号
countyName: "", // 区名称
address: "", // 详细地址
});
4.1.2 地图点击事件的监听
第一步,肯定是要先看看
高德地图
的api ,有没有鼠标点击
事件,可以看到在高德地图的参考手册上 Map 是可以绑定点击事件的
第二步,代码编写,先新建一个
handleAMapClick
方法,然后在地图初始化完成
后,进行调用,便于下面演示其他的操作
/**
* 处理用户点击 地图的点,就拿到经纬度、省市区、详细地址,并且添加 marker
*/
function handleAMapClick() {
map.on("click", function (e) {
console.log("地图:点击事件", e);
positionInfo.value.lng = e.lnglat.getLng();
positionInfo.value.lat = e.lnglat.getLat();
}
}
其实这个点击事件,是有一个
参数
的 ,里面就有经纬度信息,在高德地图参考手册中,这个lnglat
是非常常见的, lng 就是经度,lat 是纬度;高德地图点击事件官方文档
4.1.3 地图添加 marker
这个时候,其实已经是拿到了,经纬度信息,然后就是要添加一个
标记点
,,添加标记点,需要用到AMap.Marker
方法;高德地图 marker 官方文档
function handleAMapClick() {
map.on("click", function (e) {
console.log("地图:点击事件", e);
positionInfo.value.lng = e.lnglat.getLng();
positionInfo.value.lat = e.lnglat.getLat();
let marker = new AMap.Marker({
position: new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat),
});
map.add(marker);
});
}
这个方法核心就是,你要先创建一个
marker
,然后吧maker
添加到地图
上。AMap.Marker方法接收一个对象,这个对象,最主要的参数就是 position ,需要传递一个LngLat 类型的数据
进去
Lnglat 类型
它是高德地图的一个基础类,具体的使用如下
new AMap.LngLat(lng: Number?, lat: Number?, noWrap: Boolean?)
第一个参数是
经度
,第二个参数是纬度
这样的话,就已经 实现了, 添加
marker
,但是这个地图还存在一个问题
,每次点击都会生成一个新的marker
,需要每次点击的时候,把之前的marker
全部清除掉
4.1.4 地图清理 marker的方式
这个清除
marker
目前我发现有三种方式,分别如下
第一种方式
把这个地图的所有的
marker
都存起来,然后 挨个删除
map 实例上,getAllOverlays 需要接收一个参数(
覆盖物的类型
,比如:marker、circle、polyline、polygon),返回值是一个数组
map 实例上,remove 需要接收 一个或者多个 覆盖物,要么是一个数组,要么是一个覆盖物
- 高德地图API Map.getAllOverlays 文档
- 高德地图API Map.remove 文档
// 这里的map 就是 new AMap.Map 的返回值
const markers = map.getAllOverlays("marker"); // 获取地图上的所有 marker
markers.forEach((f) => map.remove(f));
第二种方式
暴力解决,直接把当前地图的
所有覆盖物
,全部删除
- 高德地图API Map.clearMap 文档
// 这里的map 就是 new AMap.Map 的返回值
map.clearMap(); // 删除地图上所有的覆盖物
第三种方式
使用 Marker 对象的
remove
方法 ,这个方法存在一个缺点,你需要在添加 marker 以后
,要找一个地方存储
起来
// 这里的 marker 指的是, nwe AMap.Marker 的返回值
marker.remove()
- 高德地图API Marker.remove 文档
第四种方式
使用 Marker 对象的
setMap
方法,
// 这里的 marker 指的是, nwe AMap.Marker 的返回值
marker.setMap(null) // 这里需要传递 null
- 高德地图API Marker.setMap 文档
到目前位置代码如下
function handleAMapClick() {
map.on("click", function (e) {
console.log("地图:点击事件", e);
positionInfo.value.lng = e.lnglat.getLng();
positionInfo.value.lat = e.lnglat.getLat();
const markers = map.getAllOverlays("marker"); // 获取地图上的所有 marker
markers.forEach((f) => map.remove(f));
let marker = new AMap.Marker({
position: new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat),
});
map.add(marker);
});
}
4.1.5 调整地图中心点
用户点击后,这个
marker
,已经是到了屏幕的右下角,这个时候就需要调整地图的中心点,让用户始终感觉当前的marker
在 正中心,这个地方,目前发现俩个
处理方式,一个是Map.setCenter
,另一个是Map.setZoomAndCenter
,但这个地方更建议使用setCenter
因为另一个方法需要传递一个zoom
,就是地图的缩放等级
function handleAMapClick() {
map.on("click", function (e) {
console.log("地图:点击事件", e);
positionInfo.value.lng = e.lnglat.getLng();
positionInfo.value.lat = e.lnglat.getLat();
const markers = map.getAllOverlays("marker"); // 获取地图上的所有 marker
markers.forEach((f) => map.remove(f));
let marker = new AMap.Marker({
position: new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat),
});
map.add(marker);
map.setCenter(new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat));
});
}
在添加
marker
以后,再调setCenter
方法即可,具体的效果如下
4.1.6 根据经纬度获取详细位置
设置好地图中心点以后,就要根据
经纬度
获取详细的地址
根据经纬度获取 详细地址 / 根据详细地址获取经纬度, 这两个操作在高德官方 api 文档上,称为正向地理编码
和逆向地理编码
正向地理编码
:详细地址 => 经纬度逆向地理编码
:经纬度 => 详细地址
我们现在要用的就是
逆向地理编码
第一种方式
在控制台,可以输入
AMap
,高德地图会在window上挂在这个key
//引入插件,此示例采用异步引入,更多引入方式 https://lbs.amap.com/api/javascript-api-v2/guide/abc/plugins
AMap.plugin("AMap.Geocoder", function () {
var geocoder = new AMap.Geocoder({
city: "010", // city 指定进行编码查询的城市,支持传入城市名、adcode 和 citycode
});
var lnglat = [116.396574, 39.992706];
geocoder.getAddress(lnglat, function (status, result) {
if (status === "complete" && result.info === "OK") {
// result为对应的地理位置详细信息
console.log(result);
}
});
});
第二种方式
高德地图API AMap.Geocoder 文档
// 这里的 mapObj 就是创建的 Map 实例,也就是 new AMap.Map 的返回值
var geocoder;
//加载地理编码插件
mapObj.plugin(["AMap.Geocoder"], function() { //加载地理编码插件
geocoder = new AMap.Geocoder({
radius: 1000, //以已知坐标为中心点,radius为半径,返回范围内兴趣点和道路信息
extensions: "all" //返回地址描述以及附近兴趣点和道路信息,默认“base”
});
//返回地理编码结果
geocoder.on("complete", geocoder_CallBack);
//逆地理编码
geocoder.getAddress(new AMap.LngLat(116.359119, 39.972121));
});
第三种方式
高德地图api 逆向地理编码调用接口的方式获取
// 调这个接口,传入对应的参数
https://restapi.amap.com/v3/geocode/regeo?output=xml&location=116.310003,39.991957&key=<用户的key>&radius=1000&extensions=all
这里,使用第二种方式,具体的代码如下
/**
* 处理用户点击 地图的点,就拿到经纬度、省市区、详细地址,并且添加 marker
*/
function handleAMapClick() {
map.on("click", function (e) {
console.log("地图:点击事件", e);
positionInfo.value.lng = e.lnglat.getLng();
positionInfo.value.lat = e.lnglat.getLat();
// 这个地方,也需要吧原来的 marker 都清空
// 第一种方式
// map.clearMap(); // 删除地图上所有的覆盖物
// 第二种方式
const markers = map.getAllOverlays("marker"); // 获取地图上的所有 marker
markers.forEach((f) => map.remove(f));
let marker = new AMap.Marker({
position: new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat),
});
map.add(marker);
console.log("marker", marker);
map.setCenter(new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat));
map.plugin("AMap.Geocoder", function () {
let geocoder = new AMap.Geocoder({});
geocoder.getAddress(new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat), function (status, res) {
if (status === "complete" && res.info === "OK") {
// res 为对应的地理位置详细信息
console.log("地图:地图点击 逆向地理编码返回值", res);
positionInfo.value.address = res.regeocode.formattedAddress;
positionInfo.value.provinceCode = res.regeocode.addressComponent.adcode.slice(0, 2);
positionInfo.value.provinceName = res.regeocode.addressComponent.province;
positionInfo.value.cityCode = res.regeocode.addressComponent.adcode.slice(2, 4);
positionInfo.value.cityName = res.regeocode.addressComponent.city || res.regeocode.addressComponent.province;
positionInfo.value.countyCode = res.regeocode.addressComponent.adcode.slice(4, 6);
positionInfo.value.countyName = res.regeocode.addressComponent.district;
}
});
});
});
}
逆向地理编码的 返回值如下
主要使用的就是formattedAddress
、adcode
、province
、city
、district
,这几个是最常用的,adcode 是行政区编码,其他值的含义在这个链接里面 逆向地理编码 返回值 解释
到这里就实现了,第一个需求
4.2 搜索地点 点击后获取所有信息、设置地图中心点、marker
4.2.1 增加输入框、变量
下面这个就是
完成 4.1
之后,又添加 输入框的布局、变量,之后的代码
注意:这次使用的是 UI库是ant-design-vue 4.x 版本
<template>
<div class="MapPage">
<a-row class="MapPage-search">
<a-input-search v-model:value="poiValue" placeholder="输入关键词" size="large" @search="handleSearchClick" />
<div class="MapPage-search-poi">
<a-row
v-for="item in poiList"
:key="item.ID"
style="cursor: pointer; margin-bottom: 5px"
@click="handlePOIItemClick(item)"
>
{{ item.Name }}【{{ item.Address }}】
</a-row>
</div>
</a-row>
<div id="MapContainer" ref="mapContainerRef"></div>
<div class="MapPage-footer">
<a-row> 经度: {{ positionInfo.lng }} , 纬度: {{ positionInfo.lat }} </a-row>
<a-row>省份编号: {{ positionInfo.provinceCode }} 省份名称: {{ positionInfo.provinceName }} </a-row>
<a-row>市编号: {{ positionInfo.cityCode }} 市名称: {{ positionInfo.cityName }} </a-row>
<a-row>区编号: {{ positionInfo.countyCode }} 区名称: {{ positionInfo.countyName }} </a-row>
<a-row>地址: {{ positionInfo.address }} </a-row>
</div>
</div>
</template>
<script setup>
import { onMounted, onUnmounted, ref } from "vue";
import AMapLoader from "@amap/amap-jsapi-loader";
let map = null;
const mapContainerRef = ref(null);
let positionInfo = ref({
lng: 0,
lat: 0,
provinceCode: "",
provinceName: "",
cityCode: "",
cityName: "",
countyCode: "",
countyName: "",
address: "",
});
let poiValue = ref("");
let poiList = ref([]);
onMounted(() => {
console.log("mapContainerRef", mapContainerRef);
window._AMapSecurityConfig = {
securityJsCode: "f22de8e155d91e514b61904b9b10e05a", // 「你申请的安全密钥」
};
AMapLoader.load({
key: "6d4f7a678203e93f42c21145a3b16d43", // 申请好的Web端开发者Key,首次调用 load 时必填
version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
})
.then((AMap) => {
map = new AMap.Map("MapContainer", {
// map = new AMap.Map(mapContainerRef.value, {
viewMode: "3D", // 是否为3D地图模式
zoom: 15, // 初始化地图级别
center: [116.397428, 39.90923], // 初始化地图中心点位置
defaultCursor: "pointer",
});
console.log("地图:实例", map);
handleAMapClick();
})
.catch((e) => {
console.log(e);
});
});
onUnmounted(() => {
map?.destroy();
});
/**
* 处理用户点击 地图的点,就拿到经纬度、省市区、详细地址,并且添加 marker
*/
function handleAMapClick() {
map.on("click", function (e) {
console.log("地图:点击事件", e);
positionInfo.value.lng = e.lnglat.getLng();
positionInfo.value.lat = e.lnglat.getLat();
// 这个地方,也需要吧原来的 marker 都清空
// 第一种方式
// map.clearMap(); // 删除地图上所有的覆盖物
// 第二种方式
const markers = map.getAllOverlays("marker"); // 获取地图上的所有 marker
markers.forEach((f) => map.remove(f));
let marker = new AMap.Marker({
position: new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat),
});
map.add(marker);
console.log("marker", marker);
map.setCenter(new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat));
map.plugin("AMap.Geocoder", function () {
let geocoder = new AMap.Geocoder({});
geocoder.getAddress(new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat), function (status, res) {
if (status === "complete" && res.info === "OK") {
// res 为对应的地理位置详细信息
console.log("地图:地图点击 逆向地理编码返回值", res);
positionInfo.value.address = res.regeocode.formattedAddress;
positionInfo.value.provinceCode = res.regeocode.addressComponent.adcode.slice(0, 2);
positionInfo.value.provinceName = res.regeocode.addressComponent.province;
positionInfo.value.cityCode = res.regeocode.addressComponent.adcode.slice(2, 4);
positionInfo.value.cityName = res.regeocode.addressComponent.city || res.regeocode.addressComponent.province;
positionInfo.value.countyCode = res.regeocode.addressComponent.adcode.slice(4, 6);
positionInfo.value.countyName = res.regeocode.addressComponent.district;
}
});
});
});
}
</script>
<style scoped>
#MapContainer {
width: 100%;
height: 700px;
}
.MapPage-footer {
padding: 0 20px;
}
.MapPage-search {
position: relative;
}
.MapPage-search-poi {
position: absolute;
z-index: 2;
top: 32px;
width: 100%;
background-color: #fff;
}
</style>
4.2.2 POI 搜索
这个 POI 就是
兴趣点
的意思,也可以理解为大多数人想搜索的 地点
。官方的解释如下,关于POI 官方解释
这个POI 也是有多种使用方式
第一种
通过 window 上的 AMap.plugin 来获取POI
官方地址:https://lbs.amap.com/api/javascript-api-v2/guide/services/autocomplete
第二种
通过 地图实例的 plugin 进行加载
官方地址:https://lbs.amap.com/api/javascript-api-v2/documentation#placesearch
第三种
通过调接口的形式进行获取 POI
官方地址:https://lbs.amap.com/api/webservice/guide/api-advanced/search
POI 的返回值如下,这个返回值结构还是比较简单的,如若设置了
extensions: "all"
返回值就会变得复杂了
这个地方,我是用的是 第一种方式,但是这个方式好像是
异步
的,所以又封装了以下,这里的思路就是 根据POI 拿到对应的经纬度
,然后通过经纬度获取具体的地址信息
const handleSearchClick = () => {
console.log("地图:POI 关键字", poiValue.value);
AMap.plugin("AMap.PlaceSearch", function () {
var placeSearch = new AMap.PlaceSearch({
extensions: "base", // base | all ,base 是返回基本信息,all 是返回 完整信息
});
placeSearch.search(poiValue.value, async function (status, res) {
//查询成功时, res 即对应匹配的 POI 信息
console.log("地图:POI 搜索返回值", status, res, res.poiList.pois);
if (status === "complete" && res.info == "OK") {
let formatList = [];
for (const f of res.poiList.pois) {
let item = {};
item.ID = f.id;
item.LngLat = f.location.lng + "," + f.location.lat;
item.Name = f.name;
// 根据经纬度 获取 详细地址
let res = await getAddressByLnglat([f.location.lng, f.location.lat]);
item.Address = res.regeocode.formattedAddress;
formatList.push(item);
}
poiList.value = formatList;
}
});
});
};
/**
* 处理 根据经纬度 获取 详细地址
* @param {Array} lnglat
* @returns {Promise} res
*/
function getAddressByLnglat(lnglat) {
return new Promise((resolve, reject) => {
AMap.plugin("AMap.Geocoder", function () {
let geocoder = new AMap.Geocoder({});
geocoder.getAddress(lnglat, function (status, result) {
if (status === "complete" && result.info === "OK") {
// result为对应的地理位置详细信息
// item.Address = result.regeocode.formattedAddress;
resolve(result);
}
});
});
});
}
4.2.3 处理 点击每个POI 跳转
// 点击每一个 POI 的时候
const handlePOIItemClick = (item) => {
console.log("地图:POI 点击事件", item, item.LngLat.split(","));
positionInfo.value.lng = item.LngLat.split(",")[0];
positionInfo.value.lat = item.LngLat.split(",")[1];
const markers = map.getAllOverlays("marker"); // 获取地图上的所有 marker
markers.forEach((f) => map.remove(f));
let marker = new AMap.Marker({
position: new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat),
});
map.add(marker);
map.setCenter(new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat));
map.plugin("AMap.Geocoder", function () {
let geocoder = new AMap.Geocoder({});
geocoder.getAddress(new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat), function (status, res) {
if (status === "complete" && res.info === "OK") {
// res 为对应的地理位置详细信息
positionInfo.value.address = res.regeocode.formattedAddress;
positionInfo.value.provinceCode = res.regeocode.addressComponent.adcode.slice(0, 2);
positionInfo.value.provinceName = res.regeocode.addressComponent.province;
positionInfo.value.cityCode = res.regeocode.addressComponent.adcode.slice(2, 4);
positionInfo.value.cityName = res.regeocode.addressComponent.city || res.regeocode.addressComponent.province;
positionInfo.value.countyCode = res.regeocode.addressComponent.adcode.slice(4, 6);
positionInfo.value.countyName = res.regeocode.addressComponent.district;
}
poiList.value = [];
poiValue.value = "";
});
});
};
6、完整代码
实现上面两个需求的完整代码如下
<template>
<div class="MapPage">
<a-row class="MapPage-search">
<a-input-search v-model:value="poiValue" placeholder="输入关键词" size="large" @search="handleSearchClick" />
<div class="MapPage-search-poi">
<a-row
v-for="item in poiList"
:key="item.ID"
style="cursor: pointer; margin-bottom: 5px"
@click="handlePOIItemClick(item)"
>
{{ item.Name }}【{{ item.Address }}】
</a-row>
</div>
</a-row>
<div id="MapContainer" ref="mapContainerRef"></div>
<div class="MapPage-footer">
<a-row> 经度: {{ positionInfo.lng }} , 纬度: {{ positionInfo.lat }} </a-row>
<a-row>省份编号: {{ positionInfo.provinceCode }} 省份名称: {{ positionInfo.provinceName }} </a-row>
<a-row>市编号: {{ positionInfo.cityCode }} 市名称: {{ positionInfo.cityName }} </a-row>
<a-row>区编号: {{ positionInfo.countyCode }} 区名称: {{ positionInfo.countyName }} </a-row>
<a-row>地址: {{ positionInfo.address }} </a-row>
</div>
</div>
</template>
<script setup>
import { onMounted, onUnmounted, ref } from "vue";
import AMapLoader from "@amap/amap-jsapi-loader";
let map = null;
const mapContainerRef = ref(null);
let positionInfo = ref({
lng: 0,
lat: 0,
provinceCode: "",
provinceName: "",
cityCode: "",
cityName: "",
countyCode: "",
countyName: "",
address: "",
});
let poiValue = ref("");
let poiList = ref([]);
onMounted(() => {
console.log("mapContainerRef", mapContainerRef);
window._AMapSecurityConfig = {
securityJsCode: "f22de8e155d91e514b61904b9b10e05a", // 「你申请的安全密钥」
};
AMapLoader.load({
key: "6d4f7a678203e93f42c21145a3b16d43", // 申请好的Web端开发者Key,首次调用 load 时必填
version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
})
.then((AMap) => {
map = new AMap.Map("MapContainer", {
// map = new AMap.Map(mapContainerRef.value, {
viewMode: "3D", // 是否为3D地图模式
zoom: 15, // 初始化地图级别
center: [116.397428, 39.90923], // 初始化地图中心点位置
defaultCursor: "pointer",
});
console.log("地图:实例", map);
handleAMapClick();
})
.catch((e) => {
console.log(e);
});
});
onUnmounted(() => {
map?.destroy();
});
/**
* 处理用户点击 地图的点,就拿到经纬度、省市区、详细地址,并且添加 marker
*/
function handleAMapClick() {
map.on("click", function (e) {
console.log("地图:点击事件", e);
positionInfo.value.lng = e.lnglat.getLng();
positionInfo.value.lat = e.lnglat.getLat();
// 这个地方,也需要吧原来的 marker 都清空
// 第一种方式
// map.clearMap(); // 删除地图上所有的覆盖物
// 第二种方式
const markers = map.getAllOverlays("marker"); // 获取地图上的所有 marker
markers.forEach((f) => map.remove(f));
let marker = new AMap.Marker({
position: new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat),
});
map.add(marker);
console.log("marker", marker);
map.setCenter(new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat));
map.plugin("AMap.Geocoder", function () {
let geocoder = new AMap.Geocoder({});
geocoder.getAddress(new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat), function (status, res) {
if (status === "complete" && res.info === "OK") {
// res 为对应的地理位置详细信息
console.log("地图:地图点击 逆向地理编码返回值", res);
positionInfo.value.address = res.regeocode.formattedAddress;
positionInfo.value.provinceCode = res.regeocode.addressComponent.adcode.slice(0, 2);
positionInfo.value.provinceName = res.regeocode.addressComponent.province;
positionInfo.value.cityCode = res.regeocode.addressComponent.adcode.slice(2, 4);
positionInfo.value.cityName = res.regeocode.addressComponent.city || res.regeocode.addressComponent.province;
positionInfo.value.countyCode = res.regeocode.addressComponent.adcode.slice(4, 6);
positionInfo.value.countyName = res.regeocode.addressComponent.district;
}
});
});
});
}
/**
* 处理 搜索按钮点击的时候
*/
const handleSearchClick = () => {
console.log("地图:POI 关键字", poiValue.value);
AMap.plugin("AMap.PlaceSearch", function () {
var placeSearch = new AMap.PlaceSearch({
extensions: "base", // base | all ,base 是返回基本信息,all 是返回 完整信息
});
placeSearch.search(poiValue.value, async function (status, res) {
//查询成功时, res 即对应匹配的 POI 信息
console.log("地图:POI 搜索返回值", status, res, res.poiList.pois);
if (status === "complete" && res.info == "OK") {
let formatList = [];
for (const f of res.poiList.pois) {
let item = {};
item.ID = f.id;
item.LngLat = f.location.lng + "," + f.location.lat;
item.Name = f.name;
// 根据经纬度 获取 详细地址
let res = await getAddressByLnglat([f.location.lng, f.location.lat]);
item.Address = res.regeocode.formattedAddress;
formatList.push(item);
}
poiList.value = formatList;
}
});
});
};
/**
* 处理 根据经纬度 获取 详细地址
* @param {Array} lnglat
* @returns {Promise} res
*/
function getAddressByLnglat(lnglat) {
return new Promise((resolve, reject) => {
AMap.plugin("AMap.Geocoder", function () {
let geocoder = new AMap.Geocoder({});
geocoder.getAddress(lnglat, function (status, result) {
if (status === "complete" && result.info === "OK") {
// result为对应的地理位置详细信息
// item.Address = result.regeocode.formattedAddress;
resolve(result);
}
});
});
});
}
// 点击每一个 POI 的时候
const handlePOIItemClick = (item) => {
console.log("地图:POI 点击事件", item, item.LngLat.split(","));
positionInfo.value.lng = item.LngLat.split(",")[0];
positionInfo.value.lat = item.LngLat.split(",")[1];
const markers = map.getAllOverlays("marker"); // 获取地图上的所有 marker
markers.forEach((f) => map.remove(f));
let marker = new AMap.Marker({
position: new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat),
});
map.add(marker);
map.setCenter(new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat));
map.plugin("AMap.Geocoder", function () {
let geocoder = new AMap.Geocoder({});
geocoder.getAddress(new AMap.LngLat(positionInfo.value.lng, positionInfo.value.lat), function (status, res) {
if (status === "complete" && res.info === "OK") {
// res 为对应的地理位置详细信息
positionInfo.value.address = res.regeocode.formattedAddress;
positionInfo.value.provinceCode = res.regeocode.addressComponent.adcode.slice(0, 2);
positionInfo.value.provinceName = res.regeocode.addressComponent.province;
positionInfo.value.cityCode = res.regeocode.addressComponent.adcode.slice(2, 4);
positionInfo.value.cityName = res.regeocode.addressComponent.city || res.regeocode.addressComponent.province;
positionInfo.value.countyCode = res.regeocode.addressComponent.adcode.slice(4, 6);
positionInfo.value.countyName = res.regeocode.addressComponent.district;
}
poiList.value = [];
poiValue.value = "";
});
});
};
</script>
<style scoped>
#MapContainer {
width: 100%;
height: 700px;
}
.MapPage-footer {
padding: 0 20px;
}
.MapPage-search {
position: relative;
}
.MapPage-search-poi {
position: absolute;
z-index: 2;
top: 32px;
width: 100%;
background-color: #fff;
}
</style>
7、总结
其实对于前端开发来说,最常用的就是
JS API
,但是这个地方,对于一些插件的介绍不完整,特别是返回值
,比如POI 搜索的返回值
、逆向地理编码的返回值
。
还有一个比较常见,就是获取用户当前的位置,这个是要获取读取位置
的权限
的,然后拿到经纬度
,还是要通过逆向地理编码
拿到具体的地址
常用的
链接
,整理如下
- 高德 JS API 官方文档
- 高德 JS API 结合 vue 使用 官方文档
- 高德 JS API 地理编码 与 逆地理编码 官方文档
- 高德 Web 服务 API 官方文档 (插件的返回值都在这里)
- 高德 API 参考手册
- 高德 常见问题汇总