HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

微信小程序、H5、APP百度地图组件的实现(定位、获取定位附近地址列表、移动地图获取地图中心附近地址列表)

百度地图

最新在开发公司用的百度地图实现,发现社区这方向资料参差不齐,很多都有残缺。下面看我的例子来一起做个百度地图的组件吧(仅限在H5、APP、微信小程序中使用)

在微信小程序中用了取巧的方式,使用uni自带map组件(在微信小程序中,map组件为腾讯地图),同时在百度后台不仅仅需要创建一个Web、iOS、Android的AK,同时还需要再创建一个服务器的AK,主要是用在微信小程序中,用来将地图获取的经纬度进行转换、逆地理编码、POI查询等功能。

在微信管理后台需要开启定位权限,具体看uni.getLocation的要求。

下方代码中会指出哪里使用百度地图Web AK,哪里使用百度地图服务器 AK。请详细查看下方代码注释。

1、创建一个定位公共类
起名:location.js
代码如下:

// 获取位置信息  
const getLocation = () => {  
    return new Promise((resolve, reject) => {  
        uni.showLoading({title: '获取位置中'});  
        // #ifdef APP-PLUS || H5  
        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();  
            }  
        })  
        // #endif  

        // #ifdef MP-WEIXIN  
        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: 'GCJ02',  
            geocode: true,  
            success: function(data) {  
                resolve(data)  
            },  
            fail: function(error) {  
                reject(error)  
            },  
            complete: function() {  
                uni.hideLoading();  
            }  
        })  
        // #endif  
    })  
};  

/**  
 * 检测是否开启定位  
*/  
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记得换成自己的百度地图web ak 和 百度地图服务器ak

<template>  
    <view class="baidu_map">  
        <view :style="!showSearch ? 'width: 100%; height: 100%; position: relative;' : 'width: 100%; height: 50%; position: relative;'">  
            <!-- #ifdef APP-PLUS || H5 -->  
            <view  
                id="myMap"  
                class="myMap"  
                :prop="dicValue"  
                :change:prop="bmap.changeValue"  
            >  
            </view>  
            <!-- #endif -->  
            <!-- #ifdef MP-WEIXIN -->  
            <map  
                class="myMap"  
                id="myMap"  
                scale="17"  
                enable-rotate="false"  
                show-location="true"  
                :latitude="maplatitude"  
                :longitude="mpalongitude"  
                @regionchange="regionchange"  
            ></map>  
            <!-- #endif -->  
            <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">  
                                {{ isEmptyString(item.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,  

                // #ifdef MP-WEIXIN  
                mapObjs: null,  
                needSearch: true,  
                city: "深圳市",  
                maplatitude: 22.685393,  
                maplongitude: 113.798274,  
                // #endif  
            };  
        },  
        mounted() {  
            let res = this.getSystemInfo();  
            this.sSearchStyle = 'margin-bottom: ' + res.safeAreaInsets.bottom + 'px;';  
            // #ifdef APP-PLUS || H5  
            this.dicValue = { type: 'needOtherAddress', needSerach: this.showSearch, guid: uni.$u.guid(), };  
            // #endif  

            // #ifdef MP-WEIXIN  
            if (this.mapObjs === undefined || this.mapObjs === null) {  
                this.mapObjs = uni.createMapContext('myMap', this); // 得到map实例对象  
            }  
            this.clickLocation();  
            // #endif  
        },  
        methods: {  
            /*  
            * 在改变 dicValue 时,或许你会有疑惑,为啥字典中都要带一个自动生成 32 位的guid  
            * 这是因为,如果没有带这个自动生成的guid,在renderjs中,当改变的 dicValue 是同一个值,监听函数是不会被调用的(H5会被调用,APP不会)  
            * 所以在字典中添加一个 自动生成的 guid,有助于renderjs中监听函数changeValue的生效。  
            */  
            // #ifdef APP-PLUS || H5  
            // 显示自身定位位置 回调   
            showMarking() {  
                if (this.showSearch) {  
                    this.dicValue = { type: 'addEventListener', guid: uni.$u.guid(), }  
                }  
                setTimeout(() => {  
                    this.clickLocation();  
                }, 200)  
            },  
            // #endif  

            // #ifdef MP-WEIXIN  
            regionchange(val) {  
                // 在安卓中是 end 事件  
                if (val.type === 'end' && this.needSearch) {  
                    this.getCenterLatLong();  
                    return;  
                }  

                // 在ios中是 regionchange  
                if (val.type ==='regionchange' && this.needSearch) {  
                    this.getCenterLatLong();  
                    return;  
                }  
            },  
            // 获取中心点位置  
            getCenterLatLong() {  
                if (this.mapObjs === undefined || this.mapObjs === null) {  
                    this.mapObjs = uni.createMapContext('myMap', this); // 得到map实例对象  
                }  
                const than = this;  
                this.mapObjs.getCenterLocation({  
                    success: res => {  
                        if (res.errMsg === 'getMapCenterLocation:ok') {  
                            than.circularRegionRetrieval(res.latitude, res.longitude);  
                        } else {  
                            uni.showToast({ icon: 'none', title: res.errMsg || '获取位置出错', duration: 3000 });  
                        }  
                    },  
                    fail: res => {  
                        uni.showToast({ icon: 'none', title: res.errMsg || '获取位置出错', duration: 3000 });  
                    },  
                    complete: res => {}  
                })  
            },  
            // 设置地图中心点  
            setMapCenter(latitude, longitude) {  
                if (this.mapObjs === undefined || this.mapObjs === null) {  
                    this.mapObjs = uni.createMapContext('myMap', this); // 得到map实例对象  
                }  
                this.needSearch = false;  
                const than = this;  
                this.mapObjs.moveToLocation({  
                    longitude: longitude,  
                    latitude: latitude,  
                    success: res => {},  
                    fail: res => {},  
                    complete: res => {   
                        setTimeout(() => {  
                            than.needSearch = true;  
                        }, 500)  
                    }  
                })  
            },  
            // 坐标转换  
            locationConversion(latitude, longitude, sendLocation, sendAddress, dicAddress) {  
                let sUrl = 'https://api.map.baidu.com/geoconv/v2/';  
                let params = {  
                    ak: '百度地图服务器ak',  
                    output: 'json',  
                    model: '1',  
                    coords: `${longitude},${latitude}`  
                }  
                uni.$u.http.get(sUrl, {params: params}).then(res => {  
                    uni.hideLoading();  
                    if (res.status === 0) {  
                        if (sendLocation) {  
                            this.sendLocation({longitude: res.result[0].x, latitude: res.result[0].y})  
                        }  

                        if (sendAddress) {  
                            let dicData = {  
                                title: dicAddress.title,  
                                address: dicAddress.address,  
                                point: {lat: res.result[0].y, lng: res.result[0].x},  
                                checked: true  
                            }  
                            this.$emit("clickSave", dicData);  
                        }  
                    } else {  
                        uni.showToast({ icon: 'none', title: res.message || '获取位置信息出错', duration: 3000 });  
                    }  
                }).catch(err => {  
                    uni.hideLoading();  
                    uni.showToast({ icon: 'none', title: err.errMsg || '获取位置信息出错', duration: 3000 });  
                })  
            },  
            // 获取当前自身坐标点 地理信息  
            getMyAddress(latitude, longitude, type) {  
                let sUrl = 'https://api.map.baidu.com/reverse_geocoding/v3/';  
                let params = {  
                    ak: '百度地图服务器ak',  
                    output: 'json',  
                    coordtype: type,  
                    location: `${latitude},${longitude}`  
                }  
                uni.$u.http.get(sUrl, {params: params}).then(res => {  
                    if (res.status === 0) {  
                        this.city = res.result.addressComponent.city;  
                        this.updateMyAddress({  
                            address: res.result.formatted_address,  
                            txPoint: res.result.location,  
                        })  
                    } else {  
                        uni.showToast({ icon: 'none', title: res.message || '获取位置信息出错', duration: 3000 });  
                    }  
                }).catch(err => {  
                    uni.showToast({ icon: 'none', title: err.errMsg || '获取位置信息出错', duration: 3000 });  
                })  
            },  
            // 圆形区域检索  
            circularRegionRetrieval(latitude, longitude) {  
                let sUrl = 'https://api.map.baidu.com/place/v2/search';  
                let params = {  
                    ak: '百度地图服务器ak',  
                    output: 'json',  
                    query: '公司企业$房地产$美食$酒店$购物$生活服务$休闲娱乐$医疗$交通设施$政府机构',  
                    coord_type: 2,  
                    ret_coordtype: 'gcj02ll',  
                    location: `${latitude},${longitude}`,  
                    radius: 1000,  
                }  
                uni.$u.http.get(sUrl, {params: params}).then(res => {  
                    if (res.status === 0) {  
                        let arrayAddressList = [];  
                        for (let item of res.results) {  
                            arrayAddressList.push({  
                                title: item.name,  
                                address: item.address,  
                                point: item.location,  
                                checked: false,  
                            });  
                        }  
                        this.updateAddressList(arrayAddressList);  
                    } else {  
                        uni.showToast({ icon: 'none', title: res.message || '获取位置信息出错', duration: 3000 });  
                    }  
                }).catch(err => {  
                    uni.showToast({ icon: 'none', title: err.errMsg || '获取位置信息出错', duration: 3000 });  
                })  
            },  
            // 地点输入检索  
            locationInputRetrieval() {  
                let sUrl = 'https://api.map.baidu.com/place/v2/suggestion';  
                let params = {  
                    ak: '百度地图服务器ak',  
                    output: 'json',  
                    ret_coordtype: 'gcj02ll',  
                    query: this.sQueryValue,  
                    region: this.city,  
                }  
                uni.$u.http.get(sUrl, {params: params}).then(res => {  
                    if (res.status === 0) {  
                        let arrayAddressList = [];  
                        let i = 0;  
                        for (let item of res.result) {  
                            arrayAddressList.push({  
                                title: item.name,  
                                address: item.address,  
                                point: item.location,  
                                checked: i === 0 ? true: false  
                            });  
                            i = i + 1;  
                        }  
                        this.updateAddressList(arrayAddressList);  
                    } else {  
                        uni.showToast({ icon: 'none', title: res.message || '获取位置信息出错', duration: 3000 });  
                    }  
                }).catch(err => {  
                    uni.showToast({ icon: 'none', title: err.errMsg || '获取位置信息出错', duration: 3000 });  
                })  
            },  
            // #endif  

            // 更新地址列表  
            updateAddressList(val) {  
                this.iLastIndex = 0;  
                this.arrayAddress = val;  
            },  
            // 向父页面发送当前坐标经纬度  
            sendLocation(val) {  
                this.$emit("sendLocation", val);  
            },  
            // 向父页面发送当前坐标地址信息  
            updateMyAddress(val) {  
                this.$emit("sendMyAddress", val);  
            },  
            // 获取自身当前经纬度  
            clickLocation() {  
                // #ifdef APP-PLUS  
                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(), }  
                }  
                // #endif  

                // #ifdef H5  
                this.dicValue = { type: 'getH5LocationPosition', guid: uni.$u.guid(), }  
                // #endif  

                // #ifdef MP-WEIXIN  
                location.getLocation().then((resp) => {  
                    if (this.mapObjs === undefined || this.mapObjs === null) {  
                        this.mapObjs = uni.createMapContext('myMap', this); // 得到map实例对象  
                    }  
                    this.maplatitude = resp.latitude;  
                    this.maplongitude = resp.longitude;  
                    this.needSearch = false;  
                    const than = this;  
                    this.mapObjs.moveToLocation({  
                        longitude: resp.longitude,  
                        latitude: resp.latitude,  
                        success: res => {  
                            than.getMyAddress(resp.latitude, resp.longitude, 'gcj02ll');  
                            than.circularRegionRetrieval(resp.latitude, resp.longitude);  
                        },  
                        fail: res => {  
                            uni.showToast({ icon: 'none', title: res.errMsg || '获取位置出错', duration: 3000 });  
                        },  
                        complete: res => {  
                            setTimeout(() => {  
                                than.needSearch = true;  
                            }, 500)  
                        }  
                    })  
                    this.locationConversion(resp.latitude, resp.longitude, true, false, null);  
                }).catch((error) => {  
                    uni.showToast({ icon: 'none', title: error.errMsg || '获取位置出错111', duration: 3000 });  
                });  
                // #endif  
            },  
            // 搜索按钮点击事件  
            searchQueryValue() {  
                uni.hideKeyboard();  
                // #ifdef APP-PLUS || H5  
                this.dicValue = { type: 'searchQueryValue', sSearchValue: this.sQueryValue, guid: uni.$u.guid(), };  
                // #endif  

                // #ifdef MP-WEIXIN  
                this.locationInputRetrieval();  
                // #endif  
            },  
            // 地址信息Cell 点击事件  
            clickAddressCell(item, index) {  
                if (this.arrayAddress[index].checked) {  
                    this.iLastIndex = index;  
                    return;  
                }  
                if (this.iLastIndex === index) {  
                    this.arrayAddress[this.iLastIndex].checked = !this.arrayAddress[this.iLastIndex].checked;  
                } else {  
                    this.arrayAddress[this.iLastIndex].checked = !this.arrayAddress[this.iLastIndex].checked;  
                    this.arrayAddress[index].checked = !this.arrayAddress[index].checked;  
                }  

                this.iLastIndex = index;  
                // #ifdef APP-PLUS || H5  
                this.dicValue = { type: 'moveMapCentre', point: {longitude: item.point.lng, latitude: item.point.lat}, guid: uni.$u.guid(), };  
                // #endif  
                // #ifdef MP-WEIXIN  
                this.setMapCenter(item.point.lat, item.point.lng);  
                // #endif  
            },  
            // 保存按钮 点击事件  
            clickFootButton() {  
                if (this.arrayAddress.length === 0) {  
                    uni.showToast({ icon: 'none', title: '请选择您要保存的地址', duration: 3000 });  
                    return;  
                }  
                // #ifdef APP-PLUS || H5  
                this.$emit("clickSave", this.arrayAddress[this.iLastIndex]);  
                // #endif  

                // #ifdef MP-WEIXIN  
                uni.showLoading({title:"加载中...", mask: true})  
                this.locationConversion(this.arrayAddress[this.iLastIndex].point.lat, this.arrayAddress[this.iLastIndex].point.lng, false, true, this.arrayAddress[this.iLastIndex]);  
                // #endif  
            },  
        }  
    }  
