mpvue開發大型體育專案及總結記

attitudes發表於2019-01-06

開篇

最近接到上頭的指示,要做一個體育類的小程式,並且要在元旦之前上線一版,看了下時間,距離元旦只有一個多月,而且除去測試的時間和雙休,最多隻有三個星期,時間相當的緊迫,而且需求文件都更新到1.3了,這也就意味著安卓和ios的版本迭代已經到了1.3了,而我們小程式要在三個星期內開發完1.0-1.3版本的功能,所以我們的時間相當的緊迫,看了下需求文件和原型圖,我整個人大吃一驚,有100多個頁面,我頓時懵逼了,產品經理更我說;你們只需做三個模組,最後一個模組不用做,我看了一下最後一個模組,有10幾個頁面,除去10幾個頁面還有90多個呀,頁面還好,最難的是需求文件的業務邏輯呀,而且這個專案的難度比中小型電商專案類的要難的多,互動相當的頻繁和複雜,怎麼辦呢,一句話,涼拌,畢竟這是boss要求做的專案,只好硬著頭皮往下做,不得不從。

技術選型

因小程式頁面多,切互動頻繁,如果用原生開發的話,時間來不急,而且頁面的互動很多,這樣原生小程式就顯得那麼的吃力了,最終我將技術選型放在了,wepy和mpvue這兩個框架上,wepy框架是微信官方維護的,相容性和擴充套件性很好,mpvue是美團旗下的,我最終選擇了mpvue,原因是mpvue的語法跟Vue的語法是一樣的,而且我們的前端同學都會Vue,所以選擇mpvue是最好的選擇,於是看了一下mpvue的文件和注意點,最終搭建了小程式的專案結構,將任務安排了下去,於是開啟了加班的苦日子….

  • 技術點1-小程式,安卓,iOS三端資料資訊同步,免登陸

因專案中的登入方式含有微信登入,所以三端協商,如果使用者是微信登入的話,三端統一取,unionid 這個欄位,這時肯定有同學要問;為什麼不取openid ,如果做過小程式的人一定知道openid是唯一的標識,微信小程式有一個,那麼在安卓,iOS他們也都有自已的openid標識,所以這樣是不能達到三端資料資訊同步,免登陸的效果的,微信官方介紹了6種獲取unionid 的方法,我們專案最終採用瞭解密獲取的方法,官方文件

import {AchieveOpenid
} from '@/http/api.js';
let that=this;
wx.login({
async success(resCode){
const cache=await AchieveOpenid({
//openid,內部伺服器=》騰訊獲取到了openid code:resCode.code
});
that.openid=cache.result.unionid;
wx.setStorageSync('openId',that.openid);

}
})複製程式碼

注意:這個方法是官方中的wx.login+code2Session方法,也確實可以獲取unionid,但是天有不測風雲呀,測試組的人員測出了unionid不存在的情況,而且還有幾個賬號也出現了這種問題,那麼我們就開始找原因,最終我們發現,如果使用者沒有關注過任何的公眾號,微信是不會給他返回unionid的,我們找到原因之後,馬上換了另外一種方法,那就是解碼的方式,也是我們最終的方法。

    <
button class='openpage-authorize' open-type="getUserInfo" lang="zh_CN" @getuserinfo="onGotUserInfo">
<
/button>
複製程式碼
   //注意我這裡只列舉解碼的程式碼,有些程式碼省略了,請熟知。   import WXBizDataCrypt from "@/utils/cryptojs/RdWXBizDataCrypt.js"   //引用解碼    methods:{ 
deCode(encryptedData,iv,sessionKey){
let wxObj=null,data=null;
wxObj= new WXBizDataCrypt('wx3ea59bf3ff3a9bb8', sessionKey);
data= wxObj.decryptData(encryptedData,iv);
this.openid=data.unionId;
wx.setStorageSync('openId',data.unionId);

}, onGotUserInfo(e) {
//通過按鈕觸發getuserinfo if(e.mp.detail.userInfo){
this.deCode(e.mp.detail.encryptedData,e.mp.detail.iv,this.sessionKey);

}else{
toast('請再次授權');

}
},
}複製程式碼

最終我們可以通過上面的程式碼獲取unionId解碼地址下載,注意:解碼這一步最好放在服務端解碼,不要放在客戶端解碼,這樣會造成資訊洩露.....

  • 技術點2-在小程式中使用 canvas

mpvue開發大型體育專案及總結記
mpvue開發大型體育專案及總結記

我們可以看到上面兩個專案中的案例圖片,他們是用canvas畫的,第一個是採用微信官方的api,wx.createCanvasContext 不懂得同學可以自已去看微信官方文件,程式碼如下

 const ctx = wx.createCanvasContext('myCanvas');
