前言

本文旨在以mpvue框架为根底,探讨地图类小程序的开发思路。 原作者利用mpvue + 腾讯地图的能力做了一个地铁路线布局的小程序,次要提供寰球次要城市的地铁线网图及游览介绍,其中国内城市反对查看地图和路线布局。

目前腾讯位置服务也推出了路线布局插件、地铁图插件,实现更加简略便捷,感兴趣的可点击查看。

运行截图

mpvue 介绍 及我的项目搭建

mpvue = miniprogram + vue framework,说白了就是用vue框架开发小程序。mpvue最近降级为2.x版本,反对微信、支付宝、百度和头条小程序。和传统形式相比,mpvue开发具备以下长处:

彻底的组件化开发能力:进步代码复用性

  • 残缺的 Vue.js 开发体验
  • 不便的 Vuex 数据管理计划:不便构建简单利用
  • 快捷的 webpack 构建机制:自定义构建策略、开发阶段 hotReload
  • 反对应用 npm 内部依赖
  • 应用 Vue.js 命令行工具 vue-cli 疾速初始化我的项目
  • H5 代码转换编译成小程序指标代码的能力

就集体应用体验来看,还是挺丝滑顺畅的,传统web利用开发无缝切换至小程序开发,根本零门槛。要留神的就是小程序的限度及和vue的差别:

  • 小程序应用绝对像素 rpx 进行款式布局
  • 局部css选择符不反对,目前只反对 #id | .class | tag | tag,tag | ::after ::before,所以要特地留神
  • 组合式生命周期,mpvue将小程序和vue的生命周期混在一块,详情见 mpvue.com/mpvue/#_3 ,目前这个中央还有很多坑,比方在小程序page unload时,vue实例却没被销毁,导致下次进入页面时,页面状态不变,必须在unLoad时手动重置状态等
  • mpvue 会封装小程序数据对象,通常以$mp结尾,如event.$mp.detail.target
  • 小程序的组件和vue组件有差别,不要空想vue组件的个性都能用,如slot,异步组件等等
  • vue store 和 wx localstorage 最好不要弄混,要依据不同须要抉择不同的存储形式
  • 不要用vue路由,要采纳小程序原生的导航机制

而后,咱们搭建开发环境,mpvue脚手架是开箱即用的:

# 全局装置 vue-cli# 个别是要 sudo 权限的$ npm install --global vue-cli@2.9# 创立一个基于 mpvue-quickstart 模板的新我的项目# 老手一路回车抉择默认就能够了$ vue init mpvue/mpvue-quickstart my-project# 装置依赖,走你$ cd my-project$ npm install$ npm run dev

接着,欠缺文件构造,减少 config、store、mixins等模块,如图:

app.json是小程序专用文件,也需欠缺下:

{  "pages": [    "pages/citylist/main",    "pages/citydetail/main"  ],  "permission": {    "scope.userLocation": {      "desc": "你的地位信息将用于小程序地位接口的成果展现"    }  },  "window": {    "backgroundTextStyle": "light",    "navigationBarBackgroundColor": "#eee",    "navigationBarTitleText": "寰球地铁,全程为你",    "navigationBarTextStyle": "black"  }}

而后就能够欢快的写Vue代码了,咔咔一个页面,咔咔又是一个页面,组件,store,数据驱动,你喜爱的样子,它都有。

腾讯地图+ 小程序

着重说一下地图的接入,腾讯地图提供了两个对接入口给小程序,1是个性化地图展现,2是专用SDK,二者独特欠缺了小程序的地图生态。

1、共性地图展现须要开发者自行注册并申请开发者密钥(key),并在治理后盾绑定小程序,而后设置共性地图的款式,能力应用:

<map  id="citymap"  name="citymap"  :longitude="lng"  :latitude="lat"  :polyline="polyline"    :markers="markers"  scale="12"  :subkey="YOUR_OWN_QQMAP_KEY"  show-location  show-compass  enable-rotate  style="width: 100%; height: 100%;">  <cover-view class="map-cover-view">    <button class="explore-btn" type="primary" @tap="exploreCity">查看游览攻略</button>  </cover-view></map>

