利用uniapp开发一个简单的地图导航

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/