uni-app通过经纬度计算两点距离 uni-app地图开发数学公式

作者:袖梨 2026-06-13
应使用Haversine公式手算两点距离,因它纯JS、跨端兼容、精度高;需将经纬度转为弧度,地球半径取6371008.8米,避免欧氏距离或未转换导致数十公里偏差。

uni-app里用JavaScript算两点经纬度距离,别用百度/高德SDK的distance

直接调地图SDK的 distance 方法看似省事,但实际在uni-app中多数场景下不可用:微信小程序不支持高德/百度地图JS API的web版distance函数;H5虽能引入,但需鉴权且跨域受限;App端又得桥接原生。真正稳定、跨端、零依赖的方式是手写球面余弦定理或Haversine公式——它只依赖经纬度,纯JS运行,所有平台都兼容。

常见错误是直接套用平面坐标系的欧氏距离(Math.sqrt((lat1-lat2)**2 + (lng1-lng2)**2)),结果偏差可达几十公里,尤其在高纬度或跨经度区域。

  • Haversine比余弦定理更数值稳定,推荐优先使用
  • 输入单位必须是**弧度**,不是度数,忘记 deg * Math.PI / 180 转换是最高频错误
  • 地球半径取6371008.8米(WGS84平均值),不要硬写6371或6378,影响百米级精度

Haversine公式实现(带单位控制和边界防护)

以下函数返回单位为米的距离,已处理极点、相同点、反向经度等边界情况,可直接复制进uni-app的utils或store:

function getDistance(lat1, lng1, lat2, lng2) {  if (!lat1 || !lng1 || !lat2 || !lng2) return 0;  const R = 6371008.8; // 地球平均半径,单位:米  const toRadians = d => d * Math.PI / 180;  const φ1 = toRadians(lat1);  const φ2 = toRadians(lat2);  const Δφ = toRadians(lat2 - lat1);  const Δλ = toRadians(lng2 - lng1);<p>const a = Math.sin(Δφ/2) <em> Math.sin(Δφ/2) +Math.cos(φ1) </em> Math.cos(φ2) <em>Math.sin(Δλ/2) </em> Math.sin(Δλ/2);const c = 2 <em> Math.atan2(Math.sqrt(a), Math.sqrt(1-a));return R </em> c;}

如需返回公里,最后除以1000;如需保留小数,用 Math.round(distance)distance.toFixed(1),但注意 toFixed 返回字符串。

uni-app地图组件里调用时的坐标来源陷阱

uni-app的 <map> 组件返回的坐标格式不统一:微信小程序 bindregionchangee.detail.centerLocation 是对象 {latitude, longitude};而H5和App端可能从 getCenterLocation 成功回调拿到的是 {latitude: xxx, longitude: xxx} ——看着一样,但实际某些安卓App端老版本会返回 lng/lat 小写键名,甚至顺序颠倒。

  • 务必用解构赋值时加默认值:const { latitude = 0, longitude = 0 } = loc || {}
  • 不要假设 lng 一定存在,有些接口返回 lng,有些返回 longitude,uni-app文档未强制统一
  • 用户授权定位后拿到的 uni.getSystemInfoSync().platform 可用于判断是否需做字段映射,但更稳妥的是统一做键名归一化

性能与精度取舍:什么时候该用简化算法?

如果业务只要“大致远近”(比如附近商家排序、距离分段显示“1km内”“3km外”),且两点纬度差<0.5°,可用简化版:先转为平面近似(墨卡托投影Y轴缩放),再用勾股定理,速度提升约3倍,误差<0.3%。

但一旦涉及导航、计费、地理围栏等对精度敏感的场景,必须用Haversine。另外注意:uni-app的 uni.getLocation 在iOS上默认返回WGS84坐标,而国内地图(高德/腾讯)底图是GCJ-02偏移坐标系,若你拿定位坐标去算和地图标注点(已偏移)的距离,结果会系统性偏差100–700米——这时必须先做WGS84→GCJ-02纠偏,不能跳过。

相关文章

精彩推荐