小程序开发日记⑦:服务范围、收货地址与地图选点

无人机并不是“哪里都能送”。用户下单前需要知道服务覆盖到哪里,填写地址时又需要把文字地点落到真实坐标。本篇包含服务范围和地图选点两部分。
1. 服务范围数据
pages/common/service-range.vue 从配置接口获取中心纬度、经度和半径。接口不可用时页面显示“程序未配置”,开发环境可以保留默认中心用于布局,但不能把默认值当真实范围。
function applyServiceArea(area) { latitude.value = area.latitude longitude.value = area.longitude serviceRadius.value = area.radius mapScale.value = getScaleByRadius(area.radius, area.latitude) mapReady.value = true}地图的 circles 属性绘制服务区域:
const circles = computed(() => [{ latitude: latitude.value, longitude: longitude.value, radius: serviceRadius.value, color: '#1769e8', fillColor: '#1769e833', strokeWidth: 3}])2. 根据半径计算缩放级别
固定 scale 会让小范围太空、大范围被裁掉。页面根据半径估算目标米/像素,再换算缩放级别:
function getScaleByRadius(radius, lat) { const targetMetersPerPixel = Math.max(1, (radius * 2) / (390 * 0.72)) const cosLat = Math.max(0.2, Math.cos(Number(lat) * Math.PI / 180)) const scale = Math.log2((156543.03392 * cosLat) / targetMetersPerPixel) return Math.max(5, Math.min(16, Math.round(scale)))}纬度会影响同一缩放级别下的地面分辨率,因此计算中保留 cos(lat) 修正。
3. 地图选点页面
pages/common/location-picker.vue 支持当前位置、地点搜索、拖动地图中心和候选地址列表。地图中间的选点图标是固定在容器中心的视觉指示,真正坐标在 regionchange 结束时通过地图上下文解析。
用户拖动地图 ↓regionchange end ↓读取地图中心经纬度 ↓逆地理编码获得地址 ↓更新候选地点与选中项拖动过程中不应连续逆地理编码,否则一次手势会产生大量请求。页面通过序号和短延迟,只处理最后一次中心点变化。
4. 候选地点模型
无论候选数据来自搜索、当前位置还是地图中心,都统一转换为:
{ id, title, subtitle, fullAreaName, detailedAddress, regionId, latitude, longitude}统一模型使列表选择和地图选择最终都调用 recipient.setSelectedAddress(place),不用为每种来源写一套回填逻辑。
5. 确认前再次检查服务范围
选择一个地点不代表它一定可配送。确认按钮拿到坐标后调用服务范围判断,超出范围则保留页面并给出提示。校验要在最终坐标确定后执行,而不是只在搜索结果返回时判断,因为用户还可能继续拖动地图。
6. 原生地图与覆盖层
小程序 map 是原生组件,层级和普通 DOM 不完全相同。地图上的 marker、polyline、circle 尽量使用组件原生属性;普通说明卡片放在地图外层。需要覆盖地图的按钮要控制层级,并在真机环境关注 cover-view 兼容性。
7. 定位权限与降级
“定位到我”使用 GCJ-02 坐标。用户拒绝位置权限时不阻断页面,仍可搜索或拖动地图选择;页面只提示检查权限。定位是快捷方式,不应成为唯一入口。
8. 本篇小结
范围判断的计算
圆形服务区可以使用 Haversine 公式计算选点到中心的球面距离,再和半径比较。页面显示的圆与提交校验必须使用同一组中心和半径,不能一个来自默认配置、另一个来自接口。
const inRange = distanceMeters(point, serviceCenter) <= serviceRadius靠近边界时要考虑 GPS 精度和业务容差,页面可以显示“接近服务边界,请确认”,最终是否允许下单由后端再次判断。前端范围校验用于即时反馈,不能替代服务端规则。
逆地理编码结果中的省市区 ID、完整地区名和 POI 文本分别保存,避免把一整串可读地址错误地当成行政区字段提交。
文字地址让人知道去哪儿,经纬度让程序知道画在哪儿,服务半径则负责说“能不能去”。三者对齐以后,下单地址才不再是一句模糊的地名,而是地图上一个可以被验证的点。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!





























