能实现不依赖后端的附近门店列表:先由用户交互触发 navigator.geolocation.getcurrentposition 获取经纬度,再用 haversine 公式计算各门店距离并排序渲染,注意错误处理、粗筛优化和安全 dom 操作。

直接用浏览器地理定位 + 前端计算距离,就能做出不依赖后端的附近门店列表——但要注意,navigator.geolocation 获取的是经纬度,而“距离”必须用球面公式(比如 Haversine),不能简单用勾股定理。
怎么拿到用户当前位置
调用 navigator.geolocation.getCurrentPosition() 是唯一标准方式,但它异步、可能失败、且需用户授权。别写成同步等待,也别在未触发用户交互前就调用(Chrome 会静默拒绝)。
- 必须由用户点击按钮等交互事件触发,例如:
document.getElementById('get-location').addEventListener('click', () => { navigator.geolocation.getCurrentPosition(...); }); - 一定要传
error回调,常见错误包括:GeolocationError: User denied geolocation、GeolocationError: Position unavailable、GeolocationError: Timeout expired - 建议加
enableHighAccuracy: true(但不保证生效),并设timeout: 10000防止卡死
怎么算门店和用户的直线距离
所有门店数据得提前以数组形式存在前端(JSON 或内联 JS),每项至少含 lat 和 lng。距离计算用 Haversine 公式,不是 Math.sqrt(dx*dx + dy*dy)——后者在经纬度上误差极大(尤其跨纬度)。
- 推荐直接用这个轻量函数(单位:公里):
function haversineDistance(lat1, lng1, lat2, lng2) {
const R = 6371;
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);
return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
}
- 输入单位必须是十进制度数(不是度分秒),且
lat范围 -90~90,lng范围 -180~180 - 如果门店超 50 家,排序前先用
Array.prototype.filter()粗筛(比如先剔除纬度差 > 2° 的),避免全量计算拖慢渲染
怎么按距离排序并渲染到页面
DOM 渲染别用字符串拼接 + innerHTML,尤其要支持反复刷新位置时。用 document.createElement 或模板字符串配合 textContent 更安全,也方便后续加点击跳转地图等功能。
- 排序逻辑示例:
stores.sort((a, b) => haversineDistance(userLat, userLng, a.lat, a.lng) - haversineDistance(userLat, userLng, b.lat, b.lng)) - 渲染时给每个门店项加
data-distance属性(如data-distance="0.83"),方便 CSS 控制(比如距离 - 注意小数精度:显示时用
distance.toFixed(1),但计算排序别四舍五入,否则 0.99km 和 1.01km 可能排反 - 别忘了加载状态提示(比如 “定位中…”)和空态(“暂无门店” 或 “未开启定位”)
真正麻烦的不是计算,而是定位失败后的降级方案——比如 fallback 到城市名关键词搜索,或让用户手动选城市;还有 iOS Safari 对后台定位的限制,切到其他标签页后 watchPosition 可能停摆。这些没法靠一段 JS 解决,得结合业务兜底。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