其中,map是小程序的原生组件,原生组件脱离在 WebView 渲染流程外,它的层级是最高的,所以页面中的其余组件无论设置 z-index 为多少,都无奈盖在原生组件上。说白了就是原生组件是微信客户端提供的,它不属于内置浏览器,为此,小程序专门提供了 cover-view 和 cover-image 组件,能够笼罩在局部原生组件下面。这两个组件也是原生组件,然而应用限度与其余原生组件有所不同。

笔者就因为这个坑耽搁了不少工夫,有时候开发工具能够用,但到了真机上组件就齐全乱了,所以还是要以真机调试为准。对于原生组件,不要用太简单的css,它的很多css属性反对的都不好。

map能够定义多个参数,经纬度不用说,scale指放缩比例,也就是地图比例尺,polyline在地图上绘制折线,markers用于标记地图上的点,show-location用于显示用户所在位置,show-compass显示指北针。

2、专用SDK,目前提供这些能力:

  • search(options:Object) 地点搜寻,搜寻周边poi,比方:“酒店” “餐饮” “娱乐” “学校” 等等
  • getSuggestion(options:Object) 用于获取输出关键字的补完与提醒,帮忙用户疾速输出
  • reverseGeocoder(options:Object) 提供由坐标到坐标所在位置的文字描述的转换。输出坐标返回地理位置信息和左近poi列表
  • geocoder(options:Object) 提供由地址形容到所述地位坐标的转换,与逆地址解析的过程正好相同
  • direction(options:Object) 提供驾车,步行,骑行,公交的路线布局能力
  • getCityList() 获取全国城市列表数据
  • getDistrictByCityId(options:Object) 通过城市ID返回城市下的区县
  • calculateDistance(options:Object) 计算一个点到多点的步行、驾车间隔

咱们以公共交通路线布局为例来看下(以下代码通过简化解决):

第一步,初始化地图SDK对象

import config from '@/config'import QQMapWX from '../../assets/lib/qqmap-wx-jssdk.js' // 这里用未压缩版的代码const QQMapSDK = new QQMapWX({  key: config.qqMapKey || ''})

第二步,获取起止坐标点,并进行路线查问

// 坐标从上一页query传进来,坐标为浮点数,可通过geocoder接口获取this.fromLocation = {  latitude: +query.from.split(',')[0] || -1,  longitude: +query.from.split(',')[1] || -1}this.toLocation = {  latitude: +query.to.split(',')[0] || -1,  longitude: +query.to.split(',')[1] || -1}// 查问地图路线queryMapRoutine() {  QQMapSDK.direction({    mode: 'transit', // 'transit'(公交路线布局)    // from参数不填默认以后地址    from: this.fromLocation,    to: this.toLocation,    success: (res) => {      console.log('路线布局后果', res);      let routes = res.result.routes;      this.routes = routes.map(r => {                // 对每一种路线计划,别离进行解析        return this.parseRoute(r)      })      console.log('parsed routes', this.routes)    }  })}

第三步,路线解析,生成路线形容等

