【开发问题记录】高德地图 Web 端开发详解:高德地图 API 最佳实践指南(安装、marker添加、逆向地理编码、实际业务案例实操)
文章目录
- 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.15plugins: ["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> 容器的 idmap.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.15plugins: ["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>
<scripttype="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"); // 获取地图上的所有 markermarkers.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"); // 获取地图上的所有 markermarkers.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"); // 获取地图上的所有 markermarkers.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"); // 获取地图上的所有 markermarkers.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-rowv-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"); // 获取地图上的所有 markermarkers.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"); // 获取地图上的所有 markermarkers.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-rowv-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"); // 获取地图上的所有 markermarkers.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"); // 获取地图上的所有 markermarkers.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 参考手册
- 高德 常见问题汇总
相关文章:
【开发问题记录】高德地图 Web 端开发详解:高德地图 API 最佳实践指南(安装、marker添加、逆向地理编码、实际业务案例实操)
文章目录 1、引入高德地图的准备工作2、高德地图 JS API 使用方式2.1 JS API Loader2.1.1 使用 script 标签加载loader2.1.2 NPM 安装loader 2.2 script 标签加载 JS API 脚本2.2.1 同步加载2.2.2 异步加载 3、在 vue3 项目中使用3.1 安装 js api loader3.2 在组件中使用 4、实…...
Unity 简单使用Addressables加载SpriteAtlas图集资源
思路很简单,传入图集名和资源名,利用Addressables提供的异步加载方式从ab包中加载。加载完成后存储进缓存字典里,以供后续使用。 添加引用计数,防止多个地方使用同一图集时,不会提前释放 using UnityEngine; using U…...
LangChain 结构化输出:用 Pydantic + PydanticOutputParser 驯服 LLM 的“自由发挥”
目录 一、Pydantic 二、PydanticOutputParser 1、为什么需要 PydanticOutputParser? 2、Pydantic和PydanticOutputParser核心区别 3、Pydantic的不足 (1)无法直接解析非结构化文本 (2)缺乏对 LLM 输出的适配性 …...
快速入手-基于Django-rest-framework的自身组件权限认证(九)
1、在对应的视图函数里增加认证(局部起作用,不全局生效) 导入类: from rest_framework.authentication import ( BasicAuthentication, SessionAuthentication, ) from rest_framework.permissions import IsAuthentica…...
【复活吧,我的爱机!】Ideapad300-15isk拆机升级:加内存条 + 换固态硬盘 + 换电源
写在前面:本博客仅作记录学习之用,部分图片来自网络,如需引用请注明出处,同时如有侵犯您的权益,请联系删除! 文章目录 前言升级成本升级流程电池健康度加内存条和换内存条光驱位加装机械硬盘更换电池重装系…...
基于Spring AI开发本地Jenkins MCP Server服务
前言 首先介绍下MCP是什么? MCP是由开发了 Claude 模型的 Anthropic 公司2024年11月提出并开源的一项开放标准,全称:Model Context Protocol,它是一个开放协议,它使 LLM 应用与外部数据源和工具之间的无缝集成成为可能…...
基于简单神经网络的线性回归
一、概述 本代码实现了一个简单的神经网络进行线性回归任务。通过生成包含噪声的线性数据集,定义一个简单的神经网络类,使用梯度下降算法训练网络以拟合数据,并最终通过可视化展示原始数据、真实线性关系以及模型的预测结果。 二、依赖库 …...
【nvidia】Windows 双 A6000 显卡双显示器驱动更新问题修复
问题描述:windows自动更新nvidia驱动会导致只检测得到一个A6000显卡。 解决方法 下载 A6000 驱动 572.83-quadro-rtx-desktop-notebook-win10-win11-64bit-international-dch-whql.exehttps://download.csdn.net/download/qq_18846849/90554276 不要直接安装。如…...
《SRv6 网络编程:开启IP网络新时代》第2章、第3章:SRv6基本原理和基础协议
背景 根据工作要求、本人掌握的知识情况,仅针对《SRv6 网络编程:开启IP网络新时代》书籍中涉及的部分知识点进行总结梳理,并与工作小组进行分享,不涉及对原作的逐字搬运。 问题 组内同事提出的问题:本文缺扩展头描述…...
如何将AI模型返回的字符串转为html元素?
场景: 接入deepseek模型的api到我们平台,返回的字符串需要做下格式化处理。 返回的数据是这样的: {"role": "assistant","content": "<think>\n嗯,用户问的是“星体是什么”。首先&am…...
Citus源码(1)分布式表行为测试
最近对citus的实现非常好奇,本篇对citus的行为做一些测试。本篇只测行为,不分析源码。后面会继续写一系列文章分析citus源码。 环境:3节点 PG17 with citus。 SELECT citus_set_coordinator_host(127.0.0.1, 3001); SELECT citus_add_node(1…...
装饰器模式与模板方法模式实现MyBatis-Plus QueryWrapper 扩展
pom <dependency><groupId>com.github.yulichang</groupId><artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 --> </dependency>MPJLambdaWrapperX /*** 拓展 MyBatis Plus Join QueryWrapper 类&…...
【PCIE711-214】基于PCIe总线架构的4路HD-SDI/3G-SDI视频图像模拟源
产品概述 PCIE711-214是一款基于PCIE总线架构的4路SDI视频模拟源。该板卡为标准的PCIE插卡,全高尺寸,适合与PCIE总线的工控机或者服务器,板载协议处理器,可以通过PCIE总线将上位机的YUV 422格式视频数据下发通过SDI接口播放出去&…...
突破反爬困境:SDK开发,浏览器模块(七)
声明 本文所讨论的内容及技术均纯属学术交流与技术研究目的,旨在探讨和总结互联网数据流动、前后端技术架构及安全防御中的技术演进。文中提及的各类技术手段和策略均仅供技术人员在合法与合规的前提下进行研究、学习与防御测试之用。 作者不支持亦不鼓励任何未经授…...
rce操作
Linux命令长度突破限制 源码 <?php $param $_REQUEST[param];if ( strlen($param) < 8 ) {echo shell_exec($param); } echo执行函数,$_REQUEST可以接post、get、cookie传参 源码中对参数长度做了限制,小于8位,可以利用临时函数&…...
LabVIEW高效溢流阀测试系统
开发了一种基于LabVIEW软件和PLC硬件的溢流阀测试系统。通过集成神经网络优化的自适应PID控制器,该系统能自动进行压力稳定性、寿命以及动静态性能测试。该设计不仅提升了测试效率,还通过智能化控制提高了数据的精确性和操作的便捷性。 项目背景&…...
Spring Boot 中 JdbcTemplate 处理枚举类型转换 和 减少数据库连接的方法 的详细说明,包含代码示例和关键要点
以下是 Spring Boot 中 JdbcTemplate 处理枚举类型转换 和 减少数据库连接的方法 的详细说明,包含代码示例和关键要点: 一、JdbcTemplate 处理枚举类型转换 1. 场景说明 假设数据库存储的是枚举的 String 或 int 值,但 Java 实体类使用 enu…...
DataGear 5.3.0 制作支持导出表格数据的数据可视化看板
DataGear 内置表格图表底层采用的是DataTable表格组件,默认并未引入导出数据的JS支持库,如果有导出表格数据需求,则可以在看板中引入导出相关JS支持库,制作具有导出CSV、Excel、PDF功能的表格数据看板。 在新发布的5.3.0版本中&a…...
Web网页内嵌 Adobe Pdf Reader 谷歌Chrome在线预览编辑PDF文档
随着数字化办公的普及,PDF文档已成为信息处理的核心载体,虽然桌面端有很多软件可以实现预览编辑PDF文档,而在线在线预览编辑PDF也日益成为一个难题。 作为网页内嵌本地程序的佼佼者——猿大师中间件,之前发布的猿大师办公助手&am…...
歌词json
绽放(4:17) {"lyrics": [{time: 00:00, text: 作词:郑润泽},{time: 00:01, text: 作曲:郑润泽},{time: 00:02, text: 编曲:赵建飞},{time: 00:03, text: 制作人:李淘/赵建飞},{time: 00:09, tex…...
CNG汽车加气站操作工备考真题及答案解析【判断题】
1、燃气经营许可证按照燃气经营规模和类别实行分级审批。(√) 解析:不同规模和类别的燃气经营,其许可证审批级别不同,以确保经营活动的规范和安全。 2、依照《安全生产法》的规定,安全生产监督检查人员对检…...
Sentinel[超详细讲解]-1
定义一系列 规则 👺,对资源进行 保护 👺, 如果违反的了规则,则抛出异常,看是否有fallback兜底处理,如果没有则直接返回异常信息😎 1. 快速入门 1.1 引入 Sentinel 依赖 <depend…...
CUDA专题8—CUDA L2缓存完全指南:从持久化策略到性能优化实战
1. 设备内存L2缓存访问管理 当CUDA内核反复访问全局内存中的某个数据区域时,此类数据访问可视为持久化(persisting)访问。反之,若数据仅被访问一次,则可视为流式(streaming)访问。 从CUDA 11.0开始,计算能力8.0及以上的设备能够调控L2缓存中数据的持久性,从而可能实现更…...
如何让 SQL2API 进化为 Text2API:自然语言生成 API 的深度解析?
在过去的十年里,技术的进步日新月异,尤其是在自动化、人工智能与自然语言处理(NLP)方面。 随着“低代码”平台的崛起,开发者和非技术人员能够更轻松地构建强大而复杂的应用程序。然而,尽管技术门槛降低了&…...
OCCT(2)Windows平台编译OCCT
文章目录 一、Windows平台编译OCCT1、准备环境2、下载源码3、下载第三方库4、使用 CMake 配置5、编译OCCT源码6、运行示例 一、Windows平台编译OCCT 1、准备环境 安装工具: Visual Studio(推荐 VS2019/2022,选择 C 桌面开发 组件࿰…...
【蓝桥杯—单片机】通信总线专项 | 真题整理、解析与拓展 (更新ing...)
通信总线专项 前言SPI第十五届省赛题 UART/RS485/RS232UARTRS485RS232第十三届省赛题小结和拓展:传输方式的分类第十三届省赛 其他相关考点网络传输速率第十五届省赛题第十二届省赛题 前言 在本文中我会把 蓝桥杯单片机赛道 历年真题 中涉及到通信总线的题目整理出…...
【Golang】泛型与类型约束
文章目录 一、环境二、没有泛型的Go三、泛型的优点四、理解泛型(一)定义(二)调用(三)类型约束(Type Constraint)1)接口与约束2)结构体类型约束3)类…...
Uni-app页面信息与元素影响解析
获取窗口信息uni.getWindowInfo {pixelRatio: 3safeArea:{bottom: 778height: 731left: 0right: 375top: 47width: 375}safeAreaInsets: {top: 47, left: 0, right: 0, bottom: 34},screenHeight: 812,screenTop: 0,screenWidth: 375,statusBarHeight: 47,windowBottom: 0,win…...
CentOS(最小化)安装之后,快速搭建Docker环境
本文以VMware虚拟机中安装最小化centos完成后开始。 1. 检查网络 打开网卡/启用网卡 执行命令ip a查看当前的网络连接是否正常: 如果得到的结果和我一样,有ens网卡但是没有ip地址,说明网卡未打开 手动启用: nmcli device sta…...
【身份证证件OCR识别】批量OCR识别身份证照片复印件图片里的文字信息保存表格或改名字,基于QT和腾讯云api_ocr的实现方式
项目背景 在许多业务场景中,需要处理大量身份证照片复印件,手动输入其中的文字信息效率低下且容易出错。利用 OCR(光学字符识别)技术可以自动识别身份证图片中的文字信息,结合 QT 构建图形用户界面,方便用户操作,同时使用腾讯 OCR API 能够保证较高的识别准确率。 界面…...