</script>  

<!-- #ifdef APP-PLUS || H5 -->   
<script module="bmap" lang="renderjs">  
    export default {  
        data() {  
            return {  
                map: null,  
                locationImg: '/static/location.png', // require("/static/location.png"),  
                innerValue: null,  
                needOtherAddress: 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 = '百度地图web 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("showMarking");  
            },  
            // 转换地图坐标点 经度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.addBaiduEventListener();  
                } else if (this.innerValue.type === 'searchQueryValue') {  
                    this.getSearchKeyAddreeList(this.innerValue.sSearchValue);  
                } else if (this.innerValue.type === 'moveMapCentre') {  
                    this.moveMapCentre(this.innerValue.point);  
                } else if (this.innerValue.type === 'needOtherAddress') {  
                    this.needOtherAddress = this.innerValue.needSerach;  
                } 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);  

                this.getLocationMyAddress(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);  
                    }  
                });  
            },  
            // 获取自身经纬度坐标 对应的地址信息  
            getLocationMyAddress(center) {  
                const than = this;  
                const geoc = new BMap.Geocoder();  
                geoc.getLocation(center, function(rs) {  
                    if (rs !== undefined && rs !== null) {  
                        var dicAddress = {  
                            address: rs.address,  
                            point: rs.point,  
                        };  
                        than.$ownerInstance.callMethod("updateMyAddress", dicAddress);  
                    }  
                });  
            },  
            // 根据搜索关键字获取地址列表信息  
            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>  
<!-- #endif -->  

<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;  
        overflow: hidden;  
    }  

    .location_cell .centent {  
        flex: 1;  
        overflow: hidden;  
    }  

    .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),不展示启用搜索选地址功能。
一种就是地图加地址检索和选地址功能。

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

继续阅读 »

