高德地图 Web 端开发详解:高德地图 API 最佳实践指南(安装、marker添加、逆向地理编码、实际业务案例实操)

高德地图 Web 端开发详解:高德地图 API 最佳实践指南(安装、marker添加、逆向地理编码、实际业务案例实操)

文章目录

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
<scriptsrc="https://webapi.amap.com/loader.js"></script><scripttype="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 =newAMap.Map("container");//"container"为 <div> 容器的 id map.addControl(newAMap.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 =newAMap.Map("container");//"container"为 <div> 容器的 id}).catch((e)=>{ console.log(e);});

2.2 script 标签加载 JS API 脚本

2.2.1 同步加载
<!-- 需要设置元素的宽高样式 --><divid="container"></div><scripttype="text/javascript"> window._AMapSecurityConfig ={ securityJsCode:"「你申请的安全密钥」",};</script><scripttype="text/javascript"src="https://webapi.amap.com/maps?v=2.0&key=你申请的key值"></script><scripttype="text/javascript">//地图初始化应该在地图容器 <div> 已经添加到 DOM 树之后var map =newAMap.Map("container",{ zoom:12,});</script>
2.2.2 异步加载
我们项目中就是用的这个方式,但是这个方式会出现略微的卡顿,因为浏览器要下载下来这个js 文件,然后解析
<script>//设置你的安全密钥 window._AMapSecurityConfig ={ securityJsCode:"「你申请的安全密钥」",};//声明异步加载回调函数 window.onLoad=function(){var map =newAMap.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><divid="MapContainer"ref="mapContainerRef"></div></template><scriptsetup>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 =newAMap.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><stylescoped>#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 */functionhandleAMapClick(){ 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 官方文档
functionhandleAMapClick(){ map.on("click",function(e){ console.log("地图:点击事件", e); positionInfo.value.lng = e.lnglat.getLng(); positionInfo.value.lat = e.lnglat.getLat();let marker =newAMap.Marker({ position:newAMap.LngLat(positionInfo.value.lng, positionInfo.value.lat),}); map.add(marker);});}
这个方法核心就是,你要先创建一个 marker ,然后吧 maker 添加到地图上。AMap.Marker方法接收一个对象,这个对象,最主要的参数就是 position ,需要传递一个 LngLat 类型的数据进去

Lnglat 类型

它是高德地图的一个基础类,具体的使用如下
newAMap.LngLat(lng: Number?, lat: Number?, noWrap: Boolean?)
第一个参数是经度,第二个参数是 纬度
在这里插入图片描述
这样的话,就已经 实现了, 添加 marker ,但是这个地图还存在一个问题,每次点击都会生成一个新的 marker ,需要每次点击的时候,把之前的 marker全部清除掉
在这里插入图片描述
4.1.4 地图清理 marker的方式
这个清除 marker 目前我发现有三种方式,分别如下

第一种方式

把这个地图的所有的 marker 都存起来,然后 挨个删除
map 实例上,getAllOverlays 需要接收一个参数(覆盖物的类型,比如:marker、circle、polyline、polygon),返回值是一个数组
map 实例上,remove 需要接收 一个或者多个 覆盖物,要么是一个数组,要么是一个覆盖物
在这里插入图片描述


在这里插入图片描述
// 这里的map 就是 new AMap.Map 的返回值const markers = map.getAllOverlays("marker");// 获取地图上的所有 marker markers.forEach((f)=> map.remove(f));

第二种方式

暴力解决,直接把当前地图的所有覆盖物,全部删除
// 这里的map 就是 new AMap.Map 的返回值 map.clearMap();// 删除地图上所有的覆盖物

第三种方式

使用 Marker 对象的 remove 方法 ,这个方法存在一个缺点,你需要在添加 marker 以后,要找一个地方存储起来
// 这里的 marker 指的是, nwe AMap.Marker 的返回值 marker.remove()

第四种方式

