官方帮助文档:https://lbs.qq.com/miniProgram/jsSdk/jsSdkGuide/jsSdkOverview
进行一些简单的配置
Uniapp提供的位置相关的服务:
https://uniapp.dcloud.net.cn/api/location/location.html
UniApp提供的地图组件
https://uniapp.dcloud.net.cn/component/map.html
文档针对微信小程序进行设置,其他端使用这些组件还需要参考uniapp官方文档是否支持对应的业务
组件属性速查:官方文档地址。
个人理解:地图组件是用户和地图交互的核心组件,所有的显示和选点都在map组件上实现
常用属性整理:
属性名 | 类型 | 默认值 | 说明 | 平台差异说明 |
---|---|---|---|---|
longitude | Number | 中心经度(重要 | ||
latitude | Number | 中心纬度(重要 | ||
scale | Number | 16 | 缩放级别,取值范围为3-20 | 高德地图缩放比例与微信小程序不同 |
markers | Array | 标记点(重要 | ||
polyline | Array | 路线(重要 | 飞书小程序不支持 | |
enable-zoom | Boolean | true | 是否支持缩放 | App-nvue 2.1.5+、微信小程序2.3.0 |
enable-traffic | Boolean | false | 是否开启实时路况 | App-nvue 2.1.5+、微信小程序2.7.0 |
微信小程序、H5、百度小程序、支付宝小程序、京东小程序 | ||||
polygons | Array.
|
多边形(可以画圈 | App-nvue 2.1.5+、App-vue 3.4.3+、H5 3.4.3+、微信小程序、百度小程序、支付宝小程序 | |
@markertap | EventHandle | 点击标记点时触发,e.detail = {markerId} | App-nvue 2.3.3+、H5、微信小程序、支付宝小程序 | |
@tap | EventHandle | 点击地图时触发; App-nvue | 微信小程序2.9支持返回经纬度 |
案例用法如下:
markers
和polyline
对应的数值类型需要注意有格式要求。如下
标记点用于在地图上显示标记的位置 ,已数组的形式组成地图上的标记点
属性 | 说明 | 类型 | 必填 | 备注 |
---|---|---|---|---|
id | 标记点id | Number | 是 | marker点击事件回调会返回此id。建议为每个marker设置上Number类型id,保证更新marker时有更好的性能。最大限制9位数 |
latitude | 纬度 | Number | 是 | 浮点数,范围 -90 ~ 90 |
longitude | 经度 | Number | 是 | 浮点数,范围 -180 ~ 180 |
title | 标注点名 | String | 否 | 点击时显示,callout存在时将被忽略 |
iconPath | 显示的图标 | String | 是 | 项目目录下的图片路径,支持相对路径写法,以’/'开头则表示相对小程序根目录;也支持临时路径 |
width | 标注图标宽度 | Number | 否 | 默认为图片实际宽度 |
height | 标注图标高度 | Number | 否 | 默认为图片实际高度 |
使用maker可以实现在地图上标记目标点位或者“我的”实时位置,格式举例如下:
//标记地点 ====> 需要在地图上绘制的点
var obj = {
width: 30,
height: 30,
latitude: Number(self.reportInfo.lttd),
longitude: Number(self.reportInfo.lgtd),
iconPath: '../../../static/icon/6.png' // 成功绘制
};
//垃圾桶====> 需要在地图上绘制的点
var bin = {
id: "0",
latitude: Number(24.44379),
longitude: Number(118.08243),
width: 20,
height: 20,
iconPath: '../../../static/icon/9.png', // 成功绘制
title: "垃圾桶"
};
// ====> 需要在地图上绘制的点
var bin2 = {
id: "1",
latitude: Number(24.44879),
longitude: Number(118.09243),
width: 20,
height: 20,
iconPath: '../../../static/icon/9.png', // 成功绘制
title: "垃圾桶"
}
// 这里定位了一个集合, 并将前面给的三个标记点存入
var arr = [];
arr.push(obj);
arr.push(bin);
arr.push(bin2);
指定一系列坐标点,从数组第一项连线至最后一项
属性 | 说明 | 类型 | 必填 | 备注 |
---|---|---|---|---|
points | 经纬度数组 | Array | 是 | [{latitude: 0, longitude: 0}] |
color | 线的颜色 | String | 否 | 8位十六进制表示,后两位表示alpha值,如:#0000AA |
width | 线的宽度 | Number | 否 | |
dottedLine | 是否虚线 | Boolean | 否 | 默认false |
borderColor | 线的边框颜色 | String | 否 | |
borderWidth | 线的厚度 | Number | 否 |
注意事项
通过这个事件可以让用户在组件上选点,用法如下:
所以通过tap事件就可以获取用户点击的详细经纬度 ,举个例子就知道了:
经度=target.detail.longitude;
纬度=target.detail.latitude;
官方文档速查
获取当前的地理位置、速度。
这个API的使用也十分简单,需要配置一些参数(而且这些参数都是可选的),配合一个success获取结果res。这个res包含关键信息:用户当前所在的经纬度(完整结果如下),就这么简单。
只是这个接口有几个坑需要注意:
以下是最好是进行配置参数:(不过貌似加了用处不大,可选吧
type: 'gcj02', // 'wgs84'默认gps 坐标 ;腾讯地图支持'gcj02'国测,减少误差
altitude: false, // 是否返回高度 ,设置为false可以提高响应速度
isHighAccuracy: true, // 是否是高精度,选是就完事...貌似没差多少5
如果有时候suceess方法进不去,进入fail方法提示getLocation:fail the api need to be declared in the requiredPrivateInfos field in app.json
。
解决方法:添加配置解决。具体方案:https://blog.csdn.net/qq_40047019/article/details/125997964
可以尝试在用户启动界面时,向用户获取权限,那就需要用到下面的几个API了
uni 的授权方法,一般搭配uni.getSetting和uni.openSetting使用。 文档地址
这个方法需要特别注意,要获取用户的位置权限,必须配置scope: 'scope.userLocation'
按官方文档的说法,必须获取选取后才能执行getLocation方法,所以建议将这个方法搭载在onLoad内执行
获取权限的方法就按附件内CV执行就行
在微信小程序中,必须在mainfest.json
文件中添加配置。如下。完整版上面有截图
"permission": {
"scope.userLocation": {
"desc": "小程序将使用定位功能"
}
},
调起客户端小程序设置界面,返回用户设置的操作结果。也是个普通的获取权限的接口,可以配合uni.authorize(OBJECT)
一起用。具体看附件,配套CV使用即可
简单粗暴的使用应用内置地图查看位置。文档地址
直接跳转到微信的地图界面,用户可以在内置的地图软件上选择是否进行导航
调用这个API可以实现一个简单的导航功能(敷衍版,但也算实现导航
为了用户更好的体验,建议加上属性name和address,可以提高用户体验
给个案例
uni.openLocation({ // 使用应用内置地图查看位置。
// 跳出去以后是可以调用系统自带的导航 并显示以下的位置信息
latitude: Number(24.44579), // 纬度(必选)
longitude: Number(118.08243), // 精度 (必选 ,感觉可以用作动态的地址
name: '康佰家厦门小药房', // 位置名 可选
address: '药店',
success: (res) => {
// console.log('成功触发导航', res);
}
})
网上已经很多了,按照官方文档操作也是完全没有问题的。这里针对小程序进行设置,官方文档地址。以下4个步骤直接参考文档操作即可
申请开发者密钥(key):申请密钥
开通webserviceAPI服务:控制台 ->应用管理 -> 我的应用 ->添加key-> 勾选WebServiceAPI -> 保存
(小程序SDK需要用到webserviceAPI的部分服务,所以使用该功能的KEY需要具备相应的权限)
下载微信小程序JavaScriptSDK,微信小程序JavaScriptSDK v1.1 JavaScriptSDK v1.2
安全域名设置,在小程序管理后台 -> 开发 -> 开发管理 -> 开发设置 -> “服务器域名” 中设置request合法域名,添加https://apis.map.qq.com
注意事项:要实现导航功能,就需要选择v1.2的SDK才行
至此,最基本的配置就完成了
官方文档提供了以下方法
方法 说明 search(options:Object) 地点搜索,搜索周边poi,比如:“酒店” “餐饮” “娱乐” “学校” 等等 getSuggestion(options:Object) 用于获取输入关键字的补完与提示,帮助用户快速输入 reverseGeocoder(options:Object) 提供由坐标到坐标所在位置的文字描述的转换。输入坐标返回地理位置信息和附近poi列表 geocoder(options:Object) 提供由地址描述到所述位置坐标的转换,与逆地址解析的过程正好相反 direction(options:Object) 提供驾车,步行,骑行,公交的路线规划能力 getCityList() 获取全国城市列表数据 getDistrictByCityId(options:Object) 通过城市ID返回城市下的区县 calculateDistance(options:Object) 计算一个点到多点的步行、驾车距离
提供由坐标到坐标所在位置的文字描述的转换。输入坐标返回地理位置信息和附近poi列表
需要发送的类型(必发的):location (经纬度信息,具体格式参考官方文档
返回的结果类型非常详细,常用的有以下几个
formatted_addresses.recommend
——经过腾讯地图优化过的描述方式,更具人性化特点address_component
——地址部件,address不满足需求时可自行拼接address
——简单的地图描述(大部分时候用这个就行了)案例如下:
tMap.reverseGeocoder({ // 这个方法的作用 :提供由坐标到坐标所在位置的文字描述的转换。输入坐标返回地理位置信息和附近poi列表
location: { // 位置坐标 发送 获取属性的
latitude: self.reportInfo.lttd,
longitude: self.reportInfo.lgtd
},
// 改用res,data的形式测试接收的结果
success: function(res) { // 所以,这里返回的结果就是 : 坐标所在位置的文字描述
console.log('坐标所在位置的文字描述', res.result);
// 获取到的参数
self.plot = res.result.formatted_addresses; // 存入了一个 经过腾讯地图优化过的描述方式,更具人性化特点
self.address = res.result.address; // 也是一串地址
// 地址的组成 包含国 省 市 等等。。的详细信息
self.addressComponent = res.result.address_component;
// console.log(province);
},
fail: function(res) {
console.log('定位获取错误', res);
}
// complete: function(res) { //无论成功失败都会执行 测试后也是获取一样的内容,表示可以注释掉
// console.log('无论成功失败都会执行',res);
// }
});
<template>
<view>
<view class="page-body">
<view class="page-section page-section-gap map">
<map @tap="getMapLocation" style="width: 100vw; height: 800rpx;" :latitude="reportInfo.lttd"
:longitude="reportInfo.lgtd" :markers="covers" enable-3D="true" >
map>
view>
<view class="item">
<view class="content">
<view class="desc solid-bottom row-info">
<view class="text-black margin-top-sm overflow-2 item-title"><text
class="cuIcon-location text-green text-xxl">text>您当前所在位置: <text
class="text-green">{{ plot.rough }}text>view>
<view class="text-black text-sm margin-top-sm overflow-2 item-content">
系统已为您匹配到最近的商家位置
view>
<view class="item-content">
编号:<text class="text-red">JN00405text>
<text style="margin-left: 58rpx;">距您:text> <text class="text-red">{{distance}}text>KM
view>
<view class="uni-button-group">
<button class="uni-button" @click="markertap"
:styles="{'borderColor':'#678D5D'}">导航button>
view>
view>
view>
view>
view>
view>
template>
<script>
import QQMapWX from '../../../util/map/qqmap-wx-jssdk.js'
const tMap = new QQMapWX({
key: '' // 存入你的key
})
export default {
data() {
return {
content: '(一)将回收价值高的可回收物率先分类投放,如报纸杂志、纸板箱、包装盒、PET塑料瓶、易拉罐等,确保这一类可回收物不被混合垃圾污染。(二)不要将已被污染、潮湿、污渍无法清除的物品投入可回收物收集容器,如被油渍污染的餐盒、食品包装盒等。瓶罐投放前倒空瓶内液体并简单清洗,有瓶盖的不需将瓶盖与瓶体分开投放,确保可回收物收集容器中的其他废品不被污染,尊重和维护他人分类的成果。(三)不确定是否可以回收(或本指引中未明确说明)的废纸、废塑料,在未被污染的情况下,请先投放至可回收物收集容器',
// 默认坐标北京
reportInfo: {
lgtd: 116.39742,
lttd: 39.909,
},
id: 0, // 使用 marker点击事件 需要填写id
title: 'map',
latitude: 39.909,
longitude: 116.39742,
//第一组为匹配的垃圾桶
covers: [], //存放标记点数组
isLocated: false, // 是否被定位
//小区
plot: {},
//详细地址
address: '',
//地址组成
addressComponent: {
city: "",
district: "",
nation: "",
province: "",
street: "",
street_number: "",
},
distance: 0.1,
}
},
methods: {
/**
* 获取经纬度并触发回调函数 ========== 调用这个方法 203行
* @param {Function} successCb 获取成功回调
* @param {Function} authDenyCb 获取失败回调
*/
getLocationA(successCb, authDenyCb) {
const self = this // 将vue实例赋值给self以便调用
// console.log('触发了getLocationA,参数的值分别是', successCb, authDenyCb);
// uniapp自带的API == > https://uniapp.dcloud.net.cn/api/location/location.html
uni.getLocation({ // 这个方法就可以获取定位
type: 'gcj02', // 'wgs84'默认gps 坐标 'gcj02'国测
altitude: false, // 是否返回高度
accuracy: 'best', // 精度值为20m
geocode: false, // 默认false,是否解析地址信息 === 文档内提示仅app平台支持,这里改为false
// 接口调用成功的方法 === 正常触发,问题已解决,可以获取用户所在的地址信息
success(res) {
console.log('成功获取用户所在地址', res)
successCb && successCb(res); // 写法很怪,
self.isLocated = true; // 将isLocated设置为true 表示已获取了用户的当前定位
//获取经纬度res.latitude 和 res.longitude ===> 将经纬度赋值给vue变量
self.reportInfo.lttd = res.latitude;
self.reportInfo.lgtd = res.longitude;
//标记地点 ====> 猜测是需要在地图上绘制点数
var obj = {
width: 30,
height: 30,
latitude: Number(self.reportInfo.lttd),
longitude: Number(self.reportInfo.lgtd),
iconPath: '../../../static/icon/6.png' // 成功绘制
};
//垃圾桶====> 猜测是需要在地图上绘制点数
var bin = {
id: "0",
latitude: Number(24.44379),
longitude: Number(118.08243),
width: 20,
height: 20,
iconPath: '../../../static/icon/9.png', // 成功绘制
title: "垃圾桶"
};
// ====> 猜测是需要在地图上绘制点数
var bin2 = {
id: "1",
latitude: Number(24.44879),
longitude: Number(118.09243),
width: 20,
height: 20,
iconPath: '../../../static/icon/9.png', // 成功绘制
title: "垃圾桶"
}
// 这个方法是调用了测算距离的方法,算出来了两个经纬度之间的大致举例
self.distance = self.getMapDistance(
self.reportInfo.lttd,
self.reportInfo.lgtd,
24.44879,
118.09243
)
// 这里定位了一个集合, 并将前面给的三个标记点存入
var arr = [];
arr.push(obj);
arr.push(bin);
arr.push(bin2);
//标记点集合赋值个给了vue对象covers == > 打印出来看看
self.covers = arr;
// console.log('vue对象covers == > 打印出来看看',self.covers );
},
fail(err) { // 定位获取失败后的提示
console.log('获取定位出错', err); // 新增
if (err.errMsg === 'getLocation:fail 频繁调用会增加电量损耗,可考虑使用 wx.onLocationChange 监听地理位置变化') {
uni.showToast({
title: '请勿频繁定位',
icon: 'none'
});
}
if (err.errMsg === 'getLocation:fail auth deny') {
// 未授权
uni.showToast({
title: '无法定位,请重新获取位置信息',
icon: 'none'
})
authDenyCb && authDenyCb()
self.isLocated = false;
}
if (err.errMsg === 'getLocation:fail:ERROR_NOCELL&WIFI_LOCATIONSWITCHOFF') {
uni.showModal({
content: '请开启手机定位服务',
showCancel: false
});
}
},
complete() { // 接口调用结束的回调函数(调用成功、失败都会执行)
console.log('进入了complete方法,用户的定位信息:', self.reportInfo)
// tMap是腾讯地图的对象 === 这边开始调用了
// 用法查询地址:https://lbs.qq.com/miniProgram/jsSdk/jsSdkGuide/qqMapwx
tMap.reverseGeocoder({ // 这个方法的作用 :提供由坐标到坐标所在位置的文字描述的转换。输入坐标返回地理位置信息和附近poi列表
location: { // 位置坐标 发送 获取属性的
latitude: self.reportInfo.lttd,
longitude: self.reportInfo.lgtd
},
// 改用res,data的形式测试接收的结果
success: function(res) { // 所以,这里返回的结果就是 : 坐标所在位置的文字描述
console.log('坐标所在位置的文字描述', res.result);
// 获取到的参数
self.plot = res.result
.formatted_addresses; // 存入了一个 经过腾讯地图优化过的描述方式,更具人性化特点
self.address = res.result.address; // 也是一串地址
// 地址的组成 包含国 省 市 等等。。的详细信息
self.addressComponent = res.result.address_component;
// console.log(province);
},
fail: function(res) {
console.log('定位获取错误', res);
}
// complete: function(res) { //无论成功失败都会执行 测试后也是获取一样的内容,表示可以注释掉
// console.log('无论成功失败都会执行',res);
// }
});
}
})
},
/**
* 重新授权并调用定位方法 == 这个方法在电脑调试可以正常运行 在页面onload加载时调用,一解读完毕,
* @param {Function} successCb 授权成功回调
* @param {Function} authDenyCb 授权失败回调
*/
getAuthorize(successCb, authDenyCb) {
// authorize是uni 的授权方法,一般搭配uni.getSetting和uni.openSetting使用。 稳定地址:https://uniapp.dcloud.net.cn/api/other/authorize.html#authorize
uni.authorize({
scope: 'scope.userLocation', // 需要获取权限的 scope,其中scope.userLocation 指地理位置 需要配置小程序弹出时的提示信息
success: () => {
this.getLocationA(successCb, authDenyCb); // 授权成功就可以获得当前的定位
},
fail: (err) => { // 失败则会调用弹窗提示用户是否进行授权
err = err['errMsg']
uni.showModal({
content: '需要授权位置信息',
confirmText: '确认授权'
})
.then((res) => { // 用户点击同意后,
if (res[1]['confirm']) { // 看不懂
uni.openSetting({ // 调起客户端小程序设置界面,返回用户设置的操作结果。 https://uniapp.dcloud.net.cn/api/other/setting.html#opensetting
success: (res) => {
if (res.authSetting['scope.userLocation']) {
// 授权成功
uni.showToast({
title: '授权成功',
icon: 'none'
})
} else {
// 未授权
uni.showToast({
title: '授权失败',
icon: 'none'
})
}
this.getLocationA(successCb, authDenyCb) // 这里也调用了
}
})
}
if (res[1]['cancel']) {
// 取消授权
console.log('取消')
this.getLocationA(successCb, authDenyCb)
}
})
}
})
},
//手动动获取定位 这个方法挂在
getMapLocation(target) {
// console.log('点击了地图', target);
var that = this;
// 将获取到的坐标赋值给vue对象
that.reportInfo.lttd = target.detail.latitude;
that.reportInfo.lgtd = target.detail.longitude;
// 加入标记点
var obj = {
width: 30,
height: 30,
latitude: that.reportInfo.lttd,
longitude: that.reportInfo.lgtd,
iconPath: '../../../static/icon/6.png'
};
var arr = [];
arr.push(obj);
that.covers = arr;
// 经过测试 res的报错信息是:chooseLocation:fail the api need to be declared in…e requiredPrivateInfos field in app.json/ext.json
// console.log('进入chooseLocation的complete:',res);
console.log('要调用txmap的参数是', that.reportInfo);
// 在这边调用了腾讯地图的接口: 和上面方法是一样的作用,将坐标转换为文字描述
tMap.reverseGeocoder({
location: {
latitude: that.reportInfo.lttd,
longitude: that.reportInfo.lgtd
},
success: function(res) {
console.log('将坐标转换为文字描述===解析地址成功',res.result.location);
// 一样的作用,继续将地址信息存入vue对象中
// ====> 但问题是:一直都是获取通用的的地址
that.plot = res.result.formatted_addresses;
that.address = res.result.address;
that.addressComponent = res.result.address_component;
let city = res.result.ad_info.city;
},
fail: function(res) {
console.log('调用接口失败了', res);
}
});
},
//导航到指定位置 ltt lgt ====> 导航点击时触发的按钮
markertap() {
let that = this
//调出地图传入目的地 ltt lgt
// console.log('1、点击导航要获取用户的位置');
uni.getLocation({ // 1、点击导航要获取用户的位置
success: (res) => { // 2、成功时的操作 ==== but 一直进不来这个方法
// 添加配置解决:https://blog.csdn.net/qq_40047019/article/details/125997964
uni.openLocation({ // 3、 使用应用内置地图查看位置。
// 跳出去以后是可以调用系统自带的导航 并显示以下的位置信息
latitude: Number(24.44579), // 纬度(必选)
longitude: Number(118.08243), // 精度 (必选 ,感觉可以用作动态的地址
name: '康佰家厦门小药房', // 位置名 可选
address: '药店',
success: (res) => {
// console.log('成功触发导航', res);
},
fail: function() { // 失败触发的方法,不管了
uni.showModal({
title: '错误',
content: '请检查定位是否打开',
showCancel: false,
success: function(res) {
if (res.confirm) {
console.log('用户点击确定');
} else if (res.cancel) {
console.log('用户点击取消');
}
}
})
}
});
},
fail: (res) => {
console.log('方法调用失败', res);
}
})
},
//进行经纬度转换为距离的计算 === 和下面的方法进行了绑定;也不管他
Rad(d) {
return d * Math.PI / 180.0; //经纬度转换成三角函数中度分表形式。
},
/*
计算距离,参数分别为第一点的纬度,经度;第二点的纬度,经度
默认单位km // 封装好的方法,也不管了
*/
getMapDistance(lat1, lng1, lat2, lng2) {
var radLat1 = this.Rad(lat1);
var radLat2 = this.Rad(lat2);
var a = radLat1 - radLat2;
var b = this.Rad(lng1) - this.Rad(lng2);
var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
s = s * 6378.137; // EARTH_RADIUS;
s = Math.round(s * 10000) / 10000; //输出为公里
//s=s.toFixed(2);
return s;
},
},
components: {
},
onLoad() {
console.log("in onload触发,执行getAuthorize")
this.getAuthorize(); // 页面第一次加载时就会触发这个方法
},
onShow() {
},
}
script>
<style>
.map {
border: 9rpx solid #678D5D;
/* border-radius: 14rpx; */
}
.content {
margin-top: 100rpx;
width: 100%;
height: 307rpx;
border: 11rpx solid #;
border-radius: 17rpx;
/* color: white; */
background-color: #ffffff;
}
.item {
margin-top: 84rpx;
border: 5px none #9E9E9E;
border-radius: 25rpx;
/* margin-left: 25rpx;
margin-right: 25rpx; */
box-shadow: 4px 4px 5px #999;
padding-bottom: 30rpx;
display: block;
background-color: var(--white);
overflow: hidden;
font-weight: 700;
}
.item-title {
height: 73rpx;
/* border-bottom: 9rpx solid #678D5D; */
margin-left: 30rpx;
margin-right: 30rpx;
font-size: 28rpx;
margin-top: -48rpx;
}
.item-content {
height: 62rpx;
/* border: 3rpx solid #9E9E9E; */
margin-left: 40rpx;
margin-right: 40rpx;
font-size: 34rpx;
/* text-justify: initial; */
/* font-style: solid; */
}
.uni-button-group {
/* margin-top: 50px; */
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
}
.uni-button {
width: 228rpx;
padding: 12px 20px;
font-size: 14px;
border-radius: 12px;
line-height: 1;
margin: 0;
background-color: #678D5D;
color: white;
}
.sider-img {
width: 254rpx;
height: 306rpx;
}
.m-footer {
margin-top: 162rpx;
margin-left: 482rpx;
}
.img-footer {
margin-top: -50rpx;
border-bottom: 9rpx solid #678D5D;
width: 300rpx;
font-weight: 700;
}
style>
基于案例实现一个导航模块