最新在开发公司用的百度地图实现,发现社区这方向资料参差不齐,很多都有残缺。下面看我的例子来一起做个百度地图的组件吧(仅限在H5、APP、微信小程序中使用)

在微信小程序中用了取巧的方式,使用uni自带map组件(在微信小程序中,map组件为腾讯地图),同时在百度后台不仅仅需要创建一个Web、iOS、Android的AK,同时还需要再创建一个服务器的AK,主要是用在微信小程序中,用来将地图获取的经纬度进行转换、逆地理编码、POI查询等功能。

在微信管理后台需要开启定位权限,具体看uni.getLocation的要求。

下方代码中会指出哪里使用百度地图Web AK,哪里使用百度地图服务器 AK。请详细查看下方代码注释。

1、创建一个定位公共类
起名:location.js
代码如下:

// 获取位置信息  
const getLocation = () => {  
    return new Promise((resolve, reject) => {  
        uni.showLoading({title: '获取位置中'});  
        // #ifdef APP-PLUS || H5  
        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();  
            }  
        })  
        // #endif  

        // #ifdef MP-WEIXIN  
        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: 'GCJ02',  
            geocode: true,  
            success: function(data) {  
                resolve(data)  
            },  
            fail: function(error) {  
                reject(error)  
            },  
            complete: function() {  
                uni.hideLoading();  
            }  
        })  
        // #endif  
    })  
};  

/**  
 * 检测是否开启定位  
*/  
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记得换成自己的百度地图web ak 和 百度地图服务器ak

<template>  
    <view class="baidu_map">  
        <view :style="!showSearch ? 'width: 100%; height: 100%; position: relative;' : 'width: 100%; height: 50%; position: relative;'">  
            <!-- #ifdef APP-PLUS || H5 -->  
            <view  
                id="myMap"  
                class="myMap"  
                :prop="dicValue"  
                :change:prop="bmap.changeValue"  
            >  
            </view>  
            <!-- #endif -->  
            <!-- #ifdef MP-WEIXIN -->  
            <map  
                class="myMap"  
                id="myMap"  
                scale="17"  
                enable-rotate="false"  
                show-location="true"  
                :latitude="maplatitude"  
                :longitude="mpalongitude"  
                @regionchange="regionchange"  
            ></map>  
            <!-- #endif -->  
            <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">  
                                {{ isEmptyString(item.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,  

                // #ifdef MP-WEIXIN  
                mapObjs: null,  
                needSearch: true,  
                city: "深圳市",  
                maplatitude: 22.685393,  
                maplongitude: 113.798274,  
                // #endif  
            };  
        },  
        mounted() {  
            let res = this.getSystemInfo();  
            this.sSearchStyle = 'margin-bottom: ' + res.safeAreaInsets.bottom + 'px;';  
            // #ifdef APP-PLUS || H5  
            this.dicValue = { type: 'needOtherAddress', needSerach: this.showSearch, guid: uni.$u.guid(), };  
            // #endif  

            // #ifdef MP-WEIXIN  
            if (this.mapObjs === undefined || this.mapObjs === null) {  
                this.mapObjs = uni.createMapContext('myMap', this); // 得到map实例对象  
            }  
            this.clickLocation();  
            // #endif  
        },  
        methods: {  
            /*  
            * 在改变 dicValue 时,或许你会有疑惑,为啥字典中都要带一个自动生成 32 位的guid  
            * 这是因为,如果没有带这个自动生成的guid,在renderjs中,当改变的 dicValue 是同一个值,监听函数是不会被调用的(H5会被调用,APP不会)  
            * 所以在字典中添加一个 自动生成的 guid,有助于renderjs中监听函数changeValue的生效。  
            */  
            // #ifdef APP-PLUS || H5  
            // 显示自身定位位置 回调   
            showMarking() {  
                if (this.showSearch) {  
                    this.dicValue = { type: 'addEventListener', guid: uni.$u.guid(), }  
                }  
                setTimeout(() => {  
                    this.clickLocation();  
                }, 200)  
            },  
            // #endif  

            // #ifdef MP-WEIXIN  
            regionchange(val) {  
                // 在安卓中是 end 事件  
                if (val.type === 'end' && this.needSearch) {  
                    this.getCenterLatLong();  
                    return;  
                }  

                // 在ios中是 regionchange  
                if (val.type ==='regionchange' && this.needSearch) {  
                    this.getCenterLatLong();  
                    return;  
                }  
            },  
            // 获取中心点位置  
            getCenterLatLong() {  
                if (this.mapObjs === undefined || this.mapObjs === null) {  
                    this.mapObjs = uni.createMapContext('myMap', this); // 得到map实例对象  
                }  
                const than = this;  
                this.mapObjs.getCenterLocation({  
                    success: res => {  
                        if (res.errMsg === 'getMapCenterLocation:ok') {  
                            than.circularRegionRetrieval(res.latitude, res.longitude);  
                        } else {  
                            uni.showToast({ icon: 'none', title: res.errMsg || '获取位置出错', duration: 3000 });  
                        }  
                    },  
                    fail: res => {  
                        uni.showToast({ icon: 'none', title: res.errMsg || '获取位置出错', duration: 3000 });  
                    },  
                    complete: res => {}  
                })  
            },  
            // 设置地图中心点  
            setMapCenter(latitude, longitude) {  
                if (this.mapObjs === undefined || this.mapObjs === null) {  
                    this.mapObjs = uni.createMapContext('myMap', this); // 得到map实例对象  
                }  
                this.needSearch = false;  
                const than = this;  
                this.mapObjs.moveToLocation({  
                    longitude: longitude,  
                    latitude: latitude,  
                    success: res => {},  
                    fail: res => {},  
                    complete: res => {   
                        setTimeout(() => {  
                            than.needSearch = true;  
                        }, 500)  
                    }  
                })  
            },  
            // 坐标转换  
            locationConversion(latitude, longitude, sendLocation, sendAddress, dicAddress) {  
                let sUrl = 'https://api.map.baidu.com/geoconv/v2/';  
                let params = {  
                    ak: '百度地图服务器ak',  
                    output: 'json',  
                    model: '1',  
                    coords: `${longitude},${latitude}`  
                }  
                uni.$u.http.get(sUrl, {params: params}).then(res => {  
                    uni.hideLoading();  
                    if (res.status === 0) {  
                        if (sendLocation) {  
                            this.sendLocation({longitude: res.result[0].x, latitude: res.result[0].y})  
                        }  

                        if (sendAddress) {  
                            let dicData = {  
                                title: dicAddress.title,  
                                address: dicAddress.address,  
                                point: {lat: res.result[0].y, lng: res.result[0].x},  
                                checked: true  
                            }  
                            this.$emit("clickSave", dicData);  
                        }  
                    } else {  
                        uni.showToast({ icon: 'none', title: res.message || '获取位置信息出错', duration: 3000 });  
                    }  
                }).catch(err => {  
                    uni.hideLoading();  
                    uni.showToast({ icon: 'none', title: err.errMsg || '获取位置信息出错', duration: 3000 });  
                })  
            },  
            // 获取当前自身坐标点 地理信息  
            getMyAddress(latitude, longitude, type) {  
                let sUrl = 'https://api.map.baidu.com/reverse_geocoding/v3/';  
                let params = {  
                    ak: '百度地图服务器ak',  
                    output: 'json',  
                    coordtype: type,  
                    location: `${latitude},${longitude}`  
                }  
                uni.$u.http.get(sUrl, {params: params}).then(res => {  
                    if (res.status === 0) {  
                        this.city = res.result.addressComponent.city;  
                        this.updateMyAddress({  
                            address: res.result.formatted_address,  
                            txPoint: res.result.location,  
                        })  
                    } else {  
                        uni.showToast({ icon: 'none', title: res.message || '获取位置信息出错', duration: 3000 });  
                    }  
                }).catch(err => {  
                    uni.showToast({ icon: 'none', title: err.errMsg || '获取位置信息出错', duration: 3000 });  
                })  
            },  
            // 圆形区域检索  
            circularRegionRetrieval(latitude, longitude) {  
                let sUrl = 'https://api.map.baidu.com/place/v2/search';  
                let params = {  
                    ak: '百度地图服务器ak',  
                    output: 'json',  
                    query: '公司企业$房地产$美食$酒店$购物$生活服务$休闲娱乐$医疗$交通设施$政府机构',  
                    coord_type: 2,  
                    ret_coordtype: 'gcj02ll',  
                    location: `${latitude},${longitude}`,  
                    radius: 1000,  
                }  
                uni.$u.http.get(sUrl, {params: params}).then(res => {  
                    if (res.status === 0) {  
                        let arrayAddressList = [];  
                        for (let item of res.results) {  
                            arrayAddressList.push({  
                                title: item.name,  
                                address: item.address,  
                                point: item.location,  
                                checked: false,  
                            });  
                        }  
                        this.updateAddressList(arrayAddressList);  
                    } else {  
                        uni.showToast({ icon: 'none', title: res.message || '获取位置信息出错', duration: 3000 });  
                    }  
                }).catch(err => {  
                    uni.showToast({ icon: 'none', title: err.errMsg || '获取位置信息出错', duration: 3000 });  
                })  
            },  
            // 地点输入检索  
            locationInputRetrieval() {  
                let sUrl = 'https://api.map.baidu.com/place/v2/suggestion';  
                let params = {  
                    ak: '百度地图服务器ak',  
                    output: 'json',  
                    ret_coordtype: 'gcj02ll',  
                    query: this.sQueryValue,  
                    region: this.city,  
                }  
                uni.$u.http.get(sUrl, {params: params}).then(res => {  
                    if (res.status === 0) {  
                        let arrayAddressList = [];  
                        let i = 0;  
                        for (let item of res.result) {  
                            arrayAddressList.push({  
                                title: item.name,  
                                address: item.address,  
                                point: item.location,  
                                checked: i === 0 ? true: false  
                            });  
                            i = i + 1;  
                        }  
                        this.updateAddressList(arrayAddressList);  
                    } else {  
                        uni.showToast({ icon: 'none', title: res.message || '获取位置信息出错', duration: 3000 });  
                    }  
                }).catch(err => {  
                    uni.showToast({ icon: 'none', title: err.errMsg || '获取位置信息出错', duration: 3000 });  
                })  
            },  
            // #endif  

            // 更新地址列表  
            updateAddressList(val) {  
                this.iLastIndex = 0;  
                this.arrayAddress = val;  
            },  
            // 向父页面发送当前坐标经纬度  
            sendLocation(val) {  
                this.$emit("sendLocation", val);  
            },  
            // 向父页面发送当前坐标地址信息  
            updateMyAddress(val) {  
                this.$emit("sendMyAddress", val);  
            },  
            // 获取自身当前经纬度  
            clickLocation() {  
                // #ifdef APP-PLUS  
                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(), }  
                }  
                // #endif  

                // #ifdef H5  
                this.dicValue = { type: 'getH5LocationPosition', guid: uni.$u.guid(), }  
                // #endif  

                // #ifdef MP-WEIXIN  
                location.getLocation().then((resp) => {  
                    if (this.mapObjs === undefined || this.mapObjs === null) {  
                        this.mapObjs = uni.createMapContext('myMap', this); // 得到map实例对象  
                    }  
                    this.maplatitude = resp.latitude;  
                    this.maplongitude = resp.longitude;  
                    this.needSearch = false;  
                    const than = this;  
                    this.mapObjs.moveToLocation({  
                        longitude: resp.longitude,  
                        latitude: resp.latitude,  
                        success: res => {  
                            than.getMyAddress(resp.latitude, resp.longitude, 'gcj02ll');  
                            than.circularRegionRetrieval(resp.latitude, resp.longitude);  
                        },  
                        fail: res => {  
                            uni.showToast({ icon: 'none', title: res.errMsg || '获取位置出错', duration: 3000 });  
                        },  
                        complete: res => {  
                            setTimeout(() => {  
                                than.needSearch = true;  
                            }, 500)  
                        }  
                    })  
                    this.locationConversion(resp.latitude, resp.longitude, true, false, null);  
                }).catch((error) => {  
                    uni.showToast({ icon: 'none', title: error.errMsg || '获取位置出错111', duration: 3000 });  
                });  
                // #endif  
            },  
            // 搜索按钮点击事件  
            searchQueryValue() {  
                uni.hideKeyboard();  
                // #ifdef APP-PLUS || H5  
                this.dicValue = { type: 'searchQueryValue', sSearchValue: this.sQueryValue, guid: uni.$u.guid(), };  
                // #endif  

                // #ifdef MP-WEIXIN  
                this.locationInputRetrieval();  
                // #endif  
            },  
            // 地址信息Cell 点击事件  
            clickAddressCell(item, index) {  
                if (this.arrayAddress[index].checked) {  
                    this.iLastIndex = index;  
                    return;  
                }  
                if (this.iLastIndex === index) {  
                    this.arrayAddress[this.iLastIndex].checked = !this.arrayAddress[this.iLastIndex].checked;  
                } else {  
                    this.arrayAddress[this.iLastIndex].checked = !this.arrayAddress[this.iLastIndex].checked;  
                    this.arrayAddress[index].checked = !this.arrayAddress[index].checked;  
                }  

                this.iLastIndex = index;  
                // #ifdef APP-PLUS || H5  
                this.dicValue = { type: 'moveMapCentre', point: {longitude: item.point.lng, latitude: item.point.lat}, guid: uni.$u.guid(), };  
                // #endif  
                // #ifdef MP-WEIXIN  
                this.setMapCenter(item.point.lat, item.point.lng);  
                // #endif  
            },  
            // 保存按钮 点击事件  
            clickFootButton() {  
                if (this.arrayAddress.length === 0) {  
                    uni.showToast({ icon: 'none', title: '请选择您要保存的地址', duration: 3000 });  
                    return;  
                }  
                // #ifdef APP-PLUS || H5  
                this.$emit("clickSave", this.arrayAddress[this.iLastIndex]);  
                // #endif  

                // #ifdef MP-WEIXIN  
                uni.showLoading({title:"加载中...", mask: true})  
                this.locationConversion(this.arrayAddress[this.iLastIndex].point.lat, this.arrayAddress[this.iLastIndex].point.lng, false, true, this.arrayAddress[this.iLastIndex]);  
                // #endif  
            },  
        }  
    }  