// 解析路线,包含间隔,工夫,形容,路线,起止点等parseRoute(route) {    let result = {}    // 登程工夫  result.setOutTime = formatTime(new Date())  result.distance = route.distance < 1000 ?                    `${route.distance}米` :                    `${(route.distance / 1000).toFixed(2)}公里`  result.duration = route.duration < 60 ?                    `${route.duration}分钟` :                    `${parseInt(route.duration / 60)}小时${route.duration % 60}分钟`    result.desc = []    // 每一个路线分很多步,如先步行,后乘公交,再搭地铁等  route.steps.forEach(step => {    // if (step.mode == 'WALKING' && step.distance > 0) {    //   result.desc.push(`向${step.direction}步行${step.distance}米`)    // }    if (step.mode == 'TRANSIT' && step.lines[0]) {      let line = step.lines[0]      if (line.vehicle == 'BUS') line.title = `公交车-${line.title}`      if (line.vehicle == 'RAIL') line.title = `铁路`      result.desc.push(`${line.title}: ${line.geton.title} —> ${line.getoff.title},途经 ${line.station_count} 站。`)    }  })  result.polyline = []  result.points = []  //获取各个步骤的polyline,也就是路线图  for(let i = 0; i < route.steps.length; i++) {    let step = route.steps[i]    let polyline = this.getStepPolyline(step)    if (polyline) {      result.points = result.points.concat(polyline.points)      result.polyline.push(polyline)    }    }    // 标记路线整体显示坐标  this.getStepPolyline.colorIndex = 0  let midPointIndex = Math.floor(result.points.length / 2)  result.latitude = result.points[midPointIndex].latitude  result.longitude = result.points[midPointIndex].longitude  // 标记路线起止点  let startPoint = result.points[0]  let endPoint = result.points[result.points.length - 1]  result.markers = [    {      iconPath: this.startIcon,      id: 0,      latitude: startPoint.latitude,      longitude: startPoint.longitude,      width: 28,      height: 28,      zIndex: -1,      anchor: {x: 0.5, y: 1}    },    {      iconPath: this.endIcon,      id: 1,      latitude: endPoint.latitude,      longitude: endPoint.longitude,      width: 28,      height: 28,      zIndex: -1,      anchor: {x: 0.5, y: 1}    }  ]  return result},

第四步,getStepPolyline函数 获取路线每一步的路线polyline

getStepPolyline(step) {    let coors = [];    // 随机色彩  let colorArr = ['#1aad19', '#10aeff', '#d84e43']  let _dottedLine = true  if (step.mode == 'WALKING' && step.polyline) {    coors.push(step.polyline);    _dottedLine = false  } else if (step.mode == 'TRANSIT' && step.lines[0].polyline) {    coors.push(step.lines[0].polyline);  } else {    return null  }  //坐标解压(返回的点串坐标,通过前向差分进行压缩)  let kr = 1000000;  for (let i = 0 ; i < coors.length; i++){    for (let j = 2; j < coors[i].length; j++) {      coors[i][j] = Number(coors[i][j - 2]) + Number(coors[i][j]) / kr;    }  }  //定义新数组,将coors中的数组合并为一个数组  let coorsArr = [];  let _points = [];  for (let i = 0 ; i < coors.length; i ++){    coorsArr = coorsArr.concat(coors[i]);  }  //将解压后的坐标放入点串数组_points中  for (let i = 0; i < coorsArr.length; i += 2) {    _points.push({ latitude: coorsArr[i], longitude: coorsArr[i + 1] })  }  if (!this.getStepPolyline.colorIndex) {    this.getStepPolyline.colorIndex = 0  }  let colorIndex = this.getStepPolyline.colorIndex % colorArr.length    this.getStepPolyline.colorIndex++    // 最终polyline后果  let polyline = {    width: 7,    points: _points,    color: colorArr[colorIndex],    dottedLine: _dottedLine,    arrowLine: true, // 带箭头的线, 开发者工具暂不反对该属性    borderColor: '#fff',    borderWidth: 1  }  return polyline}

最初,绑定到地图上并输入,咱们能够失去一个大抵这样的后果:

广州火车站 -> 广州塔9.88km 30分钟地铁5号线 广州火车站 -> 珠江新城,路径7站地铁3号线 珠江新城 -> 广州塔,路径1站

这样咱们就通过direction接口进行了简略的路线布局性能,接着把生成的数据绑定到地图组件上,一个繁难的小程序就做好了,是不是很简略?当然如果想做得更好,就要调用其余类似接口,缓缓欠缺细节。

<map  id="citymap"  name="citymap"  :latitude="currentRoute.latitude"  :longitude="currentRoute.longitude"  :polyline="currentRoute.polyline"  :markers="currentRoute.markers"  scale="12"  :subkey="qqMapKey"  show-location  show-compass  enable-rotate  style="width: 100%; height: 100%;"></map>

成果

作者:棱镜_jh

链接:https://juejin.cn/post/684490...

起源:掘金

著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。