經過Weex 300行代碼開發一款簡易的跑步App

Weex正如它的目標,javascript

一套構建高性能、可擴展的原生應用的跨平臺開發方案css

Weex 給你們帶來的無疑是客戶端開發效率的提高,咱們能夠經過一套代碼,實現web,android, iOS的三個平臺上運行。本身最近嘗試了一次藉助weex的插件機制,使用Weex-Amap地圖插件 能夠開發 LBS 相關的應用。html

首先咱們先來看下運行的效果吧:vue

iOS 版java

TB1xKpkQpXXXXX.XVXXXXXXXXXX-640-1136.png

Android 版android

TB1KwM_QXXXXXcBaXXXXXXXXXXX-720-1280.png

截圖數據僅供參考ios

它大概具有下面的一些功能;git

  • 統計用戶在運動過程當中的距離累計,時間計算等。github

  • 存儲用戶的運動數據web

  • 使用地圖定位和距離計算的API,實現距離統計。

  • 顯示地圖折線,經過對定位的數據地理位置進行折線繪製

  • 統計用戶運動的數據,計算總距離和時間

  • 點擊用戶的歷史記錄,能夠查看軌跡

感受和你們所用到的app功能相差很少了,但實際上咱們藉助 Weex 和 Weex-Amap 插件能夠很是快速的實現這些功能,下面咱們來看下具體怎麼實現吧。

使用 weex-toolkit 建立項目

首先咱們按照官網的教程安裝weex-toolkit。若是已經安裝過請忽略。

$ npm install -g weex-toolkit

安裝完成後,咱們建立一個項目目錄,好比running-app

weex create running-app

你們可能會看到下面的提示,輸入y安裝便可。

This command need to install weexpack. Install now? Yes

項目建立完成後,咱們須要添加咱們的運行平臺好比android或者ios,這裏咱們添加 android 平臺。

weex platform add android

添加成功後,咱們在經過weex的插件機制,安裝weex-amap高德的地圖依賴。

weex plugin add weex-amap

安裝完成後,你能夠到項目目錄 plugins 裏面看下是否有新增的 weex-amap 的項目目錄,若是存在即表示插件安裝成功。你就能夠在src目錄下用we或者vue開發應用代碼了

設計原理

[weex-amap]結合了高德地圖多個功能,好比定位,地圖縮放,繪製折現,進行點的標記等經常使用功能。實現一款跑步應用,咱們須要解決最核心的問題就是:

統計一個在運動過程的總距離 (s)

當咱們可以獲取到總距離(s)的時候,和運動時間(t) 經過小學物理知識,咱們知道:

速度(v) = 總路程(s) / 總時間(t)

在結合一些公式,咱們還能夠計算出咱們的 卡路里(c);

其中 weex-amap 正好能夠解決上面最爲核心的問題,咱們能夠經過定位,而後在經過比較兩個連續點之間的距離,進行累加(微分累計),從而獲取總距離。(固然這只是最爲簡單的實現原理,作成完整的app還須要更加科學化的算法)

[weex-amap] 其中提供了這麼兩個API

  • getUserLocation 用於獲取用戶的當前位置地理位置,用戶會獲取經緯度 [Long, Lat]

  • getLineDistance 用戶獲取傳入的兩個地理位置的直線距離

除了這兩個API,咱們還須要用到地圖的一個組件, 就是折線繪製 weex-amap-polyline 。它能夠經過path屬性接收到一組地理位置座標值,從而在地圖上繪製連續的折線。好比:

<weex-amap-polyline stroke-color="#1ba1e2" stroke-width="3" path="{{your_path}}"></weex-amap-polylone>

其中 your_path 指定相似這樣的數據: [[116.487, 40.00003],[113.487, 40.0002]...]

關於更多的如何使用weex-amap 插件,能夠參考這篇 文章 以及 官方Demos

設計頁面功能和邏輯

你們也都用過跑步的APP,常見的界面佈局以下:

<img width="320" src="http://img1.vued.vanthink.cn/... />

那麼咱們頁面的基本結構就已經出來了:

<template>
  <div class="container">
    <weex-amap id="map2017" geolocation="true" center="{{pos}}" class="map" sdk-key="{{keys}}" zoom="{{zoom}}">
      
    </weex-amap>
    <div class="map-controller" if="{{status!=4}}">
      <div class="distance-wrap">
      </div>
      <div class="dashboard">
      </div>
      <div class="btn-wrap">
      </div>
    </div>
  </div>
</template>

<scritp>
<script>
  module.exports = {
    data: {
      keys: {
        h5:'f4b99dcd51752142ec0f1bdcb9a8ec02',
        ios: 'c551f83e1e5b19af89c74096f1c0f007',
        android: 'db6a973159cb0c2639ad02c617a786ae'
      },
      zoom: 16,
      pos: [116.48635, 40.00079],
      status: 1,
      polylinePath: []
      
    },
    
    methods: {
    
    }
  }