ctx.setLineCap('round') var gradient1=ctx.createLinearGradient(0,0,170,0);
gradient1.addColorStop("0","#FFF956");
gradient1.addColorStop("1.0","#FF6C00");
var gradient2=ctx.createLinearGradient(0,0,170,0);
gradient2.addColorStop("0","#8156FE");
gradient2.addColorStop("1.0","#3AFFF1");
ctx.setLineWidth(4);
ctx.beginPath();
ctx.arc(50, 50, 30,0.75*Math.PI,0.25*Math.PI,false);
ctx.setStrokeStyle('#4e4f59');
ctx.stroke() ctx.beginPath();
ctx.arc(50, 50, 38,0.75*Math.PI,0.25*Math.PI,false);
ctx.setStrokeStyle('#4e4f59');
ctx.stroke();
//勝 ctx.beginPath();
ctx.arc(50, 50, 30,0.75*Math.PI,(((winarc*1.5+0.75)%2)==0?2:((winarc*1.5+0.75)%2))*Math.PI,false);
ctx.setStrokeStyle(gradient1) ctx.stroke() //負 ctx.beginPath();
ctx.arc(50, 50, 38,0.75*Math.PI,(((failarc*1.5+0.75)%2)==0?2:((failarc*1.5+0.75)%2))*Math.PI,false) ctx.setStrokeStyle(gradient2);
ctx.stroke() ctx.setTextAlign('center');
ctx.setFontSize(16);
ctx.setFillStyle('#fff');
ctx.setTextBaseline('middle');
ctx.fillText('戰績', 50, 50);
ctx.draw()複製程式碼

注意點:如果canva的資料是非同步的話,一定要在資料載入完成之後,在讓它渲染到檢視層中去,如果不這樣做的話,canvas會資料不同步,具體的做法可以加一個開關,如下..

      <
canvas canvas-id="myCanvas" class="index-header-data-circle-canvas" v-if='on'>
<
/canvas>
複製程式碼
   data(){ 
return {
on:false
}
} async xx(){
try{
const data=await xxx();
this.on=data.code==='000'?true:false;

}catch (error) {
}
} //注意:以上程式碼只是模擬,僅供查考。複製程式碼
  • 技術點3-圖片上傳轉化base64

圖片上傳微信小程式給我們提供了api,wx.chooseImage ,上傳簡單,關鍵是如何轉化base64位呢,我們的舒同學用瞭如下的寫法,看著確實沒什麼問題,用臨時路徑作為一個請求的url,把資料返回格式設定成arraybuffer,這個也確實是個辦法,在微信開發工具裡面也是ok的,但是天有不測風雲呀,在真機上請求報錯了,那麼這種方法pass掉。

   wx.chooseImage({ 
success:res=>
{
wx.request({
url:url, responseType: 'arraybuffer', //最關鍵的引數,設定返回的資料格式為arraybuffer success:res=>
{
let base64 = wx.arrayBufferToBase64(res.data);

}
})
})複製程式碼

針對上面的問題,仔細的看了下微信官方文件,最終找到了一個程式碼少,簡單的方法,wx.getFileSystemManager()這個api可以解決我們上面的問題,微信官方文件,程式碼如下

              wx.chooseImage({ 
count: 1, sizeType: ['original', 'compressed'], sourceType: ['album', 'camera'], success:(res)=>
{
wx.getFileSystemManager().readFile({
filePath:res.tempFilePaths[0], //選擇圖片返回的相對路徑 encoding: 'base64', success: res =>
{
console.log(res.data)
}
})
}
})複製程式碼

其實除了,wx.getFileSystemManager()可以解決我們的問題外,還有一種方法,那就是更html5一樣的處理方法,通過canvas來畫,然後在用canvas的api來轉base64,注意:如果通過canvas來轉base64的話,有個bug,那就是在iOS手機上圖片會出現旋轉90度的問題小程式可以借鑑這個同學的方法來解決,如果是html5的話可以通過exif.js這個庫來解決問題。

  • 技術點4-對picker的封裝

小程式中有個picker元件,他支援5中型別,雖然有5中型別但是每個專案的不同,所以對picker的用途就不同,因此我們將對picker進行封裝,來達到滿足我們專案的需求,我們封裝省市,時間日期等元件,我這裡就只介紹省市元件的封裝,其他的元件封裝原理同省市元件原理一樣的,我這裡就不多說了,程式碼如下。

    <
picker class="pickes" mode="multiSelector" @change="PickerChange" @columnchange="PickerColumnChange" :range="allList" range-key='provinceName' :value='multiIndex' v-if='show'>
<
div class="slot">
<
/div>
<
/picker>
複製程式碼
/** * @describe 省市選擇器 * @rerurn  省,市,省id,市id */  import {allCity
} from "@/http/api.js";
export default {
data() {
return {
list:[], multiIndex: [0, 0], //顯示化動的列數 allList:[], //儲存二維資料 singleList:[], //儲存一維陣列 show:false, //防止資料沒有載入出來 cityInfo:{
}, //儲存省,市,省id,市id
}
}, mounted(){
this.init();

}, methods:{
async init(){
try {
let child=[],data=null;
data=await allCity();
//獲取後臺返回的城市 this.singleList=data.result;
child.push(data.result[0]);
this.allList.push(data.result,child);
this.show=true;

} catch (error) {
}
}, PickerChange(e) {
this.cityInfo.provinceId=this.singleList[e.mp.detail.value[0]].provinceId;
//省id this.cityInfo.provinceName=this.singleList[e.mp.detail.value[0]].provinceName;
//省名 this.cityInfo.cityId=this.singleList[e.mp.detail.value[0]].cityList[e.mp.detail.value[1]].cityId;
//城市id this.cityInfo.cityName=this.singleList[e.mp.detail.value[0]].cityList[e.mp.detail.value[1]].cityName;
//城市名 this.$emit('cityInfo',this.cityInfo);
//將值傳給父元件
}, PickerColumnChange(e) {
switch (e.mp.detail.column) {
case 0: this.list = [];
this.singleList.forEach(item =>
{
if (item.provinceId ==this.singleList[e.mp.detail.value].provinceId) {
item.cityList.forEach(item=>
{
//注意這一步最為重要,給陣列新增一個和父物件一樣的鍵值名,這樣picker元件可以找的到 item.provinceName=item.cityName;

})
}
});
this.allList[1]=this.list;
this.multiIndex[0]=e.mp.detail.value;
this.multiIndex[1]=0;
//注意這個表示的時選擇中省切換的時候,要將省的第一個城市放在第一位 break;

}
},
}
}複製程式碼
mpvue開發大型體育專案及總結記
  • 技術點5-在小程式使用高德定位

