微信小程序—制作一个简单的跑步小程序

2,616 阅读4分钟

我正在参加「掘金·启航计划」

准备工作

1.微信公众平台注册一个小程序账号,注册完之后左边菜单列表点击开发管理->开发设置,就可以看到自己的appid(小程序id)了

image.png

2.官网安装微信开发者工具

image.png

创建项目

1.创建小程序项目

打开微信开发者工具选择创建小程序,输入项目名称,目录自定义,将appid复制进AppID里,点击创建

image.png

2.初始化小程序项目

这是新创建好的小程序目录,里面非常多文件是不需要的,我们要删除多余的文件

image.png

这是删除好的文件目录,可以看到简洁很多了

image.png

pages文件夹是存放页面的文件夹,右击新建index文件夹,再右击新建Page自动创建js,json,wxml,wxss文件

  • .js 里面编写一些生命周期钩子,事件处理,全局数据…
  • .json 里面编写一些页面配置,页面的 .json 配置会覆盖 app.json 的配置
  • .wxml 里面编写一些页面内容,UI标签,数据绑定
  • .wxss 里面编写一些样式

json文件里添加navigationBarTitleText设置导航栏标题

image.png

导入一张红色圆点的图片用作跑步时的定位标记

hd.png

开始编写

1.wxml

创建四个按钮分别用作开始记录/暂停记录,清除数据,保存数据,回放,并创建对应的方法

<view class="header">
  <button type="primary" size="mini" bindtap="run">{{running?'暂停记录':'开始记录'}}</button>
  <button type="warn" size="mini" bindtap="clear">清除数据</button>
  <button type="default" size="mini" bindtap="save">保存数据</button>
  <button type="primary" size="mini" bindtap="translateMarker">回放</button>
</view>

创建text标签用作记录里程和时间

<view class="counter">
  <text>里程:{{mdl.formatKM(meters)}} 时间: {{mdl.formatTime(seconds)}}</text>
</view>

使用小程序官方内置的map地图组件,里面有好几十个属性,但我们具体只使用一下几个属性:

  • latitude:number类型,中心纬度
  • longitude:number类型,中心经度
  • markers:array类型,标记点
  • polyline:array类型,路线
<map id="map" class="map" latitude="{{latitude}}" longitude="{{longitude}}" markers="{{markers}}" polyline="{{polyline}}" />

2.wxss

.header{
  display: flex;
}
.counter{
  text-align: center;
}
.map{
  width: 100%;
  height: 90vh;
}

3.js

js文件为我们创建好了一些生命周期函数,但是看起来太乱了

image.png

直接ctrl+a全选删除,再把page添加回去,dada里初始一些数据

Page({
  data:{
    meters:0,//里程
    seconds:0,//时间
    latitude:0,//纬度
    longitude:0,//经度
    running:false,//是否开始
    interval:1000,//多少秒获取当前定位
    markers:[],//标记
    polyline:[],//路线
    point:[],//标注
    i:0,
    ii:0
  }
})

进入小程序在onLoad生命周期里获取当前位置,onReady里设置map地图上下文

onReady:function () {
    //MapContext 实例,可通过wx.createMapContext获取,通过 `id` 跟一个map组件绑定,操作对应的map组件
    this.mapCtx = wx.createMapContext('map')
},
onLoad(){
    this.curLocation()
},
curLocation(){
    //wx.getLocation获取当前的地理位置,type设置'gcj02'返回gps坐标
    wx.getLocation({
      type: 'gcj02',
    }).then(res=>{
      console.log(res)
      let{latitude,longitude}=res
      this.setData({
        latitude,longitude
      })
    })
  },

这样地图就可以显示出来了

image.png

在点击开始记录按钮来记录数据前新建一个utils.js文件用于计算距离并向外导出,在index.js里引入

//index.js
const utils=require('utils')

//utils.js

//弧度
function toRadians(d){
  return d*Math.PI/180
}
//利用两点的经度,维度计算两点距离
function getDistance(lat1,lng1,lat2,lng2){
  const R=6378137 //赤道半径
  let dis=0
  let deltaLat=toRadians(lat1)-toRadians(lat2)
  let deltaLng=toRadians(lng1)-toRadians(lng2)
  dis=2*R*Math.asin(Math.sqrt(Math.pow(Math.sin(deltaLat/2),2)
  +Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(deltaLng/2),2)))
  return dis
}
module.exports={
  getDistance
}

