由于百度地图文档确实有点欠缺,在这里记录一下
- vue3 + 百度地图(js api 3.0)
- 实现效果如下
- 实现方式
- 注意事项
vue3 + 百度地图(js api 3.0)
- 需求: 地图弹框组件,可以搜索地图点,输入联想,回车定位等
- 项目:vue3 + ts + 百度地图js api
实现效果如下
实现方式
- 首先引入百度地图
const loadingBMPGL = (ak: string) => {
return new Promise(function (resolve, reject) {
window.init = () => resolve(BMapGL);
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = `https://api.map.baidu.com/api?v=3.0&type=webgl&ak=${ak}&callback=init`;
script.onerror = reject;
document.head.appendChild(script);
});
};
- 初始化地图实例并监听事件
const initMap = (val: any) => {
loadingBMPGL(val).then((BMapGL: any) => {
map = new window.BMapGL.Map('mapContainer');
// 初始化地图,设置中心点坐标和地图级别
var ac = new window.BMapGL.Autocomplete({
//建立一个自动完成的对象
input: 'searchInput',
location: map,
});
ac.setInputValue(searchData.value);
ac.addEventListener('onhighlight', function (e) {
var str = '';
var value = e.fromitem.value;
if (e.fromitem.index > -1) {
str =
value.province +
' ' +
value.city +
' ' +
value.district +
' ' +
value.street +
' ' +
value.business;
}
var highlight = 'Suggestion: ' + str;
document.getElementById('searchInput').placeholder = str;
});
ac.addEventListener('onconfirm', function (e) {
var confirmStr =
e.item.value.province +
'/' +
e.item.value.city +
'/' +
e.item.value.district +
'/' +
e.item.value.street +
'/' +
e.item.value.business;
const address = {
name: e.item.value.address,
address: confirmStr,
point: e.item.value.location,
};
selectResult(address);
console.log('确认选择: ', e, confirmStr);
});
// 以天安门为例
map.centerAndZoom(new window.BMapGL.Point(116.404, 39.915), 11);
// 启用地图拖拽事件
map.enableDragging();
// 启用地图缩放
map.enableScrollWheelZoom(true);
// 监听地图点击事件
map.addEventListener('click', function (e) {
// 获取点击位置的坐标
const point = e.latlng;
// 清除之前的标记
if (currentMarker) {
map.removeOverlay(currentMarker);
}
map.clearOverlays();
// 创建标记并添加到地图上
currentMarker = new window.BMapGL.Marker(point);
map.addOverlay(currentMarker);
map.centerAndZoom(point, 35);
// geolocation.enableSDKLocation();
// 创建地理编码服务实例
const geocoder = new window.BMapGL.Geocoder();
// 使用地理编码服务获取地址
geocoder.getLocation(point, function (result) {
if (result) {
const address = result.content.address + result.content.poi_desc;
searchData.value = address;
lat.value = point.lat;
lng.value = point.lng;
// 在点击位置显示信息窗口
const infoWindow = new window.BMapGL.Label(
'您点击的位置:' + address + '<br>' + '经纬度:' + point.lng + ', ' + point.lat
);
infoWindow.setStyle({
color: 'black',
fontSize: '14px',
backgroundColor: 'white',
border: '1px solid #ccc',
padding: '2px',
});
currentMarker.setLabel(infoWindow);
} else {
console.log('未找到该位置的地址');
}
});
});
// 0: 成功。表示搜索请求成功,并且结果可以通过 result 对象进行获取和处理。
// 1: 没有找到匹配的结果。表示搜索关键字没有匹配到任何地点。
// 2: 请求被拒绝。可能是由于权限问题或请求格式不正确。
// 3: API 密钥无效。表示使用的 API 密钥不正确或已过期。
// 4: 发生了未知错误。表示出现了无法预料的问题。
localSearch.value = new window.BMapGL.LocalSearch(map, {
// renderOptions: { map: map },
onSearchComplete: function (result) {
if (localSearch.value.getStatus() === 0) {
if (result._pois.length != 0) {
console.log('Search completed:', localSearch.value, result);
searchResults.value = result._pois.map(poi => {
return {
id: poi.uid,
name: poi.title,
address: poi.address,
point: poi.point,
};
});
}
} else {
console.log('Search failed:', result, localSearch.value.getStatus());
}
},
});
// 初始化搜索一次
// searchLocation(searchData.value);
});
};
其实这里有两种方式实现;
- 其一是使用BMapGL.Autocomplete 创建一个自定义对象,需要一个input框来绑定输入框,还有一个地图的区域
<div class="map-container" id="mapContainer" ref="mapContainer"></div>
<div class="search-box">
<el-input
id="searchInput"
ref="searchdom"
style="width: 250px"
v-model="searchData"
placeholder="搜索地点"
>
<!-- @input="searchLocation" -->
<template #suffix>
<img class="search-icon" src="@/assets/img/water-works/search.png" alt="" />
</template>
</el-input>
<!-- 显示搜索结果列表 -->
<!-- <div class="search-list" v-if="searchResults.length">
<ul>
<li v-for="result in searchResults" :key="result.id" @click="selectResult(result)">
<span style="padding: 12px 7px"> {{ result.name }}</span>
</li>
</ul>
</div> -->
</div>
这里需要注意的是:需要单独设置一下搜索结果列表的层级,不然会遮挡导致看不见,要去掉style标签的 scoped,这样的话重写的css样式才能生效。
.tangram-suggestion {
z-index: 99999;
}
onhighlight 和 onconfirm 分别设置监听输入联想和选择搜索结果的事件,可以在回调中设置需要的操作
- 第二种就是利用BMapGL.LocalSearch 方法,也就是localSearch.value
在输入框上设置 `@input="searchLocation"`
const searchLocation = (keyword: any) => {
localSearch.value.search(keyword);
};
调用BMapGL.LocalSearch 的回调方法 给searchResults.value 赋值然后将上面的搜索列表注释放开就可以在选中事件中做相应操作,如:
const selectResult = (result: any) => {
console.log(result);
// 清空搜索结果列表
searchResults.value = [];
// 清空搜索框
searchData.value = result.address;
// 获取搜索结果
const poi = result.point;
// 在地图上标记位置
markerPosition.value = poi;
lat.value = poi.lat;
lng.value = poi.lng;
// const icon = new window.BMapGL.Icon('@/assets/img/water-works/marker.svg', new window.BMapGL.Size(20, 20));
// icon.setImageSize(new window.BMapGL.Size(32,32));
// const marker = new window.BMapGL.Marker(poi,{ icon: icon });
const marker = new window.BMapGL.Marker(poi);
// 创建标签
const label = new window.BMapGL.Label(
'名称:' + result.name + '<br>' + '经纬度:' + poi.lng + ', ' + poi.lat,
{
offset: new window.BMapGL.Size(20, -10), // 调整标签位置
}
);
label.setStyle({
color: 'black',
fontSize: '14px',
backgroundColor: 'white',
border: '1px solid #ccc',
padding: '2px',
});
// 将标签添加到标记
marker.setLabel(label);
map.addOverlay(marker);
map.centerAndZoom(poi, 35);
};
注意事项
- vue3 和ts项目中没有直接的BMapGL 对象,所以挂在了Window下面
- 注意修改结果列表的层级z-index