微信页面开发中遇到需要定位设备位置信息的功能,第一反应是现看看浏览器有没有提供这个方法。
一、navigator.geolocation.getCurrentPosition
浏览器的navigator是用于获取当前设备位置的方法的:navigator.geolocation.getCurrentPosition(_success_, _error_, _options_)<br />[https://developer.mozilla.org/zh-CN/docs/Web/API/Geolocation/getCurrentPosition](https://developer.mozilla.org/zh-CN/docs/Web/API/Geolocation/getCurrentPosition)<br />但是该方法在使用中并不尽如人意。<br />下面是一段获取经纬度的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* { margin: 0; padding: 0;}
#box {
width: 500px;
height: 500px;
border: 2px solid deeppink;
}
</style>
</head>
<body>
<button id='btn'> 请求位置信息 </button>
<div id="box"></div>
<script>
let btn = document.getElementById('btn');
let box = document.getElementById('box');
//点击按钮获取地理位置信息
btn.onclick = function () {
//getCurrentPosition与定时器setInterval类似多次请求,因为位置需要不间断的获取
//直接navigator.geolocation表示单次获取位置
navigator.geolocation.getCurrentPosition(function (position) {
box.innerHTML += "经度" + position.coords.longitude;
box.innerHTML += "纬度" + position.coords.latitude;
box.innerHTML += "准确度" + position.coords.accuracy;
box.innerHTML += "海拔" + position.coords.altitude;
box.innerHTML += "海拔准确度" + position.coords.altitudeAcuracy;
box.innerHTML += "行进方向" + position.coords.heading;
box.innerHTML += "地面速度" + position.coords.speed;
box.innerHTML += "请求的时间" + new Date(position.timestamp);
}, function (err) {
alert(err.code);
// code:返回获取位置的状态
// 0 : 不包括其他错误编号中的错误
// 1 : 用户拒绝浏览器获取位置信息
// 2 : 尝试获取用户信息,但失败了
// 3 : 设置了timeout值,获取位置超时了
}, {
enableHighAcuracy: false, //位置是否精确获取
timeout: 5000, //获取位置允许的最长时间
maximumAge: 1000 //多久更新获取一次位置
})
}
</script>
</body>
</html>
在谷歌中年,错误代码 3<br />在IE中,错误代码 1<br />安卓手机浏览器下,错误代码1
所以这种方法被抛弃~
无论是在pc端还是手机浏览器,微信等,我都是授权了允许获取地理位置的,但是还是被禁止了(猜测是浏览器自身禁止了这个方法)。
这个我最想使用的方法不能使用,真的是欲哭无泪。也可能是系统为了安全考虑,浏览器不被允许随便获取位置信息,那为啥还有提供这个API呢,我真的是CTMD!!!
1、为什么会无法使用这个API
关于这个api为什么会无法使用,查找了一些资料,我个人得出的结论是谷歌的位置服务被禁止了。
pc端代码里尝试控制台输出的错误信息是这样的。
二、尝试微信提供的方法
微信是提供了这个方法的,但是公众号页面好久没开发了,已经不记得需要哪些操作才能调用起微信提供的API了(大概率是现要对网页进行授权,有点印象)。
查找了一下官方文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
因为后端也是我写,大致总结一下,整个流程步骤:
获取设备定位流程步骤:
后端:
①获取Access token
参考文档:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html
②用获取的access_token来获取jsapi_ticket,
参考文档:
https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#62
③通过jsapi_ticket来获取签名
(这一步也可以前端做,为了安全性,最好是后端来做)
前端:
①签名注入
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名
jsApiList: [] // 必填,需要使用的JS接口列表
});
②在wx.ready中去调用微信api
wx.ready(function(){
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
wx.getLocation({
success: function (res) {
var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90
var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。
var speed = res.speed; // 速度,以米/每秒计
var accuracy = res.accuracy; // 位置精度
localStorage.setItem("latitude", latitude);
localStorage.setItem("longitude", longitude);
var data = {
latitude: latitude,
longitude: longitude
};
if (typeof callback == "function") {
callback(data);
}
},
cancel: function () {
//这个地方是用户拒绝获取地理位置
if (typeof error == "function") {
error();
}
}
});
});
③将获取的经纬度传给第三方地图插件
百度地图、腾讯地图、高德地图都可以,具体看公司的需求。
来获取经纬度代表的省市县信息。
例如百度地图代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button onclick="showInfo()">解析经纬度</button>
<div class="box" style="text-align: center;">
<div style="font-weight: bold;">获取到的信息</div>
<div>纬度:<input type="text" id="lat" value="" readonly></div>
<div>经度:<input type="text" id="lng" value="" readonly></div>
<div>地址 :<input type="text" id="address" readonly></div>
</div>
<div id='allmap'></div>
</body>
</html>
<script src="http://api.map.baidu.com/api?v=2.0&ak=vtoQgAd5XCDNCFiUqYMKIFGQ1dr1tD1d"></script>
<script>
const lat = '39.961185'
const lng = '116.459029'
var map = new BMap.Map();
var geoc = new BMap.Geocoder(); //地址解析对象
//点击地图时间处理
function showInfo() {
document.getElementById('lng').value = lng
document.getElementById('lat').value = lat
var point = new BMap.Point(lng, lat);
geoc.getLocation(point, function (rs) {
var addComp = rs.addressComponents;
var address = addComp.province + addComp.city + addComp.district + addComp.street + addComp.streetNumber;
if (confirm("确定要地址是" + address + "?")) {
document.getElementById('address').value = address;
}
});
}
</script>
三、直接用百度插件提供的定位方法
通过微信的方法虽然可以准确有效的获取地理位置信息,但是由于比较麻烦,而且公司也没有那么高的要求,是否可以采用百度的定位方法。
笔者猜测百度的js_sdk应该是有提供类似的方法的。最后找到了百度基于IP进行定位的一个方法如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="allmap"></div>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=vtoQgAd5XCDNCFiUqYMKIFGQ1dr1tD1d"></script>
<script>
</script>
<script type="text/javascript">
// var map = new BMap.Map();
var geolocation = new BMap.Geolocation();
// 我们可以看到此处的写法和浏览器自带api写法类似,查询资料知道这个方法本质上就是navigator的方法(what,为啥我直接用就不行,百度插件就可以,崩溃!)(pc端准确率我感觉能差个二三十公里,我在大兴区,直接给我定位到东城区了)
// 查询资料发现这个定位是基于浏览器给就近的服务器发送消息来获取的IP定位,因此定位精度堪忧。但是足够我的项目使用了~
geolocation.getCurrentPosition(function(r){
console.log(r.point)
const point = r.point
reset_location(point)
});
function reset_location(po){
const point = new BMap.Point(po.lng,po.lat);
var geoc = new BMap.Geocoder();
geoc.getLocation(point, function(rs){
const _value = rs.addressComponents;
const province = _value.province;
const city = _value.city;
const county = _value.district;
const street = _value.street + _value.streetNumber;
console.log(province)
console.log(city)
console.log(county)
});
}
</script>
</body>
</html>