1. 项目介绍
这是一个基于uniapp框架开发的简单的地图导航小程序,主要实现了获取当前位置、输入目的地、路线规划、导航等功能。用户可以通过该小程序选择起点和终点,获取最优路线,并在导航过程中实时展示行驶路线、距离和时间等信息。
2. 技术实现
2.1 使用uni-app地图组件
uni-app官方提供了uniMap组件,该组件使用高德地图底图,支持多种地图模式和交通情况展示等功能,开发者可以通过调用uniMap组件提供的API实现对地图的控制和使用。
代码如下:
import uniMap from '@/components/uni-map/uni-map.vue';
export default {
components: {
uniMap
},
data() {
return {
markers: [],
polyline: [],
includes: [],
myLocation: {
longitude: '',
latitude: '',
title: '',
iconPath: ''
},
searchInput: '',
destination: {
longitude: '',
latitude: '',
title: '',
iconPath: ''
},
driving: true, //是否驾车模式
showDetail: false //是否显示路线详情
};
}
}
2.2 实现获取用户当前位置
使用uniMap组件提供的`getLocation()`方法可以获取用户的当前位置,需要注意的是,由于获取位置是一个异步操作,在一些平台上可能需要用户授权。
代码如下:
uniMap.getLocation({
type: 'gcj02', //坐标系类型
success: (res) => {
let {longitude, latitude} = res;
this.myLocation.longitude = longitude;
this.myLocation.latitude = latitude;
this.myLocation.iconPath = '/static/location.png';
this.markers = [this.myLocation]; //将当前位置标记点加入到markers数组中
this.includes = [{longitude, latitude, scale: 18}];
},
fail: (err) => {
console.log(err);
}
});
2.3 输入目的地
在页面上使用`uni-input`组件实现输入目的地的功能。获取到用户输入的目的地后,调用高德地图的搜索API,将搜索结果在页面上展示出来。
代码如下:
<view>
<uni-input placeholder="输入目的地" v-model="searchInput" @confirm="searchDestination" @focus='bindfocus'></uni-input>
<view class="searchResult" v-if="searchResult.length">
<view class="searchItem" v-for="(item, index) in searchResult" :key="index" @click="chooseDestination(item)">
<view>{{item.title}}</view>
<view>{{item.address}}</view>
</view>
</view>
</view>
//搜索目的地
async searchDestination() {
if(this.searchInput) {
let res = await uni.cloud.callFunction({
name: 'amap',
data: {
type: 'search',
params: {
keywords: this.searchInput
}
}
});
if(res.result.status === '1') {
let poiList = res.result.pois;
this.searchResult = poiList.map(item => {
return {
title: item.name,
address: item.address,
longitude: item.location.split(',')[0],
latitude: item.location.split(',')[1]
};
});
}
}
},
//选中目的地
chooseDestination(item) {
this.destination = { //将选中的目的地存入destination对象中
longitude: item.longitude,
latitude: item.latitude,
title: item.title,
iconPath: '/static/destination.png'
};
this.markers = [this.myLocation, this.destination];
this.getRoute(); //重新规划路线
}
2.4 路线规划
调用高德地图API进行路线规划,包括驾车、步行和公交三种模式。其中,驾车模式下规划路线时需要指定起点、终点和途经点,而步行和公交模式下只需要指定起点和终点即可。
代码如下:
//驾车路线规划
async getDriveRoute() {
if(this.destination.longitude && this.myLocation.longitude) {
let res = await uni.cloud.callFunction({
name: 'amap',
data: {
type: 'driveRoute',
params: {
origin: `${this.myLocation.longitude},${this.myLocation.latitude}`,
destination: `${this.destination.longitude},${this.destination.latitude}`,
waypoints: '',
driving: '1',
extensions: 'all'
}
}
});
if(res.result.status === '1') {
let {paths, recommend, taxi_cost, distance, duration} = res.result.route;
this.showDetail = true; //显示路线详情
this.driving = true;
this.duration = duration;
this.distance = distance;
this.routeList = paths[0].steps.map(item => {
return {
instruction: item.instruction,
orientation: item.orientation,
road: item.road,
distance: item.distance,
tolls: item.tolls,
tollDistance: item.tollDistance,
time: item.time
}
});
let points = paths[0].steps.reduce((prev, curr) => prev.concat(curr.path), []);
this.polyline = [{
points,
color: '#0091ff',
width: 6,
arrowLine: true
}];
}
}
},
//步行路线规划
async getWalkRoute() {
if(this.destination.longitude && this.myLocation.longitude) {
let res = await uni.cloud.callFunction({
name: 'amap',
data: {
type: 'Walking',
params: {
origin: `${this.myLocation.longitude},${this.myLocation.latitude}`,
destination: `${this.destination.longitude},${this.destination.latitude}`
}
}
});
if(res.result.status === '1') {
let {paths, distance, duration} = res.result.route;
this.showDetail = true;
this.driving = false;
this.duration = duration;
this.distance = distance;
this.routeList = paths[0].steps.map(item => {
return {
instruction: item.instruction,
orientation: item.orientation,
road: item.road,
distance: item.distance,
tolls: item.tolls,
tollDistance: item.tollDistance,
time: item.time
}
});
let points = paths[0].steps.reduce((prev, curr) => prev.concat(curr.path), []);
this.polyline = [{
points,
color: '#0091ff',
width: 6,
arrowLine: true
}];
}
}
},
//公交路线规划
async getTransitRoute() {
if(this.destination.longitude && this.myLocation.longitude) {
let res = await uni.cloud.callFunction({
name: 'amap',
data: {
type: 'Transit',
params: {
origin: `${this.myLocation.longitude},${this.myLocation.latitude}`,
destination: `${this.destination.longitude},${this.destination.latitude}`,
city: '',
cityd: '',
strategy: '0'
}
}
});
if(res.result.status === '1') {
let {transits, distance, duration} = res.result.route;
this.showDetail = true;
this.driving = false;
this.duration = duration;
this.distance = distance;
let route = transits[0].segments.reduce((prev, curr) => {
if(curr.bus && curr.bus.buslines.length) {
let busline = curr.bus.buslines[0];
return prev.concat({
instruction: curr.instruction,
busName: busline.name,
departureStop: curr.bus.departure_stop.name,
arrivalStop: curr.bus.arrival_stop.name,
distance: busline.distance,
duration: busline.duration,
startTime: busline.start_time,
endTime: busline.end_time,
walkDistance: busline.walk_distance
});
} else if(curr.railway && curr.railway.viastops.length) {
return prev.concat({
instruction: curr.instruction,
railwayName: curr.railway.name,
departureStop: curr.railway.departure_stop.name,
arrivalStop: curr.railway.arrival_stop.name,
distance: curr.railway.distance,
duration: curr.railway.duration
});
} else {
return prev;
}
}, []);
this.routeList = route;
let points = transits[0].segments.reduce((prev, curr) => {
if(curr.walk && curr.walk.steps.length) {
return prev.concat(curr.walk.steps.reduce((prev, curr) => prev.concat(curr.path), []));
} else if(curr.bus && curr.bus.buslines.length) {
return prev.concat(curr.bus.buslines[0].path);
} else if(curr.railway && curr.railway.viastops.length) {
return prev.concat(curr.railway.viastops.map(item => item.location));
} else {
return prev;
}
}, []);
this.polyline = [{
points,
color: '#0091ff',
width: 6,
arrowLine: true
}];
}
}
},
//根据路线类型调用路线规划API
getRoute() {
if(this.driving) {
this.getDriveRoute();
} else {
this.getWalkRoute();
}
}
2.5 导航功能
在路线规划之后,可以通过调用`navigateTo()`方法跳转到高德地图进行导航。需要注意的是,navigateTo()只支持跳转到第三方小程序,需要在manifest.json中添加相应的app id,并在App.vue中注册此app ID即可。
代码如下:
//跳转到导航页面
navigateTo() {
let url = `appid=高德地图appid&name=${this.destination.title}&lat=${this.destination.latitude}&lon=${this.destination.longitude}&dev=0`;
uni.navigateToMiniProgram({
appId: '第三方小程序appid',
path: `pages/navigation/navigation?${encodeURIComponent(url)}`
});
}
3. 实现效果
本项目展示了使用uni-app框架开发地图导航小程序的基本流程,包括获取当前位置、输入目的地、路线规划和导航等功能。用户可以通过小程序选择起点和终点,获取最优路线,并在导航过程中实时展示行驶路线、距离和时间等信息。
项目地址:https://github.com/zhangtianli2006/uniapp-map-navigation
参考资料:
uni-map文档:https://uniapp.dcloud.io/component/uni-map
高德地图API文档:https://lbs.amap.com/api/webservice/guide/api/