uni-app地图开发:经纬度计算两点距离

作者:技术拾光

时间:2026-06-04

浏览:314

在uni-app里做地图开发,计算两点距离是个高频需求。很多开发者第一反应是去调百度或高德SDK的distance方法,觉得省事。但实际操作过就知道,这条路在uni-app的多端环境下,坑远比想象的多。 微信小程序根本不支持这些地图JS API的Web版;H5端虽然能引入,但面临鉴权和跨域问题;Ap

文章目录

在uni-app里做地图开发,计算两点距离是个高频需求。很多开发者第一反应是去调百度或高德SDK的distance方法,觉得省事。但实际操作过就知道,这条路在uni-app的多端环境下,坑远比想象的多。

微信小程序根本不支持这些地图JS API的Web版;H5端虽然能引入,但面临鉴权和跨域问题;App端又得折腾原生桥接。一圈下来你会发现,最稳定、最通用、零依赖的方案,反而是自己动手,用纯Ja vaScript实现一个球面距离计算。

uni-app地图开发:经纬度计算两点距离

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

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

这里最常见的错误,是下意识地套用平面坐标系的欧氏距离公式,也就是Math.sqrt((lat1-lat2)**2 + (lng1-lng2)**2)。地球是球体,这么算出来的结果,偏差随随便便就能达到几十公里,在高纬度地区或者跨经度计算时尤其离谱。

  • 公式选择:Ha versine公式在数值计算上比传统的球面余弦定理更稳定,推荐优先使用。
  • 单位陷阱:输入的单位必须是**弧度**,而不是我们常见的度数。忘记做deg * Math.PI / 180转换,是最高频的错误。
  • 半径取值:地球半径取6371008.8米(这是WGS84椭球体的平均半径)。别图省事硬写成6371或6378,这会影响百米级别的精度。

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

下面这个函数可以直接复制到你的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);
  const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
            Math.cos(φ1) * Math.cos(φ2) *
            Math.sin(Δλ/2) * Math.sin(Δλ/2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  return R * c;
}

如果需要返回公里数,最后把结果除以1000就行。如果想保留小数,可以用Math.round(distance)四舍五入取整,或者用distance.toFixed(1)保留一位小数,不过要注意toFixed方法返回的是字符串。

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

公式写好了,数据源也得小心。uni-app的组件在不同平台返回的坐标格式并不统一,这里藏着不少坑。

比如,微信小程序里bindregionchange事件返回的e.detail.centerLocation是一个标准的{latitude, longitude}对象。但在H5和App端,通过getCenterLocation方法拿到的数据结构,虽然看起来也是{latitude: xxx, longitude: xxx},但某些安卓App的老版本可能会返回小写的lng/lat键名,甚至经纬度顺序都是反的。

  • 解构赋值加默认值:务必使用const { latitude = 0, longitude = 0 } = loc || {}这样的写法,防止undefined报错。
  • 不要假设键名:别想当然地认为一定是longitude,有些接口返回的是lng,uni-app的文档并没有强制统一这个字段名。
  • 统一归一化:最稳妥的做法,是在调用计算函数前,先对坐标对象做一次键名归一化处理,确保传给getDistance的一定是lat和lng(或latitude和longitude)。

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

Ha versine公式虽然精确,但计算涉及三角函数,如果列表中有大量点位需要实时计算排序,对性能确实有要求。这时候就需要权衡了。

如果你的业务只是需要“大致远近”——比如给附近的商家排个序,或者分段显示“1km内”、“3km外”这样的标签,并且两点之间的纬度差小于0.5°,那么可以考虑使用简化版算法。思路是先做墨卡托投影近似,将球面坐标转为平面坐标,再用勾股定理计算。这种方法速度能提升约3倍,而误差可以控制在0.3%以内。

但是,一旦涉及到导航、精确计费、地理围栏触发等对精度敏感的场景,就必须老老实实用Ha versine公式。另外还有一个至关重要的点:uni-app的uni.getLocation在iOS设备上默认返回的是WGS84坐标系(GPS原始坐标),而国内的高德、腾讯等地图底图使用的是GCJ-02坐标系(火星坐标)。如果你直接用获取的定位坐标,去计算与地图上已偏移的标注点之间的距离,结果会产生100到700米不等的系统性偏差。在这种情况下,计算距离前,必须先将WGS84坐标转换为GCJ-02坐标,这一步纠偏绝对不能跳过。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章