腾讯位置服务开发应用-使用教程,案例分享,知识总结
把你的前端拿捏得死死的,每天学习得爽爽的,达达前端程序员,微信搜索【程序员哆啦A梦】关注这个不一样的程序员。
感谢不负每一份热爱前端的程序员,不论前端技能有多奇葩,欢迎关注加我入群vx:xiaoda0423
前言
作为一名在职岗位为【前端开发工程师】的程序员,我开发的应用程序经常需要获取用户位置信息,需要再某些场合下使用展示地图以及地图商的某些地点,需要获取行政区划列表(省市区)以及地址详情信息,需要在地图上规划一条(动态)路线,轨迹回放,小车移动,需要创建信息窗口,用于地点的摘要性信息的展示。
公司内做的是共享项目, 场景是这样的,一种常见共享充电宝(功能差不多和流行的共享单车一样),在做小程序首页时,需要做到的是扫码充电,联系客服(问题反馈),获取地理位置,开篇即是一副地理位置,在你附近获取到区域内店铺信息,点击该店的logo标志可以获取该店的地理位置,营业时间,店名,距离,是否当前该店里是否有可借的充电宝等信息。
共享充电电动车?,首页也是一副地理位置地图,可以获取你附近最近的共享电动车,获取车的地址,状态等信息。显示该车的剩余电量,使用记录,租借订单,获取行程轨迹,某时间段内的里程,动态显示轨迹等。
涉及到的共享其实内容很多(如除了电动车,充电宝,还可租借设备等),但大都功能几乎相同,需要交押金,租借费用,信用免押金等。开发过app,H5,web网站,小程序项目都与地图相关的位置服务息息相关,让我说说与位置服务有关的故事。
下面主要还是讲解其中的关于地图功能等功能,使用的也是腾讯位置开发服务。会一步一步说明,做一些案例展示,代码说明,使用教程。(注意这里我回去看开发教程,尽量把每个功能都熟悉地说明一下使用方法)
一、腾讯位置服务是什么?
腾讯位置服务无疑是获取位置服务等信息内容,该产品亮点:
定位:为合作伙伴和广大开发者提供完善的位置解决方案,已为社交、出行、游戏、商业、O2O、物流等领域提供专业精准的定位服务 地图:腾讯位置服务在多平台为开发者提供了丰富的地图展现形式,帮助从属于不同领域的开发人员轻松完成构建地图并在其基础上打造专属内容的工作。同时配合海量数据、个性化定制、可视化等能力满足各个行业场景下对地图的需求 地点搜索:基于海量鲜活地点(POI)数据,提供周边搜索,城市范围搜索,关键词输入提示、分类筛选等多种搜索能力,面向社交、物流、出行等行业打造专属搜索策略,体验更胜一筹 路线规划:根据出发地、目的地以及路线策略设置,结合精准的实时交通路况提供驾车、步行、骑行、公交路线规划能力,助力开发者为用户提供贴心、人性化的出行体验 微信小程序解决方案:腾讯位置服务全面拥抱小程序生态,从服务API、基础地图组件、插件、行业方案等多个层面服务不同场景需求的小程序开发者,助力小程序插上地图的“翅膀”! 个性化地图:个性化样式:千行千面,助力开发者根据自身产品的使用场景、界面色调, 选取或者创建风格匹配的地图样式,体验更胜一筹;个性化图层:真实酷炫,助力开发者将精美绘图生成地图瓦片并置于地图之上,让旅游景点、大学高校等区域的展示效果与众不同
二、使用步骤
1.uniapp开发map说明
使用uniapp是因为它是一个使用vue.js开发所有前端应用的框架,开发者编写一套代码,可以发布到ios,android,web以及各种小程序,快应用等多个平台。
使用map地图组件开发,地图组件用于展示地图(使用的时腾讯地图),说一下它的属性有:
longitude(类型为Number,没有默认值,表示中心经度)latitude(类型为Number,没有默认值,表示中心纬度)scale(类型为Number,默认值为16,缩放级别取值范围为5-18)markers(类型为Array数组,类型为数组即表示地图上可以有多个,没有默认值,表示标记点)polyline(类型为Array数组,没有默认值,表示路线,数组上的所有点连成线)circles(类型Array数组,表示圆)controls(类型Array数组,表示控件)include-points(类型Array数组,表示缩放视野已包含所有给定的坐标点)enable-3D(类型为Boolean,默认值为false,表示是否显示3D搂块)show-compass(类型为Boolean,默认值为false,表示为是否显示指南针)enable-overlooking(类型为Boolean,默认值为false,表示为是否开启俯视)enable-satellite(类型为Boolean,默认值为false,表示为是否开启卫星图)enable-traffic(类型为Boolean,默认值为false,表示为是否开启实时路况)show-location(类型为Boolean,表示显示带有方向的当前定位点)polygons(类型Array,表示为多边形)
点击属性
@markertap-表示点击标记点时触发,e.detail={markerId}@labeltap-表示点击label时触发,e.detail = {markerId}@callouttap-表示点击标记点对应的气泡时触发,e.detail = {markerId}@controltap-表示点击控件时触发,e.detail = {controlId}@regionchange-表示视野发生变化时触发@tap-表示点击地图时触发;App-nuve、微信小程序2.9支持返回经纬度@updated-表示在地图渲染更新完成时触发
我们在写
map组件时,组件的宽/高推荐写直接量,比如说是750rpx,不要设置百分比值,在uni-app中只支持gcj02坐标。
介绍markers属性-类型为数组Array
由之前描述可知,markers属性类型为Array,表示标记点用于在地图上显示标记的位置。这个数组属性,它里面有它的对象配置属性,分别是:
id,表示 标记点id,类型为Number,必填项,marker点击事件回调会返回此id,建议为每个marker设置上Number类型id,保证更新marker时有更好的性能。latitude,纬度,类型Number,必填项,浮点数,范围-90 ~ 90longitude,经度,类型Number,必填项,浮点数,范围-180 ~ 180title,标注点名,类型String,不是必填,点击时显示,callout存在时将被忽略iconPath,显示的图标,类型String,必填项,项目目录下的图片路径rotate,旋转角度,类型Number,不是必填,顺时针旋转的角度,范围0 ~ 360,默认为 0alpha,标注的透明度,类型Number,不是必填,默认1,无透明,范围0 ~ 1width,标注图标宽度,类型Number,不是必填,默认为图片实际宽度height,标注图标高度,类型Number,不是必填,默认为图片实际高度callout,自定义标记点上方的气泡窗口,类型Object,不是必填 - 可识别换行符label,为标记点旁边增加标签,类型Object,不是必填 - 可识别换行符anchor,经纬度在标注图标的锚点,默认底边中点,不是必填,{x, y},x表示横向(0-1),y表示竖向(0-1)。{x: .5, y: 1} 表示底边中点
marker 上的气泡 callout(Object类型)
marker数组 上属性 callout 对象使用属性:
content,文本,Stringcolor,文本颜色,StringfontSize,文字大小,NumberborderRadius,callout边框圆角,NumberbgColor,背景色,Stringpadding,文本边缘留白,Numberdisplay,'BYCLICK':点击显示; 'ALWAYS':常显,StringtextAlign,文本对齐方式。有效值:left, right, center,String
marker 上的标签 label(Object类型)
content,文本,Stringcolor,文本颜色,StringfontSize,文字大小,Numberx,label的坐标,原点是 marker对应的经纬度,Numbery,label的坐标,原点是 marker对应的经纬度,NumberborderWidth,边框宽度,Number borderColor,边框颜色,String borderRadius,边框圆角,Number bgColor,背景色,String padding,文本边缘留白,Number textAlign,文本对齐方式。有效值: left, right, center,String
polyline
polyline表示指定一系列坐标点,从数组第一项连线至最后一项
points,经纬度数组,类型为Array,必填,如:[{latitude: 0, longitude: 0}]color,线的颜色,类型为String,不必填,如:#0000AAwidth,线的宽度,类型为Number,不必填dottedLine,是否虚线,类型为Boolean,不必填,默认值falsearrowLine,带箭头的线,类型为Boolean,不必填,默认值为falsearrowIconPath,更换箭头图标,类型为String,不必填,在arrowLine为true时,默认带箭头的线时生效borderColor,线的边框颜色,类型为String,不必填borderWidth,线的厚度,类型为Number,不必填
polygon
polygon指定一系列坐标点,根据points坐标数据生成闭合多边形
points,经纬度数组,array,必填,如:[{latitude: 0, longitude: 0}]strokeWidth,描边的宽度,Number,否strokeColor描边的颜色,String,否fillColor,填充颜色,String,否zIndex,设置多边形Z轴数值,Number,否
circles
circles在地图上显示圆
latitude,纬度,Number,必填,浮点数,范围-90 ~ 90longitude,经度,Number,必填,浮点数,范围-180 ~ 180color,描边的颜色,String,不必填,如:#0000AAfillColor,填充颜色,String,不必填,如:#0000AAradius,半径,Number,必填strokeWidth,描边的宽度,Number,不必填
controls
controls在地图上显示控件,控件不随着地图移动
id,控件id,Number,不必填,在控件点击事件回调会返回此idposition,控件在地图的位置,Object,必填,控件相对地图位置iconPath,显示的图标,String,必填,项目目录下的图片路径,支持相对路径写法,以'/'开头则表示相对项目根目录;也支持临时路径clickable,是否可点击,Boolean,不必填,默认不可点击
position
left,距离地图的左边界多远,Number,不必填,默认为0top,距离地图的上边界多远,Number,不必填,默认为0width,控件宽度,Number,不必填,默认为图片宽度height,控件高度,Number,不必填,默认为图片高度
注意在uniapp中地图组件的经纬度必填,如果不填,经纬度则默认值是北京的经纬度。
2.uniapp使用map组件
基本使用方法
使用uniapp开发中的map组件,基本使用方法:
代码如下(示例):
style="width: 100%; height: 100%;"enable-3D="false" show-compass="false" enable-overlooking="false"
:enable-satellite="false" :enable-traffic="false" show-location="false"
:latitude="latitude" :longitude="longitude" :markers="covers">
</map>
markers属性的使用,代码如下(示例):
markers: [{
id: 1, // Number
title: '1', // String-标注点名
rotate: 180, // Number - 顺时针旋转的角度,范围 0 ~ 360,默认为 0
alpha: 0.5, // 默认1,无透明,范围 0 ~ 1
latitude: 39.899,
longitude: 116.39742,
width: 30,
height: 30,
// callout: {
// display: "BYCLICK",
// padding: 10,
// borderRadius: 5,
// content: '',
// },
// anchor: {},
iconPath: '../../../static/location.png', // 显示的图标
}, {
id: 2,
title: '2', // String
latitude: 39.90,
longitude: 116.39,
callout: {
color: '#007AFF', // 文本颜色
bgColor: '#563BFF', // 背景色
display: "ALWAYS", // 'BYCLICK':点击显示; 'ALWAYS':常显
fontSize: 15,
textAlign: 'left', // 文本对齐方式。有效值: left, right, center
padding: 10, // 文本边缘留白
borderRadius: 5,
content: '腾讯地图',
},
label: {
content: 'Jeskson',
color: '#000000',
fontSize: 12,
borderWidth: 12,
borderColor: '#007AFF',
borderRadius: 5,
padding: 5,
textAlign: 'center',
bgColor: '#563BFF',
},
iconPath: '../../../static/location.png'
}]
预览效果如下:

controls:[{
// 在地图上显示控件,控件不随着地图移动
id: 1, // 控件id
iconPath:'../../static/icon.png', // 显示的图标
position:{
// 控件在地图的位置
left: 15,
top: 15,
width: 50,
height: 50
},
}],
地址搜索
uni-app只支持gcj02坐标
uni.getLocation(OBJECT)中的object参数
获取当前的地理位置、速度。在微信小程序中,当用户离开应用后,此接口无法调用,除非申请后台持续定位权限;当用户点击“显示在聊天顶部”时,此接口可继续调用。
OBJECT参数说明
type,String,不必填,默认为wgs84返回gps坐标,gcj02返回国测局坐标,可用于uni.openLocation的坐标,app平台高德SDK仅支持返回gcj02altitude,Boolean,不必填,传入true会返回高度信息,由于获取高度需要较高精确度,会减慢接口返回速度geocode,Boolean,不必填,默认false,是否解析地址信息success,Function,必填,接口调用成功的回调函数,返回内容详见返回参数说明fail,Function,不必填,接口调用失败的回调函数complete,Function,不必填,接口调用结束的回调函数(调用成功、失败都会执行)
对于success返回参数说明:
latitude,纬度,浮点数,范围为-90~90,负数表示南纬longitude,经度,浮点数,范围为-180~180,负数表示西经speed,速度,浮点数,单位m/saccuracy,位置的精确度altitude,高度,单位mverticalAccuracy,垂直精度,单位m(Android无法获取,返回0)horizontalAccuracy,水平精度,单位maddress,地址信息(仅App端支持,需配置geocode为true)
address 地址信息说明
country,String,国家 如“中国”,没有则返回undefinedprovince,String,省份名称 如“北京市”,没有则返回undefinedcity,String,城市名称,如“北京市”,没有则返回undefineddistrict,String,区,县名称 如“朝阳区”,没有则返回undefinedstreet,String,街道信息,如“酒仙桥路”,没有则返回undefinedstreetNum,String,获取街道门牌号信息,如“3号”,没有则返回undefinedpoiName,String POI信息,如“电子城.国际电子总部”,没有则返回undefinedpostalCode,String,邮政编码,如“100016”,没有则返回undefinedcityCode,String,城市代码,如“010”,没有则返回undefined
uni.chooseLocation(OBJECT)打开地图选择位置。
latitude,String,不必填,目标地纬度longitude,String,不必填,目标地经度keyword,String,不必填,搜索关键字,仅App平台支持success,Function,必填fail,Function,不必填complete,Function,不必填
success返回参数说明:
name,位置名称address,详细地址latitude,纬度,浮点数,范围为-90~90,负数表示南纬,使用gcj02国测局坐标系。longitude,经度,浮点数,范围为-180~180,负数表示西经,使用gcj02国测局坐标系。
代码如下(示例):
chooseLocation(e) { //打开地图选择位置
uni.chooseLocation({
success: res => {
console.log('位置名称:' + res.name);
console.log('详细地址:' + res.address);
console.log('纬度:' + res.latitude);
console.log('经度:' + res.longitude);
uni.getLocation({
type: 'gcj02',
altitude:true,
geocode:true,
success: function(res) {
console.log('当前位置的经度:' + res.longitude);
console.log('当前位置的纬度:' + res.latitude);
}
});
console.log('省:' + res.address.slice(0, res.address.indexOf('省') + 1));
console.log('市:' + res.address.slice(res.address.indexOf('省') + 1, res.address.indexOf('市') + 1));
console.log('区:' + res.address.slice(res.address.indexOf('市') + 1, res.address.indexOf('区') + 1));
this.query.address = res.address;
this.query.latitude = res.latitude;
this.query.longitude = res.longitude;
this.query.province = res.address.slice(0, res.address.indexOf('省') + 1)
this.query.city = res.address.slice(res.address.indexOf('省') + 1, res.address.indexOf('市') + 1)
this.query.district = res.address.slice(res.address.indexOf('市') + 1, res.address.indexOf('区') + 1)
}
});
},
预览效果:


