基于高德JSAPI的H5选址组件
一、需求
- 可以切换城市
- 可以检索城市下的地址
- 拖拽地图选点
- 显示选点附件的poi
- 双指缩放时以地图的中心点为中心
二、效果如图
三、准备
成为开发者并创建 key,为了正常调用 API ,请先注册成为高德开放平台开发者,并申请 web 平台(JS API)的 key 和安全密钥,点击 具体操作。
2021年12月02日后创建的 key 必须配备安全密钥一起使用,具体用法参见JS API 安全密钥使用
四、开发
初始化
<template>
<view id="container"></view>
<view class="result-list footer">
<van-list :finished="finished">
<van-cell v-for="(item, index) in resultList" :key="index" center :title="item.name" :label="item.address"
@click="handleClickAddress(item)">
<template #extra>
<span class="map-distance">{{ handleDistance(item.distance) }}</span>
</template>
</van-cell>
</van-list>
</view>
</template>
initMap() {
// 初始化地图
const _this = this
let map = null;
positionPicker = null;
AMapLoader.load({
"key": "您的key", // 申请好的Web端开发者Key,首次调用 load 时必填
"version": "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
"plugins": [
'AMap.Geolocation', // 定位插件
'AMap.AutoComplete', // 输入提示与POI搜索
'AMap.ToolBar', // 缩放工具条
'AMap.Scale', // 比例尺插件
],
"Loca": { // 是否加载 Loca, 缺省不加载
"version": '2.0.0' // Loca 版本,缺省 1.3.2
},
}).then(async (AMap) => {
await this.asyncLoadAmapUI()
map = new AMap.Map('container', {
zoom: 18,
scrollWheel: true,
// viewMode: '3D', // 3D 模式视图,
// mapStyle: 'amap://styles/macaron', // 地图样式设置
})
window.map = map
AMapUI.loadUI([
'misc/MobiCityPicker',
], (
MobiCityPicker,
) => {
this.handleCityPicker(MobiCityPicker, map)
});
const geolocation = new AMap.Geolocation({
// 是否使用高精度定位,默认:true
enableHighAccuracy: true,
// 设置定位超时时间,默认:无穷大
timeout: 6000,
position: 'RB',
showButton: true,
panToLocation: true,
zoomToAccuracy: true
})
map.addControl(geolocation);
const scale = new AMap.Scale();
map.addControl(scale);
// 有初始值, 逆向地理编码查询地理位置详细信息
// 没有初始值,进行GPS定位查询
})
},
handleCityPicker() {
// 处理点击左上角切换城市
this.cityPicker = new MobiCityPicker({
//设置主题(同名的className会被添加到外层容器上)
theme: "light"
});
//监听城市选中事件
this.cityPicker.on("citySelected", (cityInfo) => {
this.cityPicker.hideImmediately(); //立即隐藏
console.log(cityInfo); //选中的城市信息
const { adcode, name, lat, lng } = cityInfo
this.curCityName = name
this.curCityCode = adcode
// map.setCenter([lng, lat])
});
},
handlePositionPicker(map, PositionPicker, SimpleInfoWindow) {
positionPicker = new PositionPicker({
mode: 'dragMap',// 设定为拖拽地图模式,可选'dragMap'、'dragMarker',默认为'dragMap'
// dragMap模式,通过拖动地图来选择需要的点。marker一直位于地图的中心点
// dragMarker模式,通过拖动marker来选择需要的点
map: map, // 依赖地图对象
iconStyle: { //自定义外观
url: '//webapi.amap.com/ui/1.0/assets/position-picker2.png',
ancher: [24, 40],
size: [40, 40]
}
});
if (this.point.lng) {
// 初始化positionPicker
positionPicker.start([this.point.lng, this.point.lat]);
}
// 选址结束后的回调函数
positionPicker.on('success', res => {
// 拖动地图后,选点成功回调
})
positionPicker.on('fail', res => {
// 拖动地图后,选点失败回调
})
},
handleSearchValueChange(val) {
// 搜索事件处理
// 主要逻辑
const autoComplete = new AMap.Autocomplete({
city: this.curCityName,
citylimit: true
});
autoComplete.search(val, (status, result) => {
// 搜索成功时,result即是对应的匹配数据
let resAddress = [];
if (status == 'complete') {
// 检索的结果
console.log(result.tips);
}
})
}
五、问题
https
地图要使用点击定位到当前位置,必须是https协议。
1. https+IP
chrome https+IP时,需要翻墙才能定位到当前位置,firefox和edge不需要翻墙也可以直接定位到当前。
2. https+域名
无需其他任何操作,生产一定要使用https+域名
安全密钥
2021年12月02日以后申请的key需要配合您的安全密钥一起使用。也就是说2021年12月02日以后申请到key由一对组成,一个时key,一个是安全密钥。
注意:
1. 您这个设置必须是在JS API 脚本加载之前进行设置,否则设置无效。
2. 将key和安全密钥都写在前端代码中是很不安全的,生产需要将安全密钥配置到nginx。
具体如何配置请参考[JS API 安全密钥使用](https://lbs.amap.com/api/javascript-api-v2/guide/abc/jscode)。
3. 如果开发测试是http协议,需要转发到https对应的端口,或者直接使用https的端口。
4. 如果https的证书是自签的,在浏览器中打开。需要手动信任这个证书一次,否则会报net::ERR_CERT_COMMON_NAME_INVALID的错误
5. 如果https的证书是自签的,在APP 的webview中打开,需要APP配置一下白名单。
中心点缩放
双指缩放的时候,本来想要的目标点位于地图中心,可是一缩放,目标点就跑了,不位于地图中心了。
那能想到的方法就是,监听地图缩放事件,通过setCenter,把中心位置重新设置成目标点。但是bug一大把,缩放的时候,地图会莫名其妙的滑动很长的距离。
之后还是通过查看API发现了方法,由此骂自己千百遍,叫你不看API!!!只知道面向百度(现在变成了面向chatgpt,但是问不对要点也没有太大用处)开发。
map = new AMap.Map('container', {
zoom: 18,
scrollWheel: true,
touchZoomCenter: 1, // 可缺省,当touchZoomCenter=1的时候,手机端双指缩放的以地图中心为中心,否则默认以双指中间点为中心
})
touchZoomCenter
这个属性,针对移动端,为1的时候,双指缩放会以地图的中心为中心进行缩放。这样就保证了缩放的时候位于中心的目标点不会跑。
还有个奇怪的问题:在我集成的app的webveiw中,当地图放大到比例尺小于等于1:25级以上(具体多少zoom值没有看,18以上吧)时,地图的瓦片就加载不出来了。微信中打开地图页面的链接时,放到到最大1:10时展示也是正常的。
最后,再重申一下,一定要看API,不要拿来就用,就百度。
参考
1. JS API 安全密钥使用
2. 高德地图 JS API 2.0教程
3.Geolocation.getCurrentPosition