</script>  

<!-- #ifdef APP-PLUS || H5 -->   
<script module="bmap" lang="renderjs">  
    export default {  
        data() {  
            return {  
                map: null,  
                locationImg: '/static/location.png', // require("/static/location.png"),  
                innerValue: null,  
                needOtherAddress: 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 = '百度地图web 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("showMarking");  
            },  
            // 转换地图坐标点 经度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.addBaiduEventListener();  
                } else if (this.innerValue.type === 'searchQueryValue') {  
                    this.getSearchKeyAddreeList(this.innerValue.sSearchValue);  
                } else if (this.innerValue.type === 'moveMapCentre') {  
                    this.moveMapCentre(this.innerValue.point);  
                } else if (this.innerValue.type === 'needOtherAddress') {  
                    this.needOtherAddress = this.innerValue.needSerach;  
                } 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);  

                this.getLocationMyAddress(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);  
                    }  
                });  
            },  
            // 获取自身经纬度坐标 对应的地址信息  
            getLocationMyAddress(center) {  
                const than = this;  
                const geoc = new BMap.Geocoder();  
                geoc.getLocation(center, function(rs) {  
                    if (rs !== undefined && rs !== null) {  
                        var dicAddress = {  
                            address: rs.address,  
                            point: rs.point,  
                        };  
                        than.$ownerInstance.callMethod("updateMyAddress", dicAddress);  
                    }  
                });  
            },  
            // 根据搜索关键字获取地址列表信息  
            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>  
<!-- #endif -->  

<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;  
        overflow: hidden;  
    }  

    .location_cell .centent {  
        flex: 1;  
        overflow: hidden;  
    }  

    .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),不展示启用搜索选地址功能。
一种就是地图加地址检索和选地址功能。

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

收起阅读 »

uni-app h5、app、微信小程序 全局水印组件

参考了:https://ask.dcloud.net.cn/article/35955 内容,对代码进行了修改,添加了优化

