使用navigator.geolocation解决h5公众号定位不准确的问题
封装js(utils/geolocation.min.js):
window.qq=window.qq||{},qq.maps=qq.maps||{},window.soso||(window.soso=qq),soso.maps||(soso.maps=qq.maps),qq.maps.Geolocation=function(){"use strict";var e=[],t=null,o=0,n="_geoIframe_"+Math.ceil(1e7*Math.random()),i=document.createElement("iframe"),r=null,s=null,a=null,c=null,u=function(u,l){if(!u)return void alert("请输入key!");if(!l)return void alert("请输入referer!");var p=document.getElementById(n);if(!p){i.setAttribute("id",n),i.setAttribute("allow","geolocation");var g="https:";i.setAttribute("src",g+"//apis.map.qq.com/tools/geolocation?key="+u+"&referer="+l),i.setAttribute("style","display: none; width: 100%; height: 30%"),document.body?document.body.appendChild(i):document.write(i.outerHTML);var m=this;window.addEventListener("message",function(n){var i=n.data;if(i&&"geolocation"==i.module){if(clearTimeout(c),e.length>0){var u=e.shift();u.sucCb&&u.sucCb(i)}o=2,m.executeNextGeo(),t&&t(i)}else{s=(new Date).getTime();var l=s-r;if(l>=a){if(e.length>0&&"geo"===e[0].type){var u=e.shift(),p={type:"fail",code:5,message:"The request"};u.errCb&&u.errCb(p)}clearTimeout(c),o=-1,m.executeNextGeo()}if(e.length>0&&"ip"===e[0].type){var u=e.shift();u.errCb&&u.errCb(p)}}},!1)}};return u.prototype.executeNextGeo=function(){1!==o&&e.length>0&&(o=1,e[0].geoprocess())},u.prototype.getLocation=function(t,n,i){if(i&&i.timeout){var r=new RegExp("^[0-9]*$");if(!r.test(i.timeout))return void alert("timeout 请输入数字")}if(e.length>10)throw new Error("geolocation queue must be lass than 10");e.push({sucCb:t,errCb:n,option:i,geoprocess:this.getOnceLocation,type:"geo"}),1!==o&&(o=1,this.getOnceLocation())},u.prototype.getOnceLocation=function(){var t=e[0]&&e[0].option;r=(new Date).getTime(),a=t&&t.timeout?+t.timeout:1e4,clearTimeout(c),c=setTimeout(function(){if(e.length>0){var t=e.shift();t.errCb&&t.errCb()}},a),document.getElementById(n).contentWindow.postMessage("getLocation","*")},u.prototype.getIpLocation=function(t,n){if(e.length>10)throw new Error("geolocation queue mast be lass than 10");e.push({sucCb:t,errCb:n,geoprocess:this.getOnceIpLocation,type:"ip"}),1!==o&&(o=1,this.getOnceIpLocation())},u.prototype.getOnceIpLocation=function(){document.getElementById(n).contentWindow.postMessage("getLocation.robust","*")},u.prototype.watchPosition=function(e){t=e,document.getElementById(n).contentWindow.postMessage("watchPosition","*")},u.prototype.clearWatch=function(){t=null,document.getElementById(n).contentWindow.postMessage("clearWatch","*")},u}();
精确定位使用:
<!-- 精确定位 -->
<template>
<view>{{ positionInfo }}</view>
</template>
<script>
import '@/utils/geolocation.min.js';
export default {
data() {
return {
positionInfo: ''
};
},
onLoad(options) {
this._initLocation();
},
methods: {
_initLocation() {
if (origin.indexOf('https') === -1) {
uni.showToast({
title: '请在https环境中使用'
});
return;
}
if (!navigator || !navigator.geolocation) {
uni.showToast({
title: '地理位置服务不可用'
});
return;
}
uni.showLoading({
title: '定位中...',
mask: true
});
const options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
};
/** err 说明
code 1 表示用户拒绝授权
code 3 未获取到地址信息,可能是设备没有开启定位服务或者系统没有给浏览器定位权限
**/
navigator.geolocation.getCurrentPosition(
(position) => {
const lat = position.coords.latitude,
lng = position.coords.longitude,
geo = new qq.maps.Geolocation('地图api key', '获取位置信息');
geo.getLocation(this.getLocationSuccess, this.getLocationErr, options);
},
(err) => {
if (err.code === 1) {
uni.showModal({
title: '获取定位权限失败',
content: '你拒绝了位置授权服务。请允许当前页面获取定位授权,后刷新页面。'
});
} else {
uni.showModal({
title: '获取定位权限失败',
content: '请确定手机定位已打开,并且当前浏览器允许获取定位,都开启后请刷新页面。'
});
}
uni.hideLoading();
}
);
},
getLocationSuccess(position) {
uni.showToast({
title: '定位成功!',
duration: 1000
});
this.positionInfo = position;
uni.hideLoading();
},
getLocationErr() {
uni.showToast({
title: '获取位置失败!',
duration: 2000
});
uni.hideLoading();
}
}
};
</script>
效果:

