直接用 Haversine 公式计算经纬度直线距离,比调用地图 SDK 更快更准且省配额;但需先统一坐标系——uni.getLocation 返回 WGS84,若后端为 GCJ02 或 BD09,须用 coordtransform 库转换后再计算。

直接用 Haversine 公式算,别调地图 SDK 的距离接口——除非你真需要驾车/步行路径,否则纯经纬度直线距离,前端自己算又快又准,还省 API 调用配额和白名单配置。
uni.getLocation 获取的是 WGS84 坐标,但后端给的可能是 GCJ02 或 BD09
这是最常踩的坑:uni-app 默认 uni.getLocation({ type: 'wgs84' }) 返回的是原始 GPS 坐标(WGS84),但国内多数地图服务(高德、腾讯)要求或返回的是加密坐标系。如果你拿 WGS84 直接去套 GCJ02 的点算距离,偏差可能达 500 米以上。
- 先确认后端接口文档里写的坐标系类型,关键词是
gcj02、bd09或wgs84 - 如果后端返回的是
gcj02,而你用wgs84原始值直接计算,必须先做一次wgs84togcj02转换(注意:这个转换不可逆,且无官方公式,得用社区验证过的近似算法) - 百度坐标
bd09不能直接和其它坐标系混用,必须先转成gcj02或wgs84才能参与 Haversine 计算 - 转换库推荐用
coordtransform(npm 包名同名),它把三者互转都封装好了,别手抄网上残缺版
用 Haversine 公式计算距离,单位默认是公里
地球是球面,不能用平面勾股定理。Haversine 是业内通用解法,精度足够日常 LBS 场景(1km 内误差
示例函数(可直接复制进 utils/location.js):
function getDistance(lat1, lng1, lat2, lng2) {
const R = 6371; // 地球平均半径,单位 km
const dLat = (lat2 - lat1) * Math.PI / 180;
const dLng = (lng2 - lng1) * Math.PI / 180;
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1 * Math.PI / 180) *
Math.cos(lat2 * Math.PI / 180) *
Math.sin(dLng / 2) *
Math.sin(dLng / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return parseFloat((R * c).toFixed(2)); // 返回两位小数的公里数
}- 输入顺序固定为
getDistance(当前纬度, 当前经度, 目标纬度, 目标经度),别把 lat/lng 搞反 - 如果后端返回的是百度坐标
bd09,先调bd09togcj02(lng, lat)得到[gcj_lng, gcj_lat],再传给getDistance - 不要对结果再乘 1000 换米——除非你明确要米制显示,否则保留公里更符合用户直觉(比如“1.23km”比“1234m”更易读)
微信小程序里 uni.getLocation 可能失败,得兜底处理
微信小程序对定位权限管控极严:scope.userLocation 必须在 manifest.json 里声明,且首次调用会弹窗;用户拒绝后,后续调用直接进 fail 回调,不会重试。
- 务必在
fail里给默认值或提示,例如设distance = null并显示“定位不可用,请手动选择城市” - 避免连续调用
uni.getLocation,它不是 Promise,不支持 await,重复调可能触发频率限制 - 真要重试,用
setTimeout+ 标志位控制,最多试 2 次 - 测试时用开发者工具「模拟位置」功能,真机调试前先确认手机系统级定位开关已开
坐标系对齐比算法本身更重要——很多“算出来不对”的问题,根源是 WGS84 和 GCJ02 当成同一套数据用了。转换步骤宁可多写两行,也别图省事跳过。


















