最新在开发公司用的百度地图实现,发现社区这方向资料参差不齐,很多都有残缺。下面看我的例子来一起做个百度地图的组件吧(仅限在H5和APP中使用)
1、创建一个定位公共类
起名:location.js
代码如下:
// 获取位置信息
const getLocation = () => {
return new Promise((resolve, reject) => {
uni.showLoading({title: '获取位置中'});
uni.getLocation({
/*
* 目前国内主要有以下三种坐标系:
* WGS84:为一种大地坐标系,也是目前广泛使用的GPS全球卫星定位系统使用的坐标系。
* GCJ02:又称火星坐标系,是由中国国家测绘局制订的地理信息系统的坐标系统。由WGS84坐标系经加密后的坐标系。
* BD09:为百度坐标系,在GCJ02坐标系基础上再次加密。其中bd09ll表示百度经纬度坐标,bd09mc表示百度墨卡托米制坐标。
*
* 如果使用的定位为手机自带定位,那么type 使用 GCJ02。
* 如果是使用百度地图定位,那么type 使用 BD09。(需要在项目中的manifest.json文件配置 百度地图定位的AK)
* 如果是使用高德地图定位,那么type 使用 GCJ02。(需要在项目中的manifest.json文件配置 高德地图定位的AK)
* 如果是使用谷歌地图定位,那么type 使用 WGS84。(需要在项目中的manifest.json文件配置 谷歌地图定位的AK)
*/
type: 'BD09',
geocode: true,
success: function(data) {
resolve(data)
},
fail: function(error) {
reject(error)
},
complete: function() {
uni.hideLoading();
}
})
})
};
/**
* 检测是否开启定位
*/
const checkOpenGPSServiceByAndroidIOS = () => {
let system = uni.getSystemInfoSync(); // 获取系统信息
if (system.platform === 'android') { // 判断平台
var context = plus.android.importClass("android.content.Context");
var locationManager = plus.android.importClass("android.location.LocationManager");
var main = plus.android.runtimeMainActivity();
var mainSvr = main.getSystemService(context.LOCATION_SERVICE);
if (!mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER)) {
uni.showModal({
title: '温馨提示',
content: '您未开启定位服务,请打开定位服务功能,以便获取您的位置!',
showCancel: true,
success() {
var Intent = plus.android.importClass('android.content.Intent');
var Settings = plus.android.importClass('android.provider.Settings');
var intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
main.startActivity(intent); // 打开系统设置GPS服务页面
}
});
return {s: 'android', b: false};
} else {
return {s: 'android', b: true};
}
} else if (system.platform === 'ios') {
var cllocationManger = plus.ios.import("CLLocationManager");
var enable = cllocationManger.locationServicesEnabled();
var status = cllocationManger.authorizationStatus();
plus.ios.deleteObject(cllocationManger);
if (enable && status != 2) {
// 手机系统的定位已经打开
return {s: 'ios', b: true};
} else {
// 手机系统的定位没有打开
uni.showModal({
title: '提示',
content: '请前往设置-隐私-定位服务打开定位服务功能',
showCancel: true,
success() {
var UIApplication = plus.ios.import("UIApplication");
var application2 = UIApplication.sharedApplication();
var NSURL2 = plus.ios.import("NSURL");
var setting2 = NSURL2.URLWithString("app-settings:"); // UIApplicationOpenSettingsURLString
application2.openURL(setting2);
plus.ios.deleteObject(setting2);
plus.ios.deleteObject(NSURL2);
plus.ios.deleteObject(application2);
}
});
return {s: 'ios', b: false};
}
} else {
return {s: 'h5', b: false};
}
}
const getLocationChange = () => {
return new Promise((resolve, reject) => {
uni.startLocationUpdate({
success: function() {
uni.onLocationChange(function (res) {
// 纬度:res.latitude 经度:res.longitude
resolve(res)
});
uni.onLocationChangeError(function (error) {
reject(error);
});
},
fail: function(error) {
reject(error);
},
complete: function() {
// 调用开启小程序接收位置消息 API 完成
}
});
})
}
const stopLocationUpdate = () => {
uni.stopLocationUpdate(function () {
// 关闭监听实时位置变化,前后台都停止消息接收。
})
}
export default {
getLocation: getLocation,
getLocationChange: getLocationChange,
stopLocationUpdate: stopLocationUpdate,
checkOpenGPSServiceByAndroidIOS: checkOpenGPSServiceByAndroidIOS,
}
2、创建一个名字叫 xn-map.vue 的组件 (不知道uniapp 如何创建组件,自行百度一下)
创建完后,记得进行引入:
import xnMap from '@/components/xn-map/xn-map.vue';
Vue.component('xn-map', xnMap);
以下是 xn-map.vue 代码:
代码中的ak记得换成自己的百度地图ak
<template>
<view class="baidu_map">
<view :style="!showSearch ? 'width: 100%; height: 100%; position: relative;' : 'width: 100%; height: 50%; position: relative;'">
<view
id="myMap"
class="myMap"
:prop="dicValue"
:change:prop="bmap.changeValue"
>
</view>
<view class="location" @click="clickLocation">
<u--image :src="sLocationIcon" width="28px" height="28px"></u--image>
</view>
<view v-if="showSearch" class="marking"></view>
</view>
<view v-if="showSearch" class="address_list">
<view class="search">
<u-search :clearabled="true" v-model="sQueryValue" @search="searchQueryValue" @custom="searchQueryValue"></u-search>
</view>
<view class="list">
<view v-for="(item, index) in arrayAddress" :key="index" @click="clickAddressCell(item, index)">
<view class="location_cell">
<view class="centent">
<view class="title">
{{ item.title }}
</view>
<view class="sub_title">
{{ item.address }}
</view>
</view>
<view class="right" v-if="item.checked">
<u-icon name="checkbox-mark" color="#2979ff" size="18"></u-icon>
</view>
</view>
<u-line></u-line>
</view>
</view>
<view class="footer" :style="sSearchStyle">
<u-button type="primary" text="保存" @click="clickFootButton"></u-button>
</view>
</view>
</view>
</template>
<script>
import location from '@/tool/location.js';
export default {
name:"crm-map",
props: {
showSearch: {
type: Boolean,
default() {
return false;
}
},
},
data() {
return {
sSearchStyle: "",
dicValue: null,
sLocationIcon: "../../static/map_location.png",
sQueryValue: "",
arrayAddress: [],
iLastIndex: 0,
};
},
mounted() {
let res = uni.getSystemInfoSync();
this.sSearchStyle = 'margin-bottom: ' + res.safeAreaInsets.bottom + 'px;';
},
methods: {
/*
* 在改变 dicValue 时,或许你会有疑惑,为啥字典中都要带一个自动生成 32 位的guid
* 这是因为,如果没有带这个自动生成的guid,在renderjs中,当改变的 dicValue 是同一个值,监听函数是不会被调用的(H5会被调用,APP不会)
* 所以在字典中添加一个 自动生成的 guid,有助于renderjs中监听函数changeValue的生效。
*/
isShowMarking() {
if (this.showSearch) {
this.dicValue = { type: 'addEventListener', guid: uni.$u.guid(), }
}
setTimeout(() => {
this.clickLocation();
}, 200)
},
// 更新地址列表
updateAddressList(val) {
this.iLastIndex = 0;
this.arrayAddress = val;
},
sendLocation(val) {
this.$emit("sendLocation", val);
},
// 获取自身当前经纬度
clickLocation() {
let dicInfo = location.checkOpenGPSServiceByAndroidIOS();
if (dicInfo.s !== 'h5') {
if (dicInfo.b) {
location.getLocation().then((resp) => {
this.dicValue = {
type: 'addMyLocationIcon',
longitude: resp.longitude,
latitude: resp.latitude,
guid: uni.$u.guid(),
}
this.sendLocation({longitude: resp.longitude, latitude: resp.latitude});
}).catch((error) => {
uni.showToast({ icon: 'none', title: error.errMsg || '获取位置出错', duration: 3000 });
});
}
} else {
this.dicValue = { type: 'getH5LocationPosition', guid: uni.$u.guid(), }
}
},
// 搜索按钮点击事件
searchQueryValue() {
uni.hideKeyboard();
this.dicValue = { type: 'searchQueryValue', sSearchValue: this.sQueryValue, guid: uni.$u.guid(), };
},
// 地址信息Cell 点击事件
clickAddressCell(item, index) {
this.arrayAddress[this.iLastIndex].checked = !this.arrayAddress[this.iLastIndex].checked;
this.arrayAddress[index].checked = !this.arrayAddress[index].checked;
this.iLastIndex = index;
this.dicValue = { type: 'moveMapCentre', point: {longitude: item.point.lng, latitude: item.point.lat}, guid: uni.$u.guid(), };
},
// 保存按钮 点击事件
clickFootButton() {
this.$emit("clickSave", this.arrayAddress[this.iLastIndex]);
},
}
}
</script>
<script module="bmap" lang="renderjs">
export default {
data() {
return {
map: null,
locationImg: require("../../static/location.png"),
innerValue: null,
needSearch: false,
};
},
mounted(){
// 初始化百度地图
this.initBaiDuMap();
},
methods: {
// 动态创建Script标签
createScript(url) {
return new Promise((resolve,reject) => {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.onload = () => { resolve() };
script.onerror = () => { reject() };
document.head.appendChild(script);
})
},
initBaiDuMap() {
const ak = '换成你自己的ak';
if( typeof window.BMap === 'function') {
this.initMap();
} else {
window.init = () => this.initMap();
this.createScript(`https://api.map.baidu.com/api?v=3.0ak=${ak}&callback=init`)
}
},
async initMap() {
// myMap 要渲染地图的view的id
this.map = new BMap.Map("myMap");
this.map.centerAndZoom(this.getPoint(113.804346, 22.691386), 17); // 设置中心点
var scaleCtrl = new BMap.ScaleControl(); // 添加比例尺控件
this.map.addControl(scaleCtrl);
this.$ownerInstance.callMethod("isShowMarking");
},
// 转换地图坐标点 经度longitude 纬度latitude
getPoint(longitude, latitude) {
return new BMap.Point(longitude, latitude);
},
// 接收Value改变时的数据,用来操作百度地图的API
changeValue(val) {
if (val === null || val === undefined) {
return
}
this.innerValue = val;
if (this.innerValue.type === 'addMyLocationIcon') {
this.addMyLocationIcon(this.innerValue);
} else if (this.innerValue.type === 'getH5LocationPosition') {
this.getH5LocationPosition();
} else if (this.innerValue.type === 'addEventListener') {
this.needSearch = true;
this.addBaiduEventListener();
} else if (this.innerValue.type === 'searchQueryValue') {
this.getSearchKeyAddreeList(this.innerValue.sSearchValue);
} else if (this.innerValue.type === 'moveMapCentre') {
this.moveMapCentre(this.innerValue.point);
} else {
}
this.innerValue = null;
},
// 添加自身定位坐标点 并且将地图中心点移动至定位坐标点 经度longitude 纬度latitude
addMyLocationIcon(val) {
// 清除地图上所有覆盖物
this.map.clearOverlays();
let point = this.getPoint(val.longitude, val.latitude);
// 构造函数: 以给定的图像地址和大小创建图标对象实例
var startIcon = new BMap.Icon(
this.locationImg,
new BMap.Size(30, 30)
);
// 设置图标的大小
startIcon.setImageSize(new BMap.Size(30, 30));
var overlay = new BMap.Marker(point, {icon: startIcon});
// 将覆盖物添加到地图中,一个覆盖物实例只能向地图中添加一次
this.map.addOverlay(overlay);
// 将地图中心 移动至定位点
this.map.panTo(point);
if (this.needSearch) {
this.getLocationAddress(point)
}
},
// 将地图中心点移动某个经纬度上 经度longitude 纬度latitude
moveMapCentre(val) {
let point = this.getPoint(val.longitude, val.latitude);
// 将地图中心 移动至定位点
this.map.panTo(point);
},
// 调用浏览器H5定位接口进行定位 (优先调用浏览器H5定位接口,如果失败会调用IP定位, IP定位:根据用户IP 返回城市级别的定位结果)
getH5LocationPosition() {
/* 关于状态码
* BMAP_STATUS_SUCCESS 检索成功。对应数值“0”
* BMAP_STATUS_CITY_LIST 城市列表。对应数值“1”
* BMAP_STATUS_UNKNOWN_LOCATION 位置结果未知。对应数值“2”
* BMAP_STATUS_UNKNOWN_ROUTE 导航结果未知。对应数值“3”
* BMAP_STATUS_INVALID_KEY 非法密钥。对应数值“4”
* BMAP_STATUS_INVALID_REQUEST 非法请求。对应数值“5”
* BMAP_STATUS_PERMISSION_DENIED 没有权限。对应数值“6”。(自 1.1 新增)
* BMAP_STATUS_SERVICE_UNAVAILABLE 服务不可用。对应数值“7”。(自 1.1 新增)
* BMAP_STATUS_TIMEOUT 超时。对应数值“8”。(自 1.1 新增)
*/
const than = this;
var geolocation = new BMap.Geolocation();
geolocation.getCurrentPosition((r) => {
if(geolocation.getStatus() === BMAP_STATUS_SUCCESS){
than.addMyLocationIcon({longitude: r.point.lng, latitude: r.point.lat});
than.$ownerInstance.callMethod("sendLocation", {longitude: r.point.lng, latitude: r.point.lat});
} else {
switch(geolocation.getStatus()) {
case 2:
alert('位置结果未知,获取位置失败。');
break;
case 3:
alert('导航结果未知,获取位置失败。');
break;
case 4:
alert('非法密钥获取位置失败。');
break;
case 5:
alert('对不起,非法请求位置,获取位置失败。');
break;
case 6:
alert('对不起,当前没有权限,获取位置失败。');
break;
case 7:
alert('对不起,服务不可用,获取位置失败。');
break;
case 8:
alert('对不起,请求超时,获取位置失败。');
break;
default:
alert('定位发生未知错误,请重试!');
break;
}
}
},{ enableHighAccuracy: true }); // 指示浏览器获取高精度的位置,默认false
},
// 添加百度地图拖拽完成事件 回调
addBaiduEventListener() {
const than = this;
this.map.addEventListener('dragend', function (e) {
const center = than.map.getCenter();
than.getLocationAddress(center);
});
},
// 获取经纬度坐标 对应的地址信息
getLocationAddress(center) {
const than = this;
const geoc = new BMap.Geocoder();
geoc.getLocation(center, function(rs) {
if (rs !== undefined && rs !== null) {
var arrayAddressList = [];
arrayAddressList.push({
title: rs.business,
address: rs.address,
point: rs.point,
checked: true,
});
for (let item of rs.surroundingPois) {
arrayAddressList.push({
title: item.title,
address: item.address,
point: item.point,
checked: false
});
}
than.$ownerInstance.callMethod("updateAddressList", arrayAddressList);
}
});
},
// 根据搜索关键字获取地址列表信息
getSearchKeyAddreeList(sSearchKey) {
const than = this;
const locationController = new BMap.LocalSearch(this.map, {
onSearchComplete: function(results) {
var arrayAddressList = [];
var data = [];
for (var i = 0; i < results.getCurrentNumPois(); i ++) {
data.push(results.getPoi(i));
}
var i = 0;
for (let item of data) {
arrayAddressList.push({
title: item.title,
address: item.address,
point: item.point,
checked: i === 0 ? true : false,
});
i = i + 1;
}
than.$ownerInstance.callMethod("updateAddressList", arrayAddressList);
if (arrayAddressList.length > 0) {
than.moveMapCentre({longitude: arrayAddressList[0].point.lng, latitude: arrayAddressList[0].point.lat})
}
},
});
locationController.setPageCapacity(10);
locationController.search(sSearchKey);
}
},
}
</script>
<style scoped>
.baidu_map {
width: 100%;
height: 100%;
}
.baidu_map .myMap {
width: 100%;
height: 100%;
}
.baidu_map .location {
position: absolute;
width: 40px;
height: 40px;
top: 10px;
right: 10px;
display: flex;
justify-content: center;
align-items: center;
}
.baidu_map .marking {
background-image: url('../../static/location_dw.png');
position: absolute;
width: 40px;
height: 40px;
left: 50%;
right: 50%;
transform: translate(-50%, -40px);
top: 50%;
/* display: flex;
justify-content: center;
align-items: center; */
}
.baidu_map .address_list {
width: 100%;
height: 50%;
overflow: hidden;
}
.baidu_map .address_list .search {
padding: 10px;
background-color: #ffffff;
}
.baidu_map .address_list .list {
width: 100%;
height: calc(100% - 104px);
overflow: scroll;
}
.baidu_map .address_list .footer {
height: 40px;
background-color: #f7f7fa;
padding: 5px;
}
.location_cell {
display: flex;
padding: 5px 10px 0px 10px;
}
.location_cell .centent {
flex: 1;
}
.location_cell .right {
width: 40px;
display: flex;
justify-content: center;
align-items: center;
}
.location_cell .centent .title {
height: 24px;
font-size: 16px;
font-weight: 500;
line-height: 24px;
margin-bottom: 3px;
overflow:hidden;
white-space:nowrap;
text-overflow:ellipsis;
}
.location_cell .centent .sub_title {
font-size: 14px;
color: #222222;
text-overflow: ellipsis;
overflow: hidden;
margin-bottom: 5px;
}
</style>
3、在业务页面使用它
代码如下
<template>
<view>
<u-navbar
title="坐标获取"
:border="true"
:placeholder="true"
:pagingEnabled="false"
:autoBack="true">
</u-navbar>
<!-- showSearch 控制显示模式,true为带搜索地址功能,false为纯地图 -->
<view :style="sStyle">
<xn-map
showSearch
@clickSave="clickSave"
@sendLocation="getLocation"
/>
</view>
</view>
</template>
<script >
export default {
data() {
return {
sStyle: "",
}
},
onLoad: function(option) {},
onReady() {
let res = uni.getSystemInfoSync();
let iHeight = res.windowHeight - (44.5 + res.statusBarHeight + res.safeAreaInsets.bottom);
this.sStyle = 'width: 100vw; height: ' + iHeight + 'px;';
},
methods: {
clickSave(val) {
console.log('选定了地址');
console.log(val);
},
getLocation(val) {
console.log('获取到定位信息');
console.log(val);
}
},
}
</script>
<style scoped>
</style>
上面的百度地图有2种模式,一种就是纯地图展示(含定位功能,定位功能需要自己去将项目中的manifest.json,进行配置百度地图的ak),不展示启用搜索选地址功能。
一种就是地图加地址检索和选地址功能。
代码里面都有注释,详细的去看,保证你会了解。