获取附近的动态,点聚合
uni.getNetworkType(OBJECT)获取网络类型。
uni.createMapContext(mapId,this)创建并返回 map 上下文 mapContext 对象。在自定义组件下,第二个参数传入组件实例this,以操作组件内 组件。
mapContext-mapContext 通过 mapId 跟一个 组件绑定,通过它可以操作对应的 组件。
该对象得方法列表:
getCenterLocationOBJECT获取当前地图中心的经纬度,返回的是gcj02坐标系,可以用于uni.openLocationmoveToLocationOBJECT将地图中心移动到当前定位点,需要配合map组件的show-location使用translateMarkerOBJECT平移marker,带动画includePointsOBJECT缩放视野展示所有经纬度getRegionOBJECT获取当前地图的视野范围getScaleOBJECT获取当前地图的缩放级别$getAppMap获取原生地图对象plus.maps.Map
getCenterLocation 的 OBJECT 参数列表
success Function 不必填,接口调用成功的回调函数 ,res = { longitude: "经度", latitude: "纬度"}
moveToLocation 的 OBJECT 参数列表 - 可不必填
translateMarker 的 OBJECT 参数列表
markerIdNumber必填 指定markerdestinationObject必填 指定marker移动到的目标点autoRotateBoolean不必填 移动过程中是否自动旋转markerrotateNumber不必填marker的旋转角度durationNumber不必填 动画持续时长,默认值1000ms,平移与旋转分别计算animationEndFunction不必填 动画结束回调函数failFunction不必填 接口调用失败的回调函数
代码如下(示例):
"activeMap" ><view @tap="activeMarker={}">
<view class="page-body map-view" style="z-index: 1;position: relative;">
<view class="page-section page-section-gap map-view">
<map :markers="shops" id="map1" :show-location="true" :latitude="latitude" :longitude="longitude" @regionchange="regionChange"
@markertap="markerTap" @tap="activeMarker={}">
map>
<cover-image class="map-image" src="../static/address.png">cover-image>
view>
view>
view>
</view>
regionChange() { // 移动地图后重新获取门店
uni.createMapContext('map1', this).getCenterLocation({
success: res => {
console.log(res.latitude)
console.log(res.longitude)
this.shopTimeout = setTimeout(_ => {
this.shops = [{
address: "广东省汕头市xxx区xx大道1",
distance: 122,
end_time: "1",
id: 2,
latitude: "22.72078500009999",
longitude: "114.36090200009999",
shop: {
iconPath: '/static/logo.png',
id: 3,
latitude: "22.72078500009999",
longitude: "114.36090200009999",
height: 34,
width: 34,
shop: {return: 0}
},
return: 0,
height: 34,
width: 34,
start_time: "1",
store_name: "三星大酒店",
iconPath: '/static/shop.png',
}]
}, 500)
},
fail: res => {
uni.showModal({
content: '获取位置失败',
showCancel: false
})
}
})
},
预览效果图如下:

地图上标注附近的人
代码如下(示例):
list: [{
id: 1264640,
user_id: 335187,
place: "Jeskson市",
text: "dadaqianduan.cn",
latitude: "27.267520",
longitude: "111.727120",
status: "normal",
nickname: "dada",
avatar: "https://image.aishencn.com/2020/10/20/002207441_40845724-user.jpg",
distance: 13419,
}, {
id: 1272720,
user_id: 36950,
place: "dadaqianduan市",
text: "dadaqianduan.cn",
latitude: "27.257640",
longitude: "111.747910",
deletetime: null,
status: "normal",
nickname: "dadaqianduan",
avatar: "https://image.aishencn.com/2020/04/09/004135379_37869100-user.jpg",
distance: 27070,
}, {
id: 1316740,
user_id: 366172,
place: "dadaqianduan.cn",
text: "dadaqianduan.cn",
images: "https://image.aishencn.com/2020/11/04/215134979_98197351-bbs.jpg",
latitude: "27.257430",
longitude: "111.732960",
status: "normal",
nickname: "dada",
avatar: "https://image.aishencn.com/2020/11/04/182622730_98197351-user.venus/cache/ext/crop/1604518314542_jpg",
distance: 27190,
images_arr: ["https://image.aishencn.com/2020/11/04/215134979_98197351-bbs.jpg"]
}],
预览效果如图:


定位附近门店
代码如下(示例):
// 两点间距离
distance(la1, lo1, la2, lo2) {
var La1 = (la1 * Math.PI) / 180.0
var La2 = (la2 * Math.PI) / 180.0
var La3 = La1 - La2
var Lb3 = (lo1 * Math.PI) / 180.0 - (lo2 * Math.PI) / 180.0
var s =
2 *
Math.asin(
Math.sqrt(
Math.pow(Math.sin(La3 / 2), 2) +
Math.cos(La1) * Math.cos(La2) * Math.pow(Math.sin(Lb3 / 2), 2)
)
)
s = s * 6378.137 //地球半径
s = Math.round(s * 10000) / 10000
return s
},
// 计算最近的距离
nearDistance(array, centerLatitude, centerLongitude) {
let temp = []
for (let i = 0, l = array.length; i < l; i++) {
const element = array[i]
let d = this.distance(
element.latitude,
element.longitude,
centerLatitude,
centerLongitude
)
temp.push(d)
}
this.distanceL = Math.min.apply(null, temp)
}
效果如下图:
滑动轨迹
代码如下(示例):
:scale="scale" id="maps" :markers="markers" :latitude="center.latitude":longitude="center.longitude">
</map>
// 播放标记点
playMarkars() {
if (this.polyline.length == 0) {
uni.showModal({
content: '当前时间范围内没有轨迹,无法播放!',
})
this.isPlay = false // 无
this.playIndex = 0 // 第一个
return
}
this.playIndex = Math.min(this.points.length - 1, this.playIndex)
this.markers = [this.formatMarker(this.points[this.playIndex++], 'ALWAYS')]
this.timer = setInterval(_ => {
var i = this.playIndex++
this.nextAdaress(i);
if (i >= this.points.length) {
clearInterval(this.timer)
this.isPlay = false
this.playIndex = 0
this.initMarkers()
return
}
this.markers = [this.formatMarker(this.points[i], 'ALWAYS')]
}, 1000)
},
formatMarker(point, display = "BYCLICK") {
let content = [
"时间:" + parseTime(point.create_time),
"运动状态:" + (point.sport == 1 ? '运动' : '静止'),
"地址:" + point.address || ''
]
return {
id: point.id,
iconPath: '/static/dada.png',
width: 35,
height: 35,
latitude: point.latitude,
longitude: point.longitude,
callout: {
display: display,
padding: 10,
borderRadius: 5,
content: content.join("\n")
}
}
},
nextAdaress(index) {
const len = 10;
if (this.isGetAddress) {
return
}
for (let i = 0; i < len; i++) {
if (!this.points[i + index]) {
break
}
if (this.points[i + index].address === undefined) {
this.isGetAddress = true
this.getAddress(i + index, len * 2, _ => {
this.isGetAddress = false
});
break
}
}
},
图片效果如下:

vue接入腾讯地图接口
腾讯(推荐)
https://apis.map.qq.com/ws/location/v1/ip={$ip}&key={$key}
需要申请key,速度快,有基本信息
首页点击可以进行注册,申请一个获取key:https://lbs.qq.com?lbs_invite=VJJIFLV
key管理,创建新密钥,填写相应信息即可
1.创建地图预览效果图如下:
2.地图加载完成效果图:
使用前需要在index.html里引入才可以使用地图。