因專案中要用到定位功能,而小程式中的的api並不適用專案,所以就選擇了高德定位,高德小程式版文件,程式碼如下

   //注意我這裡只列舉定位的程式碼,有些程式碼省略了,請熟知。       let _this = this,myAmapFun=null;
myAmapFun = new amapFile.AMapWX({
key: "xxxxx" //高德的金鑰
});
myAmapFun.getRegeo({
success(data){
_this.$store.dispatch('cityLocal',data[0].regeocodeData.addressComponent.city);

}, fail(err) {
wx.showModal({
title: '提示', content: '定位失敗,請手動定位', success (res) {
if (res.confirm) {
path({url:'/pages/city/main'
});

}else if (res.cancel) {
_this.$store.dispatch('cityLocal','定位失敗');

}
}
})
}
});
複製程式碼
  • 技術點6-對微信小程式節點的運用

由於專案用到了城市索引選擇功能,所以就採用 wx.createSelectorQuery()這個api來實現這個功能,程式碼如下

   <
ul class="slide">
<
li v-for="(item,index) in cityJson.leter" :key="index" @tap='touStart(item.letid,item.lettext)'>
{{item.lettext
}
} <
/li>
<
/ul>
複製程式碼
   //注意我這裡只列舉城市索引選擇的程式碼,有些程式碼省略了,請熟知。   onPageScroll(e){ 
this.scollTop=e.scrollTop //同步
}, methods:{
touStart(flag,text){
try {
wx.createSelectorQuery().select(flag).fields({
//運用微信節點api dataset: true, size: true, rect: true, computedStyle: ['margin', 'backgroundColor']
}, (res)=>
{
wx.pageScrollTo({
scrollTop: this.scollTop+res.top, duration: 0
});
this.on=true;
this.modalText=text;
setTimeout(()=>
{
this.on=false;

},2000)
}).exec()
}catch (error) {
}
},
}複製程式碼
mpvue開發大型體育專案及總結記

當然實現上面這個功能也可以用其他的方法,如scroll-view,我這裡就不多說了。

  • 技術點7-返回上一層頁面,重新整理頁面資料

我們可以通過微信中的wx.navigateBack()這個api就可以返回上一層頁面,但是怎樣返回上一層頁面並且重新整理呢,其實可以通過onShow這個生命週期函式來重新整理頁面,如果那個頁面含有引數的話,最好程式碼這麼寫

onShow(){//之所以用try,是因為mpvue官方說,如果要獲取地址引數的話,最好在mounted週期裡面獲取,我們用try可以避免程式碼終止和報錯     try { 
let id=this.$root.$mp.query.Id;
this.init(id);

}catch (error) {
}
}複製程式碼

結語

由於時間的原因,我暫時先介紹這幾個在小程式中常見的問題和功能,後面我會陸續介紹,如下技術棧

  • vue的三種ssr方法,以及在專案中的使用
  • react+redux在專案中的使用
  • 打造自已的webpack,gulp開發環境
  • koa框架的介紹和使用

最後,祝所有人,新年快樂,在2019年中實現自已的夢想,放飛自我。

來源:https://juejin.im/post/5c2d8073e51d455405559941#comment

相關文章