ip定位使用:
<!-- IP定位 -->
<template>
<view>{{ positionInfo }}</view>
</template>
<script>
import '@/utils/geolocation.min.js';
export default {
data() {
return {
positionInfo: ''
};
},
onLoad(options) {
this._initLocation();
},
methods: {
_initLocation() {
if (origin.indexOf('https') === -1) {
uni.showToast({
title: '请在https环境中使用'
});
return;
}
if (!navigator || !navigator.geolocation) {
uni.showToast({
title: '地理位置服务不可用',
duration: 2000
});
return;
}
const options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
};
uni.showLoading({
title: '定位中...',
mask: true
});
/** err 说明
code 1 表示用户拒绝授权
code 3 未获取到地址信息,可能是设备没有开启定位服务或者系统没有给浏览器定位权限
**/
navigator.geolocation.getCurrentPosition(
(position) => {
const lat = position.coords.latitude,
lng = position.coords.longitude,
geo = new qq.maps.Geolocation('QAWBZ-S2MWR-U5OWI-WZBUC-UXDSZ-AAFRJ', '获取位置信息');
geo.getIpLocation(this.getIpLocationSuccess, this.getIpLocationErr, options);
},
(err) => {
if (err.code === 1) {
uni.showModal({
title: '获取定位权限失败',
content: '你拒绝了位置授权服务。请允许当前页面获取定位授权,后刷新页面。'
});
} else {
uni.showModal({
title: '获取定位权限失败',
content: '请确定手机定位已打开,并且当前浏览器允许获取定位,都开启后请刷新页面。'
});
}
uni.hideLoading();
}
);
},
getIpLocationSuccess(position) {
uni.showToast({
title: '定位成功!',
duration: 1000
});
this.positionInfo = position;
uni.hideLoading();
},
getIpLocationErr() {
uni.showToast({
title: '获取位置失败!',
duration: 2000
});
uni.hideLoading();
}
}
};
</script>
效果如上一样,只是区别于当前是通过ip定位的。
实时监听当前位置:
<!-- 监听位置 -->
<template>
<view class="watch-position">
<view class="watch-position-btn">
<view class="btn" @click="watchPosition">开启监听</view>
<view class="btn" @click="clearWatch">关闭监听</view>
</view>
<view class="watch-position-info" v-if="positionInfo.length">
<view class="watch-position-info-title">位置信息:</view>
<view class="watch-position-info-list">
<view class="watch-position-info-list-item" v-for="(item, index) in positionInfo" :key="index">
{{ `第${index + 1}次:` }}<br />{{ JSON.stringify(item) }}
</view>
</view>
</view>
</view>
</template>
<script>
import '@/utils/geolocation.min.js';
export default {
data() {
return {
positionInfo: [],
geo: null,
isWatch: false
};
},
onLoad() {
this._initPosition();
},
methods: {
_initPosition() {
if (origin.indexOf('https') === -1) {
uni.showToast({
title: '请在https环境中使用'
});
return;
}
if (!navigator || !navigator.geolocation) {
uni.showToast({
title: '地理位置服务不可用',
duration: 2000
});
return;
}
uni.showLoading({
title: '定位中...',
mask: true
});
/** err 说明
code 1 表示用户拒绝授权
code 3 未获取到地址信息,可能是设备没有开启定位服务或者系统没有给浏览器定位权限
**/
navigator.geolocation.getCurrentPosition(
(position) => {
const lat = position.coords.latitude,
lng = position.coords.longitude,
geo = new qq.maps.Geolocation('QAWBZ-S2MWR-U5OWI-WZBUC-UXDSZ-AAFRJ', '获取位置信息');
this.geo = geo;
uni.hideLoading();
},
(err) => {
if (err.code === 1) {
uni.showModal({
title: '获取定位权限失败',
content: '你拒绝了位置授权服务。请允许当前页面获取定位授权,后刷新页面。'
});
} else {
uni.showModal({
title: '获取定位权限失败',
content: '请确定手机定位已打开,并且当前浏览器允许获取定位,都开启后请刷新页面。'
});
}
uni.hideLoading();
}
);
},
watchPosition() {
const options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
};
if (this.isWatch)
return uni.showToast({
title: '已开启持续监听,请勿重复开启'
});
if (this.geo) {
this.isWatch = true;
this.geo.watchPosition(this.watchPositionSuccess, this.watchPositionErr, options);
} else {
uni.showModal({
title: '获取定位权限失败',
content: '请确定手机定位已打开,并且当前浏览器允许获取定位,都开启后请刷新页面。'
});
}
},
watchPositionSuccess(position) {
this.positionInfo.push(position);
},
watchPositionErr() {
uni.showToast({
title: '获取位置失败!'
});
},
clearWatch() {
if (!this.isWatch)
return uni.showToast({
title: '已关闭持续监听,请勿重复关闭'
});
this.isWatch = false;
this.geo.clearWatch();
}
}
};
</script>
<style lang="scss" scoped>
.watch-position {
min-height: 100vh;
background-color: #ededed;
&-info {
padding: 30rpx;
&-title {
margin-bottom: 30rpx;
}
&-list {
background: #fff;
&-item {
width: 100%;
margin-bottom: 20rpx;
word-break: break-all;
}
}
}
&-btn {
margin: 0 auto 40rpx;
text-align: center;
padding-top: 40rpx;
}
}
.btn {
background-color: #4cd964;
color: #ffffff;
margin: 0 auto 30rpx;
padding: 15rpx;
border-radius: 10rpx;
font-size: 26rpx;
text-align: center;
width: 40%;
}
</style>
效果:

注:使用浏览器定位域名必须是https访问
希望大佬看到有不对的地方,提出博主予以改正!

浙公网安备 33010602011771号