小程序地图导航,怎样实现用户体验更好
最近在开发一个小程序的项目, 接触到了地图导航这一块, 然后就对其进行了深入了解,然后在此分享一下我的收获和心得
1. 使用小程序API直接实现
代码实现起来比较简单,实现的目标效果也可以满足我们需求
实现代码(wx.openLocation):
wx.openLocation({latitude: 23.132345, // 商家纬度longitude: 113.324567, // 商家经度name: '星巴克(天河店)', // 商家名称address: '广东省广州市天河区天河路123号', // 商家地址scale: 15 // 地图缩放级别,范围5-18
});当你调用这个小程序的API时, 就会出现这样一个地图画面(微信开发者工具上的效果), 通过点击去这里就可以调用手机上的地图APP了, 这样就可以实现实时导航,良好的用户体验。

这个和美团上的实现效果比较相似, 不管用户去选择哪个地图去进行导航,都可以达到其目标


2.2 腾讯地图SDK集成
申请腾讯地图Key
1. 访问腾讯位置服务:https://lbs.qq.com/
2. 注册并登录
3. 进入控制台 → 应用管理 → 创建应用
4. 添加Key,选择类型:**WebServiceAPI**
5. 复制Key备用
安装SDK(方式一:npm)
npm install @tmap/map-wx --save实现路径规划功能
<!-- pages/Navigation/RoutePreview.vue -->
<template><view class="route-preview"><!-- 地图容器 --><mapid="route-map"class="map":latitude="centerLat":longitude="centerLng":scale="14":markers="markers":polyline="polylines":show-location="true"><!-- 路线信息悬浮卡片 --><cover-view class="route-info-card"><cover-view class="info-row"><cover-image src="/images/icon-distance.png" class="icon" /><cover-view class="text">距离: {{ routeInfo.distance }}</cover-view></cover-view><cover-view class="info-row"><cover-image src="/images/icon-time.png" class="icon" /><cover-view class="text">预计: {{ routeInfo.duration }}</cover-view></cover-view></cover-view><!-- 开始导航按钮 --><cover-view class="start-nav-btn" @tap="startNavigation"><cover-view class="btn-text">开始导航</cover-view></cover-view></map><!-- 底部路线详情 --><view class="route-detail"><view class="detail-header"><text class="title">路线详情</text><text class="sub">{{ routeInfo.steps.length }}个路段</text></view><scroll-view class="steps-list" scroll-y><viewv-for="(step, index) in routeInfo.steps":key="index"class="step-item"><view class="step-index">{{ index + 1 }}</view><view class="step-content"><text class="instruction">{{ step.instruction }}</text><text class="distance">{{ step.distance }}米</text></view></view></scroll-view></view></view>
</template><script setup lang="ts">
import { ref, onMounted, computed } from 'vue';
import qqmapsdk from '@/utils/qqmap';// 商家信息
const merchant = ref({name: '星巴克(天河店)',address: '广东省广州市天河区天河路123号',latitude: 23.132345,longitude: 113.324567
});// 用户当前位置
const userLocation = ref({latitude: 0,longitude: 0
});// 地图中心点
const centerLat = computed(() => {return (userLocation.value.latitude + merchant.value.latitude) / 2;
});const centerLng = computed(() => {return (userLocation.value.longitude + merchant.value.longitude) / 2;
});// 地图标记点
const markers = ref([{id: 1,latitude: 0,longitude: 0,iconPath: '/images/marker-start.png', // 起点图标width: 30,height: 40,callout: {content: '我的位置',display: 'ALWAYS'}},{id: 2,latitude: merchant.value.latitude,longitude: merchant.value.longitude,iconPath: '/images/marker-end.png', // 终点图标width: 30,height: 40,callout: {content: merchant.value.name,display: 'ALWAYS'}}
]);// 路径折线
const polylines = ref([]);// 路线信息
const routeInfo = ref({distance: '0km',duration: '0分钟',steps: []
});onMounted(() => {getUserLocation();
});// 获取用户位置
function getUserLocation() {wx.getLocation({type: 'gcj02',success: (res) => {userLocation.value = {latitude: res.latitude,longitude: res.longitude};// 更新起点标记markers.value[0].latitude = res.latitude;markers.value[0].longitude = res.longitude;// 规划路线planRoute();},fail: () => {wx.showToast({title: '请授权位置信息',icon: 'none'});}});
}// 规划路线(调用腾讯地图API)
function planRoute() {wx.showLoading({ title: '规划路线中...' });qqmapsdk.direction({mode: 'walking', // 步行导航(可选:driving、bicycling、transit)from: {latitude: userLocation.value.latitude,longitude: userLocation.value.longitude},to: {latitude: merchant.value.latitude,longitude: merchant.value.longitude},success: (res) => {wx.hideLoading();const route = res.result.routes[0];// 路线信息routeInfo.value = {distance: (route.distance / 1000).toFixed(2) + 'km',duration: Math.ceil(route.duration / 60) + '分钟',steps: route.steps.map(step => ({instruction: step.instruction,distance: step.distance}))};// 绘制路线drawPolyline(route.polyline);},fail: (error) => {wx.hideLoading();console.error('路线规划失败:', error);wx.showToast({title: '路线规划失败',icon: 'none'});}});
}// 绘制路径折线
function drawPolyline(coords) {const points = coords.map(coord => ({latitude: coord.lat,longitude: coord.lng}));polylines.value = [{points: points,color: '#1890ff',width: 6,borderColor: '#ffffff',borderWidth: 2,arrowLine: true, // 显示箭头arrowIconPath: '/images/icon-arrow.png'}];
}// 开始导航
function startNavigation() {wx.openLocation({latitude: merchant.value.latitude,longitude: merchant.value.longitude,name: merchant.value.name,address: merchant.value.address,scale: 15});
}
</script><style scoped lang="scss">
.route-preview {width: 100%;height: 100vh;display: flex;flex-direction: column;
}.map {flex: 1;width: 100%;
}.route-info-card {position: absolute;top: 30rpx;left: 30rpx;right: 30rpx;background: rgba(255, 255, 255, 0.95);border-radius: 16rpx;padding: 24rpx;box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);.info-row {display: flex;align-items: center;margin-bottom: 16rpx;&:last-child {margin-bottom: 0;}.icon {width: 32rpx;height: 32rpx;margin-right: 16rpx;}.text {font-size: 28rpx;color: #333;font-weight: 500;}}
}.start-nav-btn {position: absolute;right: 30rpx;bottom: 30rpx;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);padding: 24rpx 48rpx;border-radius: 48rpx;box-shadow: 0 8rpx 16rpx rgba(102, 126, 234, 0.4);.btn-text {font-size: 32rpx;color: #fff;font-weight: 600;}
}.route-detail {height: 400rpx;background: #fff;border-top: 1px solid #f0f0f0;.detail-header {padding: 30rpx;border-bottom: 1px solid #f0f0f0;.title {font-size: 32rpx;font-weight: 600;color: #333;margin-right: 16rpx;}.sub {font-size: 24rpx;color: #999;}}.steps-list {height: calc(400rpx - 90rpx);padding: 0 30rpx;}.step-item {display: flex;align-items: flex-start;padding: 24rpx 0;border-bottom: 1px solid #f5f5f5;.step-index {width: 48rpx;height: 48rpx;background: #1890ff;border-radius: 50%;display: flex;align-items: center;justify-content: center;color: #fff;font-size: 24rpx;font-weight: 600;flex-shrink: 0;margin-right: 20rpx;}.step-content {flex: 1;.instruction {display: block;font-size: 28rpx;color: #333;line-height: 1.6;margin-bottom: 8rpx;}.distance {display: block;font-size: 24rpx;color: #999;}}}
}
</style>