1、使用者需要在自己想要开始使用全局水印的地方开始写入,一般来说都是在首页index.vue执行的,在App.vue无法实现。本示例举例在 首页的 index.vue进行。

<!-- 水印组件.vue -->  

<template>  
    <!-- #ifdef APP-PLUS -->  
    <view class="watermark_back">  
        <canvas class="watermark" canvas-id="watermarkCanvas" id="watermarkCanvas"></canvas>  
    </view>  
    <!-- #endif -->  

    <!-- #ifdef H5 -->  
    <view>  

    </view>  
    <!-- #endif -->  

    <!-- #ifdef MP-WEIXIN -->  
    <view class="wx_watermark">  
        <view v-for="(item, index) in [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]" :key="index">  
            <view class="wx_watermark-row">  
                <span class="wx_watermark-col" v-for="(item1, index1) in ['a1','a2','a3','a4','a5','a6']" :key="index1">{{title}}</span>  
            </view>  
        </view>  
    </view>  
    <!-- #endif -->  
</template>  

<script>  
    export default {  
        name:"crm-watermark",  
        props: {  
            title: {  
                type: String,  
                default() {  
                    return '';  
                }  
            },  
        },  
        data() {  
            return {  

            };  
        },  
        mounted() {  
            uni.$on('initCrmWatermark', this.initCrmWatermark);  
            uni.$on('removeCrmWatermark', this.removeCrmWatermark);  
        },  
        destroyed() {  
            uni.$off('initCrmWatermark', this.initCrmWatermark)  
            uni.$off('removeCrmWatermark', this.removeCrmWatermark)  
        },  
        methods: {  
            initCrmWatermark(msg) {  
            // #ifdef APP-PLUS  
                let id = 'crm_watermark_20240423';  
                if (plus.nativeObj.View.getViewById(id) !== null) {  
                    plus.nativeObj.View.getViewById(id).close();  
                }  
                let context = uni.createCanvasContext('watermarkCanvas');  
                context.rotate(-45 * Math.PI / 180);  
                context.setFontSize(15);  
                context.setFillStyle('rgba(200, 200, 200, 0.30)');  
                context.setTextAlign('left');  
                context.setTextBaseline('middle');  
                context.fillText(msg, -83, 86);  

                context.draw(false, function() {  
                    uni.canvasToTempFilePath({  
                        canvasId: "watermarkCanvas",  
                        width: 126,  // 与下方 tarArr position width 保持一致  
                        height: 126, // 与下方 tarArr position height 保持一致  
                        success: function(res) {  
                            let path = res.tempFilePath;  
                            uni.getSystemInfo({  
                                success: function (res) {  
                                    // 水印排列行数  
                                    let row = Math.floor(res.windowHeight / 126);  
                                    let tarArr = [];  
                                    for (let i = 0; i < row + 1; i++) {  
                                        for (let j = 0; j < row + 1; j++){  
                                            tarArr.push({  
                                                tag: 'img',  
                                                src: path,  
                                                position: {  
                                                    top: (126 * i) + 'px',  
                                                    left: (126 * j) + 'px',  
                                                    width: '126px',  
                                                    height: '126px',  
                                                }  
                                            });  
                                        }  
                                    }  
                                    var watermarkView = new plus.nativeObj.View(  
                                        id,  
                                        {top:'0px', left:'0px', right: '0px', bottom: '0px'},  
                                        tarArr  
                                    );  
                                    // 拦截View控件的触屏事件,将事件穿透给下一层view  
                                    watermarkView.interceptTouchEvent(false);  
                                    watermarkView.show();  
                                    context.clearRect(0, 0, 126, 126);  
                                    context.draw();  
                                }  
                            });  
                        }  
                    });  
                });  
            // #endif  
            // #ifdef H5  
                let id = 'crm_watermark_20240423';  
                if (document.getElementById(id) !== null) {  
                    document.body.removeChild(document.getElementById(id));  
                }  

                let canvas = document.createElement('canvas');  
                canvas.width = 126;  
                canvas.height = 126;  

                let canvas2 = canvas.getContext('2d');  

                canvas2.rotate(-45 * Math.PI / 180);  
                canvas2.font = '15px Vedana';  
                canvas2.fillStyle = 'rgba(200, 200, 200, 0.3)';  
                canvas2.textAlign = 'left';  
                canvas2.textBaseline = 'middle';  
                canvas2.fillText(msg, -83, 86);  

                let div = document.createElement('div');  
                div.id = id;  
                div.style.pointerEvents = 'none';  
                div.style.top = '0px';  
                div.style.left = '0px';  
                div.style.bottom = '0px';  
                div.style.right = '0px';  
                div.style.position = 'fixed';  
                div.style.zIndex = '100000';  
                div.style.background = 'url(' + canvas.toDataURL('image/png') + ') left top repeat';  
                document.body.appendChild(div);  
                return id;  
            // #endif  
            },  
            // 删除水印(仅APP与H5有效)  
            removeCrmWatermark() {  
                // #ifdef APP-PLUS  
                    if (plus.nativeObj.View.getViewById('crm_watermark_20240423') !== null) {  
                        plus.nativeObj.View.getViewById('crm_watermark_20240423').close();  
                    }  
                // #endif  
                // #ifdef H5  
                    if (document.getElementById('crm_watermark_20240423') !== null) {  
                        document.body.removeChild(document.getElementById('crm_watermark_20240423'));  
                    }  
                // #endif  
            },  
        },  
    }  
</script>  

<style scoped>  
    /* #ifdef APP-PLUS */  
    .watermark_back {  
        position: relative;  
        width: 126px;  
        height: 126px;  
        z-index: -1;  
    }  

    .watermark {  
        position: absolute;  
        left: -126px;  
        top: -126px;  
    }  
    /* #endif */  

    /* #ifdef MP-WEIXIN */  
    .wx_watermark {  
      position: fixed;  
      width: 200vw;  
      height: 150vh;  
      top: -20vw;   
      left: -50vw;   
      color: rgba(200, 200, 200, 0.3);  
      font-size: 15px;  
      opacity: 1;  
      z-index: 1000000; // 放在顶层  
      pointer-events: none; // 点击穿透,不影响页面交互  
      transform: rotate(-45deg); // 水印倾斜角度  
    }  

    .wx_watermark-col {  
      display: inline-block;  
      padding: 50rpx 40rpx;  
    }  

    .wx_watermark-row {  
      white-space: nowrap;  
    }  

    .wx_watermark-row:nth-child(2n+1) {  
      transform: translateX(10%); // 奇偶数行水印错开  
    }  

    /* #endif */  

</style>

业务代码

<template>  
    <view>  
        <!-- 其他业务代码 -->  

        <!-- 添加水印 app与H5 只需要调用一次,即可配置全局水印 微信小程序需要每个页面都引入 -->  
        <!-- #ifdef MP-WEIXIN || APP-PLUS -->  
        <crm-watermark :title="sWatermark"></crm-watermark>  
        <!-- #endif -->  
    </view>  
</template>  

<script>  
    data() {  
        return {  
            // 微信小程序需要每个页面都引入,并且设置水印  
            // #ifdef MP-WEIXIN || APP-PLUS  
            sWatermark: "",  
            // #endif  
        }  
    },  
    methods: {  
        showWatermark() {  
            // app与H5 只需要调用一次,即可配置全局水印  
            // #ifdef APP-PLUS || H5  
            uni.$emit('initCrmWatermark', sTitle);  
            // #endif  

            // 微信小程序需要每个页面都引入,并且设置水印  
            // #ifdef MP-WEIXIN || APP-PLUS  
            this.sWatermark = sTitle;  
            // #endif  
        },  
    }

如果渲染出来 在APP水印页面发现多了个 格格不入的水印,请进行 APP-PLUS 中代码的微调,这是正常的。下面让我来解释一下 (H5不会出现这个问题)

在 APP-PLUS 模式下,先是使用 uni.createCanvasContext('watermarkCanvas'),找到页面中的 canvas。并且对 canvas进行设置(如字体、旋转角度、字体颜色、文字对齐方式、文字水平对齐方式、及填充文字,并且进行 X、Y轴设置)