</script>

其中 咱們使用了weex-amap組件,其中一些屬性:

  • zoom 表示設置的地圖的縮放級別

  • geolocation 添加地圖定位插件沒若是你須要定位功能,必須設置

  • sdk-key 設置地圖的密鑰,這是地圖開發必須申請 (前往高德地圖申請)

  • center 設置地圖的中心,須要設置一個數組,傳入地理位置座標[116.487, 40.00003]第一個數字表示經度,第二個值表示緯度

其中的樣式參考以下,固然你也能夠本身實現一個佈局:

.container{
  position: relative;
  flex: 1;
  min-height: 600;
  background-color: #eee;
}
.map{
  flex: 1;
  min-height: 600;
}
.map-controller{
  z-index: 10000;
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 500;
  background-color: rgba(255,255,255,1);
  border-top-width: 2;
  border-top-color: rgba(0,0,0,.25);
}
.distance-wrap{
  flex: 1;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}

.dashboard{
  flex: 1;
  flex-direction: row;
}

.btn-wrap{
  flex: 1;
  flex-direction: row;
  align-items: center;
  justify-content: center;
}

定義數據模型

咱們須要在界面裏顯示四組數據:

  • 運動距離

  • 運動時間

  • 運動消耗

  • 運動配速

本身設計的runningData裏面包含了下面一些數據:

runningData: {
  distance: 0,  // 表示運動的累計距離
  miles: 0,    // 表示運動的累計距離,單位是千米用於界面顯示
  path: [],    // 運動座標數據
  time: '00:00:00',  // 用於界面的運動時間顯示
  seconds: 0,   // 運動的時間,單位:秒
  speed: 0,    // 配速 
  calories: 0,  // 運動的消耗,單位千卡
}

處於計算的方便其中我設計了幾個用於數據格式的轉換和計算,在個人 utils.js 裏面。

這個時候咱們須要在模板裏面添加一些代碼用於顯示這些數據;

<template>
<div class="distance-wrap">
  <text class="distance">{{runningData.miles}}</text>
  <text class="unit">千米</text>
</div>
<div class="dashboard">
  <div class="dashboard-item">
    <div class="time-wrap">
      <text class="dashboard-title">運動時間</text>
      <text class="number-lg">{{runningData.time}}</text>
    </div>
  </div>
  <div class="dashboard-item">
    <text class="dashboard-title">配速</text>
    <text class="number-lg">{{runningData.speed}}</text>
  </div>
  <div class="dashboard-item">
    <text class="dashboard-title">熱量</text>
    <text class="number-lg">{{runningData.calories}}</text>
  </div>
</div>
</template>

添加地圖折線polyline

<weex-amap id="map2017" geolocation="true" center="{{pos}}" class="map" sdk-key="{{keys}}" zoom="{{zoom}}">
  <weex-amap-polyline path="{{polylinePath}}" stroke-opacity="0.9"  stroke-style="solid" stroke-width="8" stroke-color="#1ba1e2"></weex-amap-polyline>
</weex-amap>

添加流程控制

在咱們進行跑步的過成功無疑就是這麼幾個狀態,我將它定義在了 status.js

module.exports = {
  RUNNING_READY: 1, // 跑步開始前
  RUNNING_DOING: 2, // 跑步進行中
  RUNNING_PAUSE: 3, // 跑步暫停中
  RUNNING_END: 4  // 跑步結束,
  RUNNING_PREVIEW: 5 // 數據預覽
};

咱們經過這幾個狀態來實現對界面的操做,好比開始或者暫停。這個時候咱們須要添加一一些用於界面控制的按鈕。

<template>
  ...
  <div class="btn-wrap">
    <div class="btn-circle btn-green" if="{{status==1}}" onclick="start">
      <image class="btn-icon" src="https://gw.alicdn.com/tfs/TB1sGrEQXXXXXc4XVXXXXXXXXXX-60-60.png"></image>
    </div>
    <div class="btn-circle btn-midnight" if="{{status==2 || status == 3}}" onclick="end">
      <image class="btn-icon" src="https://gw.alicdn.com/tfs/TB1uEnqQXXXXXcdapXXXXXXXXXX-60-60.png"></image>
    </div>
    <div class="btn-circle btn-green" if="{{status == 3}}" onclick="continue">
      <image class="btn-icon" src="https://gw.alicdn.com/tfs/TB1sGrEQXXXXXc4XVXXXXXXXXXX-60-60.png"></image>
    </div>
    <div class="btn-circle btn-red" if="{{status==2}}" onclick="stop">
      <image class="btn-icon" src="https://gw.alicdn.com/tfs/TB1A6vJQXXXXXa0XVXXXXXXXXXX-60-60.png"></image>
    </div>
  </div>
<template>

實現流程

咱們接下來,按照流程來實現咱們的程序邏輯:

const status = require('./lib/status');
...
module.exports = {
  // ...
  methods() {
    start() {

    },
    stop() {

    },
    continue() {

    },
    end() {

    },
  }
}

start

開始的業務邏輯很簡單,就是更改頁面狀態到運行中,而後執行程序。

start() {
  this.status = status.RUNNING_DOING;
  this.runningAmapGeolocation();
}

stop

暫停的話,咱們須要清除掉頁面的計時器。

stop() {
  this.status = status.RUNNING_PAUSE;
  clearInterval(this.timeRecorder); // 計算時間
  clearInterval(this.amapRecorder); // 計算定位
}

end

點擊結束按鈕,咱們須要清除計時器,而後顯示出累計的數據就好了,固然作的複雜一點,還能夠進行數據的存儲等。

end() {
  clearInterval(this.timeRecorder);
  clearInterval(this.amapRecorder);
  /* 使用存儲
  * storage.getItem('runningData', (res) => {
  * ...  
  * }) 
  */
}

實現地圖定位

在添加完 weex-amap 模塊後,咱們就能夠實現地圖的定位和距離計算。

// 引入 amap 模塊
const Amap = require('@weex-module/amap');

etUserLocation(callback) {
  Amap.getUserLocation(this.$el('map2017').ref, callback);
}

其中callback回調中會返回一個對象:

{
  result: 'success' or 'fail', // 接口調用是否成功
  data: {
    position: [Long, Lat] // 返回經緯度
  }
}

實現地圖距離計算

// 咱們引入第三發utils文件,用於一些計算

const utils = require('./lib/utils');


calcDistanceAndSpeed() {
  const len = this.runningData.path.length
  if(len > 1) {
    // 計算兩個點以前的距離
    Amap.getLineDistance(this.runningData.path[len-1], this.runningData.path[len-2], (res) => {
      if(res.result == 'success') {
        console.log(res.data.distance);
        this.runningData.distance += res.data.distance;
      }
      // 將總長度轉化爲公里
      this.runningData.miles = utils.mtoKm(this.runningData.distance);
       // 初略的計算卡路里 
      this.runningData.calories = (this.runningData.distance / 1000).toFixed(2);
      // 速度換算
      this.runningData.speed = utils.calcSpeed(this.runningData.distance, this.runningData.seconds);
    });
  }
}

其中 utils.js 的實現能夠參考 這裏

讓程序自動採集數據

你們寫JS必定都實現過一個倒計時的程序,經常使用的解決方案就是 setInterval (關於setInterval 時間的執行的問題能夠看這裏) 。

當點擊開始按鈕後,咱們須要設置一個計時器,用戶進行用戶時間的計算:

countDownTime() {
  this.timeRecorder = setInterval(() => {
    this.runningData.seconds ++;
    // 進行格式轉化 12s => 00:00:12
    this.runningData.time = utils.setTimeFormat(this.runningData.seconds);
  }, 1000);  
},

// 設置定位的計時器
 runningAmapGeolocation() {
  this.setUserLocation((res) => {
    if(res.result == 'success') {
      this.pos = res.data.position;
      this.runningData.path.push(res.data.position);
    }  
  }); 
  this.amapRecorder= setInterval(() => {
    this.setUserLocation((res) => {
      if(res.result == 'success') {
        this.runningData.path.push(res.data.position);  
        this.polylinePath = Array.from(this.runningData.path);
        this.pos = utils.setPosition(this.runningData.path);
        this.calcDistanceAndSpeed();
      }
    });
  }, 10000);
},

透過代碼咱們能夠看到程序會大約每隔十秒進行一次定位,而後再進行計算和距離累加。

文件源代碼

打包運行

開發完畢後,咱們能夠運行命令,讓它安裝到咱們的測試手機上。

weex run android

PS: 固然若是你要作出一個 科學 的跑步程序,還須要你加入大量測試和數據的糾正,好比咱們在使用過程會遇到定位的誤差,斷網, 用戶沒有開啓定位權限等問題,這些都是咱們須要考慮和應對的

運行 Github 上項目

項目運行截圖:

<img src="https://gw.alicdn.com/tfs/TB1... />

若是你們在實現過程當中遇到問題能夠參考 Github 上這個項目的一些代碼。相對剛剛這個簡單的功能,它完善了存儲和數據預覽,以及倒計時等小細節。

1.首先克隆這個項目(後面會寫如何本身建立這樣的項目). 確保你本身環境安裝了weex-toolkit

git clone https://github.com/weex-plugins/amap-running-app

2.進入克隆的項目目錄,而後執行 npm install

3.測試你的須要運行的平臺,好比android 或者 ios

weex plaform add android

4.添加插件 weex-amap

weex plugin add weex-amap

這個時候你就能夠運行命令看具體運行的效果了:

weex run android

amap-running-app,也歡迎PR,拍磚。

擴展閱讀

=========
原文地址:http://www.jackpu.com/tong-gu...

相關文章
相關標籤/搜索