使用 Marker 对象的 setMap 方法,
// 这里的 marker 指的是, nwe AMap.Marker 的返回值 marker.setMap(null)// 这里需要传递 null 
到目前位置代码如下
functionhandleAMapClick(){ 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 =newAMap.Marker({ position:newAMap.LngLat(positionInfo.value.lng, positionInfo.value.lat),}); map.add(marker);});}
4.1.5 调整地图中心点
在这里插入图片描述
用户点击后,这个 marker ,已经是到了屏幕的右下角,这个时候就需要调整地图的中心点,让用户始终感觉当前的 marker 在 正中心,这个地方,目前发现俩个处理方式,一个是 Map.setCenter ,另一个是Map.setZoomAndCenter ,但这个地方更建议使用 setCenter 因为另一个方法需要传递一个 zoom,就是地图的缩放等级
在这里插入图片描述
functionhandleAMapClick(){ 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 =newAMap.Marker({ position:newAMap.LngLat(positionInfo.value.lng, positionInfo.value.lat),}); map.add(marker); map.setCenter(newAMap.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 =newAMap.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 =newAMap.Geocoder({ radius:1000,//以已知坐标为中心点,radius为半径,返回范围内兴趣点和道路信息 extensions:"all"//返回地址描述以及附近兴趣点和道路信息,默认“base”});//返回地理编码结果 geocoder.on("complete", geocoder_CallBack);//逆地理编码 geocoder.getAddress(newAMap.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 */functionhandleAMapClick(){ 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 =newAMap.Marker({ position:newAMap.LngLat(positionInfo.value.lng, positionInfo.value.lat),}); map.add(marker); console.log("marker", marker); map.setCenter(newAMap.LngLat(positionInfo.value.lng, positionInfo.value.lat)); map.plugin("AMap.Geocoder",function(){let geocoder =newAMap.Geocoder({}); geocoder.getAddress(newAMap.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;}});});});}
逆向地理编码的 返回值如下
主要使用的就是 formattedAddressadcodeprovincecitydistrict ,这几个是最常用的,adcode 是行政区编码,其他值的含义在这个链接里面 逆向地理编码 返回值 解释
在这里插入图片描述
到这里就实现了,第一个需求

4.2 搜索地点 点击后获取所有信息、设置地图中心点、marker

在这里插入图片描述
4.2.1 增加输入框、变量
下面这个就是完成 4.1 之后,又添加 输入框的布局、变量,之后的代码
注意:这次使用的是 UI库是 ant-design-vue 4.x 版本
<template><divclass="MapPage"><a-rowclass="MapPage-search"><a-input-searchv-model:value="poiValue"placeholder="输入关键词"size="large"@search="handleSearchClick"/><divclass="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><divid="MapContainer"ref="mapContainerRef"></div><divclass="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><scriptsetup>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 =newAMap.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 */functionhandleAMapClick(){ 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 =newAMap.Marker({ position:newAMap.LngLat(positionInfo.value.lng, positionInfo.value.lat),}); map.add(marker); console.log("marker", marker); map.setCenter(newAMap.LngLat(positionInfo.value.lng, positionInfo.value.lat)); map.plugin("AMap.Geocoder",function(){let geocoder =newAMap.Geocoder({}); geocoder.getAddress(newAMap.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><stylescoped>#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 拿到对应的 经纬度,然后通过经纬度获取具体的地址信息
consthandleSearchClick=()=>{ console.log("地图:POI 关键字", poiValue.value); AMap.plugin("AMap.PlaceSearch",function(){var placeSearch =newAMap.PlaceSearch({ extensions:"base",// base | all ,base 是返回基本信息,all 是返回 完整信息}); placeSearch.search(poiValue.value,asyncfunction(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 =awaitgetAddressByLnglat([f.location.lng, f.location.lat]); item.Address = res.regeocode.formattedAddress; formatList.push(item);} poiList.value = formatList;}});});};/** * 处理 根据经纬度 获取 详细地址 * @param {Array} lnglat * @returns {Promise} res */functiongetAddressByLnglat(lnglat){returnnewPromise((resolve, reject)=>{ AMap.plugin("AMap.Geocoder",function(){let geocoder =newAMap.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 的时候consthandlePOIItemClick=(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 =newAMap.Marker({ position:newAMap.LngLat(positionInfo.value.lng, positionInfo.value.lat),}); map.add(marker); map.setCenter(newAMap.LngLat(positionInfo.value.lng, positionInfo.value.lat)); map.plugin("AMap.Geocoder",function(){let geocoder =newAMap.Geocoder({}); geocoder.getAddress(newAMap.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><divclass="MapPage"><a-rowclass="MapPage-search"><a-input-searchv-model:value="poiValue"placeholder="输入关键词"size="large"@search="handleSearchClick"/><divclass="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><divid="MapContainer"ref="mapContainerRef"></div><divclass="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><scriptsetup>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 =newAMap.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 */functionhandleAMapClick(){ 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 =newAMap.Marker({ position:newAMap.LngLat(positionInfo.value.lng, positionInfo.value.lat),}); map.add(marker); console.log("marker", marker); map.setCenter(newAMap.LngLat(positionInfo.value.lng, positionInfo.value.lat)); map.plugin("AMap.Geocoder",function(){let geocoder =newAMap.Geocoder({}); geocoder.getAddress(newAMap.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;}});});});}/** * 处理 搜索按钮点击的时候 */consthandleSearchClick=()=>{ console.log("地图:POI 关键字", poiValue.value); AMap.plugin("AMap.PlaceSearch",function(){var placeSearch =newAMap.PlaceSearch({ extensions:"base",// base | all ,base 是返回基本信息,all 是返回 完整信息}); placeSearch.search(poiValue.value,asyncfunction(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 =awaitgetAddressByLnglat([f.location.lng, f.location.lat]); item.Address = res.regeocode.formattedAddress; formatList.push(item);} poiList.value = formatList;}});});};/** * 处理 根据经纬度 获取 详细地址 * @param {Array} lnglat * @returns {Promise} res */functiongetAddressByLnglat(lnglat){returnnewPromise((resolve, reject)=>{ AMap.plugin("AMap.Geocoder",function(){let geocoder =newAMap.Geocoder({}); geocoder.getAddress(lnglat,function(status, result){if(status ==="complete"&& result.info ==="OK"){// result为对应的地理位置详细信息// item.Address = result.regeocode.formattedAddress;resolve(result);}});});});}// 点击每一个 POI 的时候consthandlePOIItemClick=(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 =newAMap.Marker({ position:newAMap.LngLat(positionInfo.value.lng, positionInfo.value.lat),}); map.add(marker); map.setCenter(newAMap.LngLat(positionInfo.value.lng, positionInfo.value.lat)); map.plugin("AMap.Geocoder",function(){let geocoder =newAMap.Geocoder({}); geocoder.getAddress(newAMap.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><stylescoped>#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 搜索的返回值逆向地理编码的返回值
还有一个比较常见,就是获取用户当前的位置,这个是要获取 读取位置权限的,然后拿到 经纬度,还是要通过 逆向地理编码 拿到具体的地址
在这里插入图片描述
常用的 链接,整理如下

Read more

百川2-13B-Chat WebUI v1.0 故障排查手册:网页打不开、响应慢、中断不完整等6大问题解决

百川2-13B-Chat WebUI v1.0 故障排查手册:网页打不开、响应慢、中断不完整等6大问题解决 你是不是也遇到过这种情况:兴致勃勃地部署好了百川2-13B-Chat WebUI,准备大展身手,结果浏览器一打开——网页死活打不开。或者好不容易进去了,问个问题等半天没反应,好不容易有反应了,回答到一半又断了。 别急,这些问题我都遇到过。今天我就把自己踩过的坑和解决方法整理出来,帮你快速定位和解决百川2-13B-Chat WebUI v1.0的常见问题。无论你是刚部署完的新手,还是用了一段时间遇到突发状况,这份手册都能帮到你。 1. 问题一:网页打不开,显示“无法访问此网站” 这是最常见的问题,通常有几种可能的原因。咱们一步步来排查。 1.1 检查服务是否真的在运行 首先,打开终端,运行状态检查脚本: /root/baichuan2-13b-webui/check.sh 你会看到类似这样的输出: ╔══════════════════════════════════════════════════════════════╗ ║ 百川2-13B-Chat We

Open-WebUI—开箱即用的AI对话可视化神器

Open-WebUI—开箱即用的AI对话可视化神器

你是否曾兴奋地在本地部署了Ollama,却很快被冰冷的命令行和繁琐的指令劝退?是否羡慕ChatGPT那样优雅的聊天界面,却又希望数据能牢牢掌握在自己手中?OpenWebUI。这个在GitHub上狂揽 110,000 Stars 的明星项目,完美地解决了所有痛点 github地址: https://github.com/open-webui/open-webui 1.什么是Open WebUI? Open WebUI 是一款专为大型语言模型(LLM)设计的 开源可视化交互框架,它通过简洁的Web界面,让用户无需编写代码即可与本地部署的AI模型/各大服务商提供大模型API(如DeepSeek、Llama、ChatGLM等)进行自然对话。其核心使命是 “让LLM私有化部署像打开浏览器一样简单” ,尤其适合需要快速搭建企业级AI平台或追求数据隐私的开发者。 2. 核心价值 * 开箱即用:无需复杂的前端开发,快速搭建 AI 交互界面。完全开源,可自由部署、修改和二次开发,无商业使用限制。 * 多模型支持:兼容 Ollama、

鸿蒙 HarmonyOS 6 | 混合开发 (01) Web 组件内核——ArkWeb 加载机制与 Cookie 管理

鸿蒙 HarmonyOS 6 | 混合开发 (01) Web 组件内核——ArkWeb 加载机制与 Cookie 管理

文章目录 * 前言 * 一、 Web 组件的控制核心:WebviewController * 二、 掌控加载生命周期:优化加载与异常反馈 * 三、 跨端状态同步:Cookie 管理与持久化 * 四、 实战 构建具备完整状态闭环的 ArkWeb 浏览器容器 * 五、 总结 前言 在移动应用开发中,原生开发(Native)与网页开发(Web)的融合方案(Hybrid)已成为商业应用的标配。营销活动页、动态协议、复杂的可视化报表等场景,通常依赖 Web 生态的灵活性与更新效率。因此,在鸿蒙原生应用中高性能地嵌入 H5 页面,是开发者必须掌握的核心能力。 在 HarmonyOS 6 (API 20) 中,系统提供了全新的 ArkWeb 内核。它基于

SpringBoot+Vue 雪具销售系统平台完整项目源码+SQL脚本+接口文档【Java Web毕设】

SpringBoot+Vue 雪具销售系统平台完整项目源码+SQL脚本+接口文档【Java Web毕设】

摘要 随着滑雪运动的普及和冬季旅游业的蓬勃发展,雪具市场需求持续增长,传统线下销售模式已难以满足消费者的多样化需求。线上雪具销售平台能够突破地域限制,提供更便捷的购物体验,同时降低运营成本。当前市场上缺乏专门针对雪具销售的综合性电商平台,现有系统往往功能单一,无法满足用户从选购到售后的一站式需求。此外,数据管理和用户体验的优化也成为提升平台竞争力的关键因素。因此,开发一个功能完善、操作便捷的雪具销售系统具有重要的现实意义和市场价值。关键词:雪具销售、电商平台、市场需求、用户体验、数据管理。 本系统基于SpringBoot和Vue技术栈开发,采用前后端分离架构,确保系统的高效性和可维护性。后端使用SpringBoot框架实现RESTful API,集成MyBatis进行数据库操作,并利用Redis缓存提升性能。前端采用Vue.js框架,结合Element UI组件库,实现响应式设计和用户友好的交互界面。系统核心功能包括用户注册登录、商品分类展示、购物车管理、订单支付、评价反馈以及后台管理模块。通过JWT实现用户认证与授权,确保数据安全性。系统还支持多条件商品搜索和推荐算法,提升用户购