接着 使用 context.draw,进行渲染,这个时候,其实页面渲染成功就会出现一个 水印了,但后续调用 uni.canvasToTempFilePath(把当前画布指定区域的内容导出生成指定大小的图片) 在其中做了 for循环,将画布内容又生产了N个,并且通过plus.nativeObj.View方式加入到了页面中。这个时候页面就会多出一个看起来格格不入的水印,这个水印就是前面提到的 context.draw 的时候页面已经出来一个了。

那么如何解决这个格格不入的水印问题呢,我的方式是覆盖后将其删除。将一个通过context.draw渲染出来的水印,通过大小调整为与 uni.canvasToTempFilePath for 循环出来的 水印大小一致,将其盖在上面,这样虽然第一个水印看起来颜色深了一个点,但其他并无异常。在uni.canvasToTempFilePath for 循环成功后加入 context.clearRect(0, 0, 126, 126); context.draw(); 将其原来绘制的水印进行删除。

具体看我代码注释:下面是关键代码
width: 126, // 与下方 tarArr position width 保持一致
height: 126, // 与下方 tarArr position height 保持一致
context.clearRect(0, 0, 126, 126);
context.draw();

微信小程序由于无法实现全局水印,只能在每个页面都加入该组件,并且使用条件编译
<!-- #ifdef MP-WEIXIN-->
<crm-watermark :title="sWatermark"></crm-watermark>
<!-- #endif -->

// #ifdef MP-WEIXIN
sWatermark: "",
// #endif

// #ifdef MP-WEIXIN
this.sWatermark = sTitle;
// #endif

继续阅读 »

参考了:https://ask.dcloud.net.cn/article/35955 内容,对代码进行了修改,添加了优化

1、使用者需要在自己想要开始使用全局水印的地方开始写入,一般来说都是在首页index.vue执行的,在App.vue无法实现。本示例举例在 首页的 index.vue进行。

<!-- 水印组件.vue -->  

<template>  
    <!-- #ifdef APP-PLUS -->  
    <view class="watermark_back">  
        <canvas class="watermark" canvas-id="watermarkCanvas" id="watermarkCanvas"></canvas>  
    </view>  
    <!-- #endif -->  

    <!-- #ifdef H5 -->  
    <view>  

    </view>  
    <!-- #endif -->  

    <!-- #ifdef MP-WEIXIN -->  
    <view class="wx_watermark">  
        <view v-for="(item, index) in [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]" :key="index">  
            <view class="wx_watermark-row">  
                <span class="wx_watermark-col" v-for="(item1, index1) in ['a1','a2','a3','a4','a5','a6']" :key="index1">{{title}}</span>  
            </view>  
        </view>  
    </view>  
    <!-- #endif -->  
</template>  

<script>  
    export default {  
        name:"crm-watermark",  
        props: {  
            title: {  
                type: String,  
                default() {  
                    return '';  
                }  
            },  
        },  
        data() {  
            return {  

            };  
        },  
        mounted() {  
            uni.$on('initCrmWatermark', this.initCrmWatermark);  
            uni.$on('removeCrmWatermark', this.removeCrmWatermark);  
        },  
        destroyed() {  
            uni.$off('initCrmWatermark', this.initCrmWatermark)  
            uni.$off('removeCrmWatermark', this.removeCrmWatermark)  
        },  
        methods: {  
            initCrmWatermark(msg) {  
            // #ifdef APP-PLUS  
                let id = 'crm_watermark_20240423';  
                if (plus.nativeObj.View.getViewById(id) !== null) {  
                    plus.nativeObj.View.getViewById(id).close();  
                }  
                let context = uni.createCanvasContext('watermarkCanvas');  
                context.rotate(-45 * Math.PI / 180);  
                context.setFontSize(15);  
                context.setFillStyle('rgba(200, 200, 200, 0.30)');  
                context.setTextAlign('left');  
                context.setTextBaseline('middle');  
                context.fillText(msg, -83, 86);  

                context.draw(false, function() {  
                    uni.canvasToTempFilePath({  
                        canvasId: "watermarkCanvas",  
                        width: 126,  // 与下方 tarArr position width 保持一致  
                        height: 126, // 与下方 tarArr position height 保持一致  
                        success: function(res) {  
                            let path = res.tempFilePath;  
                            uni.getSystemInfo({  
                                success: function (res) {  
                                    // 水印排列行数  
                                    let row = Math.floor(res.windowHeight / 126);  
                                    let tarArr = [];  
                                    for (let i = 0; i < row + 1; i++) {  
                                        for (let j = 0; j < row + 1; j++){  
                                            tarArr.push({  
                                                tag: 'img',  
                                                src: path,  
                                                position: {  
                                                    top: (126 * i) + 'px',  
                                                    left: (126 * j) + 'px',  
                                                    width: '126px',  
                                                    height: '126px',  
                                                }  
                                            });  
                                        }  
                                    }  
                                    var watermarkView = new plus.nativeObj.View(  
                                        id,  
                                        {top:'0px', left:'0px', right: '0px', bottom: '0px'},  
                                        tarArr  
                                    );  
                                    // 拦截View控件的触屏事件,将事件穿透给下一层view  
                                    watermarkView.interceptTouchEvent(false);  
                                    watermarkView.show();  
                                    context.clearRect(0, 0, 126, 126);  
                                    context.draw();  
                                }  
                            });  
                        }  
                    });  
                });  
            // #endif  
            // #ifdef H5  
                let id = 'crm_watermark_20240423';  
                if (document.getElementById(id) !== null) {  
                    document.body.removeChild(document.getElementById(id));  
                }  

                let canvas = document.createElement('canvas');  
                canvas.width = 126;  
                canvas.height = 126;  

                let canvas2 = canvas.getContext('2d');  

                canvas2.rotate(-45 * Math.PI / 180);  
                canvas2.font = '15px Vedana';  
                canvas2.fillStyle = 'rgba(200, 200, 200, 0.3)';  
                canvas2.textAlign = 'left';  
                canvas2.textBaseline = 'middle';  
                canvas2.fillText(msg, -83, 86);  

                let div = document.createElement('div');  
                div.id = id;  
                div.style.pointerEvents = 'none';  
                div.style.top = '0px';  
                div.style.left = '0px';  
                div.style.bottom = '0px';  
                div.style.right = '0px';  
                div.style.position = 'fixed';  
                div.style.zIndex = '100000';  
                div.style.background = 'url(' + canvas.toDataURL('image/png') + ') left top repeat';  
                document.body.appendChild(div);  
                return id;  
            // #endif  
            },  
            // 删除水印(仅APP与H5有效)  
            removeCrmWatermark() {  
                // #ifdef APP-PLUS  
                    if (plus.nativeObj.View.getViewById('crm_watermark_20240423') !== null) {  
                        plus.nativeObj.View.getViewById('crm_watermark_20240423').close();  
                    }  
                // #endif  
                // #ifdef H5  
                    if (document.getElementById('crm_watermark_20240423') !== null) {  
                        document.body.removeChild(document.getElementById('crm_watermark_20240423'));  
                    }  
                // #endif  
            },  
        },  
    }  
</script>  

<style scoped>  
    /* #ifdef APP-PLUS */  
    .watermark_back {  
        position: relative;  
        width: 126px;  
        height: 126px;  
        z-index: -1;  
    }  

    .watermark {  
        position: absolute;  
        left: -126px;  
        top: -126px;  
    }  
    /* #endif */  

    /* #ifdef MP-WEIXIN */  
    .wx_watermark {  
      position: fixed;  
      width: 200vw;  
      height: 150vh;  
      top: -20vw;   
      left: -50vw;   
      color: rgba(200, 200, 200, 0.3);  
      font-size: 15px;  
      opacity: 1;  
      z-index: 1000000; // 放在顶层  
      pointer-events: none; // 点击穿透,不影响页面交互  
      transform: rotate(-45deg); // 水印倾斜角度  
    }  

    .wx_watermark-col {  
      display: inline-block;  
      padding: 50rpx 40rpx;  
    }  

    .wx_watermark-row {  
      white-space: nowrap;  
    }  

    .wx_watermark-row:nth-child(2n+1) {  
      transform: translateX(10%); // 奇偶数行水印错开  
    }  

    /* #endif */  

</style>

业务代码

