郑莫莫
郑莫莫
  • 发布:2024-04-24 17:54
  • 更新:2024-04-24 17:54
  • 阅读:52

百度地图组件的实现(定位、获取定位附近地址列表、移动地图获取地图中心附近地址列表)

分类:uni-app

最新在开发公司用的百度地图实现,发现社区这方向资料参差不齐,很多都有残缺。下面看我的例子来一起做个百度地图的组件吧(仅限在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),不展示启用搜索选地址功能。
一种就是地图加地址检索和选地址功能。

代码里面都有注释,详细的去看,保证你会了解。

0 关注 分享

要回复文章请先登录注册