通過Weex 300行代碼開發一款簡易的跑步App
Weex 正如它的目標: 一套構建高性能、可擴展的原生應用的跨平臺開發方案
Weex 給大家帶來的無疑是客戶端開發效率的提升,我們可以通過一套代碼,實現web,android, iOS的三個平臺上運行。自己最近嘗試了一次借助weex的插件機制,使用 Weex-Amap地圖插件 可以開發 LBS 相關的應用。
首先我們先來看下運行的效果吧:
iOS 版
Android 版
截圖數據僅供參考
它大概具備下面的一些功能;
- 統計用戶在運動過程中的距離累計,時間計算等。
- 存儲用戶的運動數據
- 使用地圖定位和距離計算的API,實現距離統計。
- 顯示地圖折線,通過對定位的數據地理位置進行折線繪制
- 統計用戶運動的數據,計算總距離和時間
- 點擊用戶的歷史記錄,可以查看軌跡
感覺和大家所用到的app功能相差不多了,但實際上我們借助 Weex 和 Weex-Amap 插件可以非常快速的實現這些功能,下面我們來看下具體怎么實現吧。
使用 weex-toolkit 創建項目
首先我們按照官網的教程安裝 weex-toolkit 。如果已經安裝過請忽略。
$ npm install -g weex-toolit
安裝完成后,我們創建一個項目目錄,比如 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,常見的界面布局如下:
那么我們頁面的基本結構就已經出來了:
<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://simg.open-open.com/show/ab95f3676281e1d58867ead2a6669ac6.png"></image>
</div>
<div class="btn-circle btn-midnight" if="{{status==2 || status == 3}}" onclick="end">
<image class="btn-icon" src="https://simg.open-open.com/show/bb87dc75d68c143fb19faaed33cd2e3c.png"></image>
</div>
<div class="btn-circle btn-green" if="{{status == 3}}" onclick="continue">
<image class="btn-icon" src="https://simg.open-open.com/show/ab95f3676281e1d58867ead2a6669ac6.png"></image>
</div>
<div class="btn-circle btn-red" if="{{status==2}}" onclick="stop">
<image class="btn-icon" src="https://simg.open-open.com/show/88da7ae89211b57ebab997e9a8b27088.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 上項目
項目運行截圖:
如果大家在實現過程中遇到問題可以參考 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.baiduhome.net/lib/view/home/1490749271493