<template>  
    <view>  
        <!-- 其他业务代码 -->  

        <!-- 添加水印 app与H5 只需要调用一次,即可配置全局水印 微信小程序需要每个页面都引入 -->  
        <!-- #ifdef MP-WEIXIN || APP-PLUS -->  
        <crm-watermark :title="sWatermark"></crm-watermark>  
        <!-- #endif -->  
    </view>  
</template>  

<script>  
    data() {  
        return {  
            // 微信小程序需要每个页面都引入,并且设置水印  
            // #ifdef MP-WEIXIN || APP-PLUS  
            sWatermark: "",  
            // #endif  
        }  
    },  
    methods: {  
        showWatermark() {  
            // app与H5 只需要调用一次,即可配置全局水印  
            // #ifdef APP-PLUS || H5  
            uni.$emit('initCrmWatermark', sTitle);  
            // #endif  

            // 微信小程序需要每个页面都引入,并且设置水印  
            // #ifdef MP-WEIXIN || APP-PLUS  
            this.sWatermark = sTitle;  
            // #endif  
        },  
    }

如果渲染出来 在APP水印页面发现多了个 格格不入的水印,请进行 APP-PLUS 中代码的微调,这是正常的。下面让我来解释一下 (H5不会出现这个问题)

在 APP-PLUS 模式下,先是使用 uni.createCanvasContext('watermarkCanvas'),找到页面中的 canvas。并且对 canvas进行设置(如字体、旋转角度、字体颜色、文字对齐方式、文字水平对齐方式、及填充文字,并且进行 X、Y轴设置)

接着 使用 context.draw,进行渲染,这个时候,其实页面渲染成功就会出现一个 水印了,但后续调用 uni.canvasToTempFilePath(把当前画布指定区域的内容导出生成指定大小的图片) 在其中做了 for循环,将画布内容又生产了N个,并且通过plus.nativeObj.View方式加入到了页面中。这个时候页面就会多出一个看起来格格不入的水印,这个水印就是前面提到的 context.draw 的时候页面已经出来一个了。

那么如何解决这个格格不入的水印问题呢,我的方式是覆盖后将其删除。将一个通过context.draw渲染出来的水印,通过大小调整为与 uni.canvasToTempFilePath for 循环出来的 水印大小一致,将其盖在上面,这样虽然第一个水印看起来颜色深了一个点,但其他并无异常。在uni.canvasToTempFilePath for 循环成功后加入 context.clearRect(0, 0, 126, 126); context.draw(); 将其原来绘制的水印进行删除。

具体看我代码注释:下面是关键代码
width: 126, // 与下方 tarArr position width 保持一致
height: 126, // 与下方 tarArr position height 保持一致
context.clearRect(0, 0, 126, 126);
context.draw();

微信小程序由于无法实现全局水印,只能在每个页面都加入该组件,并且使用条件编译
<!-- #ifdef MP-WEIXIN-->
<crm-watermark :title="sWatermark"></crm-watermark>
<!-- #endif -->

// #ifdef MP-WEIXIN
sWatermark: "",
// #endif

// #ifdef MP-WEIXIN
this.sWatermark = sTitle;
// #endif

收起阅读 »

全栈开发在线接单,可接急单大单

外包 外包接单

本人全栈,因现在本职工作是产品了,担心久了不写代码,丢了吃饭的家伙,所以想接点写代码的单子。
主要是应用开发,小程序、微信网页应用,或是AI应用、区块链应用都做过,大佬们有需求可以聊聊,vx:laifeilim。
不急的单我可以周末自己抽空写,成本低;
急单,我得通过单位来接,这样我上班的时候也可以写。
大一点的单,单位这边应该也可以接下来的:团队百人+,目前CMMI3,年内CMMI5,注册资本3亿。

我自己从2021年就在插件市场发布插件,前端插件、云端一体页面模板、Admin插件、SDK都有:https://ext.dcloud.net.cn/publisher?id=743749
挑战过不到3天开发上线一个在线报名选课缴费应用,也在各种技术分享会安利unicloud:https://www.bilibili.com/video/BV1nW421N7XC/?spm_id_from=333.999.0.0

继续阅读 »

本人全栈,因现在本职工作是产品了,担心久了不写代码,丢了吃饭的家伙,所以想接点写代码的单子。
主要是应用开发,小程序、微信网页应用,或是AI应用、区块链应用都做过,大佬们有需求可以聊聊,vx:laifeilim。
不急的单我可以周末自己抽空写,成本低;
急单,我得通过单位来接,这样我上班的时候也可以写。
大一点的单,单位这边应该也可以接下来的:团队百人+,目前CMMI3,年内CMMI5,注册资本3亿。

我自己从2021年就在插件市场发布插件,前端插件、云端一体页面模板、Admin插件、SDK都有:https://ext.dcloud.net.cn/publisher?id=743749
挑战过不到3天开发上线一个在线报名选课缴费应用,也在各种技术分享会安利unicloud:https://www.bilibili.com/video/BV1nW421N7XC/?spm_id_from=333.999.0.0

收起阅读 »

免费帮忙开发 安卓 ios 原生插件,刚学完练练手,有需要的留言(太难的就算了)

uniapp原生插件

免费开发安卓 ios 原生插件,刚学完练练手,有需要的留言(太难的就算了)

免费开发安卓 ios 原生插件,刚学完练练手,有需要的留言(太难的就算了)

uni-app排坑指南-uni-push获取cid异常问题的处理

uni-push2配置完成后,根据官方文档使用uni.getPushClientId方法获取cid,
可能会报错getPushClientId:fail uniPush is not enabled,此时重新打自定义调试基座也没有作用。

app端可以使用

let pinf = plus.push.getClientInfo();  
let cid = pinf && pinf.clientid || ''; //客户端标识  
uni.setStorageSync('unipush_id', cid)  
plus.push.getClientInfoAsync((info) => {  
    cid = info.clientid;  
    uni.setStorageSync('unipush_id', cid)  
    console.log(cid)  
}, err => {});

使用plus方法可以稳定获取到cid,但是这个方法有局限性,只能在APP-PLUS中使用。

如果想在h5中使用,就需要在app.vue文件中引入一下uni-push模块

// #ifdef H5  
require('@dcloudio/vue-cli-plugin-uni/packages/uni-push/dist/uni-push.es.js')  
// #endif

使用这个方法获取到的cid后台会直接检测为小程序,不管是否勾选离线推送都只能在线推送。
根据自己编译环境具体看使用什么方法

继续阅读 »

uni-push2配置完成后,根据官方文档使用uni.getPushClientId方法获取cid,
可能会报错getPushClientId:fail uniPush is not enabled,此时重新打自定义调试基座也没有作用。

app端可以使用

let pinf = plus.push.getClientInfo();  
let cid = pinf && pinf.clientid || ''; //客户端标识  
uni.setStorageSync('unipush_id', cid)  
plus.push.getClientInfoAsync((info) => {  
    cid = info.clientid;  
    uni.setStorageSync('unipush_id', cid)  
    console.log(cid)  
}, err => {});

使用plus方法可以稳定获取到cid,但是这个方法有局限性,只能在APP-PLUS中使用。

如果想在h5中使用,就需要在app.vue文件中引入一下uni-push模块

// #ifdef H5  
require('@dcloudio/vue-cli-plugin-uni/packages/uni-push/dist/uni-push.es.js')  
// #endif

使用这个方法获取到的cid后台会直接检测为小程序,不管是否勾选离线推送都只能在线推送。
根据自己编译环境具体看使用什么方法

收起阅读 »

uni-app的app和web平台定位异常;uni-app已支持鸿蒙next;uni-app x 3端发布;uniCloud阿里云版Nodejs8终止支持;oppo商店误报广告

鸿蒙 uniCloud

uni-app的app和web平台定位异常

该问题已修复,请升级到uni-app 4.24。原因分析见下:

uni-app x 3端正式发布

随着4.14正式版发布,uni-app x的Web、Android、iOS均已上线。详见

欢迎阅读评测报告,了解uni-app x为何是性能最好的跨平台框架。详见

uni-app 已支持鸿蒙next

update@20240706:uni-app的鸿蒙版已灰度发布,若你想抢鲜体验,可下载最新的HBuilderX Alpha版本,手动打开鸿蒙入口,详见uni-app 开发鸿蒙应用