然后可以点击开始按钮进行记录数据了,在onLoad里添加一个定时器用于记录数据

onLoad(){
    this.curLocation()
    setInterval(this.record,this.data.interval)
},
run(){
    this.setData({
      running:!this.data.running
    })
},
record(){
    //没有开始记录return出去
    if(!this.data.running){
      return
    }
    this.setData({
      seconds:this.data.seconds+this.data.interval/1000
    })
    wx.getLocation({
      type: 'gcj02',
    }).then(res=>{
      //当前标记位置信息
      let newMarker={
        latitude:res.latitude,
        longitude:res.longitude,
        iconPath:'hd.png',
        width:12,
        height:12,
        id:1+this.data.i
      } 
      let i=this.data.i
      let point=this.data.point
      let pace=0
      let markers=this.data.markers
      if(this.data.markers.length>0){
        let lastmarker=this.data.markers.slice(-1)[0]
        //根据上一次标记点和当前标记点计算距离,超出15m添加标记,否则视为距离太短不添加标记
        pace=utils.getDistance(lastmarker.latitude,lastmarker.longitude,
          newMarker.latitude,newMarker.longitude)
          if(pace>15){
            markers.push(newMarker)
            i=this.data.i+1
            point.push({longitude:res.longitude,latitude:res.latitude})
          }else{
            pace=10
          }
      }else{
        markers.push(newMarker)
        i=this.data.i+1
        point.push({longitude:res.longitude,latitude:res.latitude})
      }
      this.setData({
        latitude:res.latitude,
        longitude:res.longitude,
        markers,
        point,
        meters:this.data.meters+pace,
        i
      })
    })
  },

然后出门走一圈记录记录😤😤😤

d59f3be5-d26b-4c61-9e82-665c9b11ecd5.gif

ok没问题,然后下一个按钮清除数据

clear(){
    this.setData({
      markers:[],
      meters:0,
      seconds:0,
      polyline:[],
      point:[],
      i:0,
      ii:0
    })
  },

点击保存数据按钮时将数据添加进本地缓存中

save(){
    //没有暂停记录return出去
    if(this.data.running){
      return
    }
    let point=this.data.point
    let markers=this.data.markers
    //point添加数组第一个数组,回放线路时形成一个闭环
    point.push(point[0])
    markers.push(markers[0])
    this.setData({
      polyline:[{
        points:point,
        color:'#99ff00',
        width:10,
        dottedLine:false
      }]
    })
    wx.setStorage({
      data:{
        markers:this.data.markers,
        seconds:this.data.seconds,
        polyline:this.data.polyline,
        point:this.data.point,
        meters:this.data.meters
      },
      key:'running',
    }).then(()=>{
      wx.showToast({
        title: '保存成功',
      })
    })
    //本地缓存后清理数据
    this.clear()
  },

点击回放按钮,开始回放记录

translateMarker() {
    let that=this
    //获取本地缓存
    wx.getStorage({
      key:'running',
      success:function (res) {
        console.log(res.data.markers)
        let running=res.data
        that.setData({
          markers:running.markers,
          point:running.point,
          polyline:running.polyline,
          seconds:running.seconds,
          meters:running.meters
        })
      }
    })
    let ii=this.data.ii
    let markers=this.data.markers
    let markerId = markers[ii].id;
    let destination = {
      longitude: markers[ii+1].longitude,
      latitude: markers[ii+1].latitude
    };
    //使每个不同距离的标记点匀速平移滑动,duration固定的话标记点距离不同动画会时快时慢
    let duration=utils.getDistance(markers[this.data.ii].latitude,markers[this.data.ii].longitude,markers[this.data.ii+1].latitude,markers[this.data.ii+1].longitude)*5
    //回放使用MapContext.translateMarker
    this.mapCtx.translateMarker({
      markerId: markerId,//当前标记点
      destination: destination,//要移动到的下一个标记点
      autoRotate: false,//关闭旋转
      duration: duration,//动画市场
      success(res) {
        that.setData({
          ii: that.data.ii + 1
        });
        // 小于长度减1继续下一个标记点动画
        if (that.data.ii < markers.length-1) {
          that.translateMarker();
        }
      },
      fail(err) {
        console.log('fail', err)
      }
    })
  }

image.png

回放效果,动画比较简陋啊😛😛,可以自己设置样式:

e3e897ca-2885-4877-9bf4-3d73db79ea03.gif