关联阅读,参考:星河璀璨,uni-app 亮相华为 HDC2024 开发者大会

2023底举办的插件大赛圆满结束

本次插件大赛在数千名候选插件中,评选出了82个优秀插件。这些插件为uni-app x的生态做出重要的贡献。
至此,大部分常见插件在uni-app x中均已提供。

获奖名单详见:https://ask.dcloud.net.cn/article/40812

关于 App Store 提交的隐私更新

Appstore要求2024年5月1日以后提交的包,都必须包含隐私清单。
Apple公告另见:关于 App Store 提交的隐私更新

使用 Transporter 工具上传到 AppStore 会提示以下警告:

ITMS-91053: Missing API declaration - Your app’s code in the “HBuilder” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryFileTimestamp. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code. For more details about this policy, including a list of required reason APIs and approved reasons for usage, visit: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api.

此警告只是提示信息,在2024年5月1日前仍可继续提交 AppStore。

2024年4月24号起,云打包支持隐私清单配置。

  • uni-app、5+App项目请更新到HBuilderX4.08及以上版本,重新提交云端打包
  • uni-app x项目需更新到HBuilderX4.13及以上版本重新提交云端打包

配置方法教程:详见

离线打包和uni小程序sdk也见上面的链接。

uniCloud阿里云版Nodejs8终止支持

uniCloud阿里云版服务空间云函数运行时目前支持Nodejs8、Nodejs12、Nodejs14、Nodejs16四个版本。接阿里云通知,其中Nodejs8即将终止支持,计划如下:

版本 终止支持阶段一:禁止新建 终止支持阶段二:禁止新建和更新
Node.js8 2024年06月01日 2024年09月01日

终止支持仅影响运行时为Nodejs8的云函数更新,不影响已有云函数继续运行,建议您及时升级到更高的版本。

所有已部署到服务空间的云函数(并非公共模块)均需开发者自行升级,升级方式:修改云函数package.jsoncloudfunction-config节点下的runtime,然后重新上传云函数。如果云函数的package.json没有cloudfunction-config相关配置,可参考文档进行添加,点此查看相关文档

uni一键登录SDK升级

接到联通运营商通知,旧版联通一键认证SDK将于2024年5月31日正式下线。
之前我们已经发布过升级公告,另见:uni一键登录SDK升级公告
注意:
云端打包:如果您已经使用HBuilderX3.99及以上版本重新打包并发布了一键登录的App,请忽略此公告。
离线打包:请更新Android、IOS离线SDK至最新版本

vivo商店提示无合理使用场景频繁采集oaid的问题

详见:https://ask.dcloud.net.cn/article/41143

oppo商店误报有广告的问题

推荐使用uni加固解决,详见:https://uniapp.dcloud.net.cn/tutorial/app-security.html
后续官方会升级代码,减少误检测误报。

继续阅读 »

uni-app的app和web平台定位异常

该问题已修复,请升级到uni-app 4.24。原因分析见下:

uni-app x 3端正式发布

随着4.14正式版发布,uni-app x的Web、Android、iOS均已上线。详见

欢迎阅读评测报告,了解uni-app x为何是性能最好的跨平台框架。详见

uni-app 已支持鸿蒙next

update@20240706:uni-app的鸿蒙版已灰度发布,若你想抢鲜体验,可下载最新的HBuilderX Alpha版本,手动打开鸿蒙入口,详见uni-app 开发鸿蒙应用

关联阅读,参考:星河璀璨,uni-app 亮相华为 HDC2024 开发者大会

2023底举办的插件大赛圆满结束

本次插件大赛在数千名候选插件中,评选出了82个优秀插件。这些插件为uni-app x的生态做出重要的贡献。
至此,大部分常见插件在uni-app x中均已提供。

获奖名单详见:https://ask.dcloud.net.cn/article/40812

关于 App Store 提交的隐私更新

Appstore要求2024年5月1日以后提交的包,都必须包含隐私清单。
Apple公告另见:关于 App Store 提交的隐私更新

使用 Transporter 工具上传到 AppStore 会提示以下警告:

ITMS-91053: Missing API declaration - Your app’s code in the “HBuilder” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryFileTimestamp. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code. For more details about this policy, including a list of required reason APIs and approved reasons for usage, visit: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api.

此警告只是提示信息,在2024年5月1日前仍可继续提交 AppStore。

2024年4月24号起,云打包支持隐私清单配置。

  • uni-app、5+App项目请更新到HBuilderX4.08及以上版本,重新提交云端打包
  • uni-app x项目需更新到HBuilderX4.13及以上版本重新提交云端打包

配置方法教程:详见

离线打包和uni小程序sdk也见上面的链接。

uniCloud阿里云版Nodejs8终止支持

uniCloud阿里云版服务空间云函数运行时目前支持Nodejs8、Nodejs12、Nodejs14、Nodejs16四个版本。接阿里云通知,其中Nodejs8即将终止支持,计划如下:

版本 终止支持阶段一:禁止新建 终止支持阶段二:禁止新建和更新
Node.js8 2024年06月01日 2024年09月01日

终止支持仅影响运行时为Nodejs8的云函数更新,不影响已有云函数继续运行,建议您及时升级到更高的版本。

所有已部署到服务空间的云函数(并非公共模块)均需开发者自行升级,升级方式:修改云函数package.jsoncloudfunction-config节点下的runtime,然后重新上传云函数。如果云函数的package.json没有cloudfunction-config相关配置,可参考文档进行添加,点此查看相关文档

uni一键登录SDK升级

接到联通运营商通知,旧版联通一键认证SDK将于2024年5月31日正式下线。
之前我们已经发布过升级公告,另见:uni一键登录SDK升级公告
注意:
云端打包:如果您已经使用HBuilderX3.99及以上版本重新打包并发布了一键登录的App,请忽略此公告。
离线打包:请更新Android、IOS离线SDK至最新版本

vivo商店提示无合理使用场景频繁采集oaid的问题

详见:https://ask.dcloud.net.cn/article/41143

oppo商店误报有广告的问题

推荐使用uni加固解决,详见:https://uniapp.dcloud.net.cn/tutorial/app-security.html
后续官方会升级代码,减少误检测误报。

收起阅读 »

【建议】建议压缩包添加一个脚本文件创建桌面快捷方式

@echo off  
echo Set oWS = WScript.CreateObject("WScript.Shell") > CreateShortcut.vbs  
echo sLinkFile = "%USERPROFILE%\Desktop\HBuilder X.lnk" >> CreateShortcut.vbs  
echo Set oLink = oWS.CreateShortcut(sLinkFile) >> CreateShortcut.vbs  
echo oLink.TargetPath = "%CD%\HBuilderX.exe" >> CreateShortcut.vbs  
echo oLink.WorkingDirectory = "%CD%\" >> CreateShortcut.vbs  
echo oLink.Save >> CreateShortcut.vbs  
cscript CreateShortcut.vbs  
del CreateShortcut.vbs
继续阅读 »
@echo off  
echo Set oWS = WScript.CreateObject("WScript.Shell") > CreateShortcut.vbs  
echo sLinkFile = "%USERPROFILE%\Desktop\HBuilder X.lnk" >> CreateShortcut.vbs  
echo Set oLink = oWS.CreateShortcut(sLinkFile) >> CreateShortcut.vbs  
echo oLink.TargetPath = "%CD%\HBuilderX.exe" >> CreateShortcut.vbs  
echo oLink.WorkingDirectory = "%CD%\" >> CreateShortcut.vbs  
echo oLink.Save >> CreateShortcut.vbs  
cscript CreateShortcut.vbs  
del CreateShortcut.vbs
收起阅读 »

previewImage图片预览如何实现懒加载

懒加载 previewimage

而不是等所有图片都加载完成了才进入预览界面

而不是等所有图片都加载完成了才进入预览界面

吐槽:云数据库数据导入

clientDB

今天导数据弄了半天,一开始直接上传json文件一直失败,查了一下发现要用jsonl格式,结果导入文件只支持json文件格式。。。无语

今天导数据弄了半天,一开始直接上传json文件一直失败,查了一下发现要用jsonl格式,结果导入文件只支持json文件格式。。。无语