最近接到上頭的指示,要作一個體育類的小程序,而且要在元旦以前上線一版,看了下時間,距離元旦只有一個多月,並且除去測試的時間和雙休,最多隻有三個星期,時間至關的緊迫,並且需求文檔都更新到1.3了,這也就意味着安卓和ios的版本迭代已經到了1.3了,而咱們小程序要在三個星期內開發完1.0-1.3版本的功能,因此咱們的時間至關的緊迫,看了下需求文檔和原型圖,我整我的大吃一驚,有100多個頁面,我頓時懵逼了,產品經理更我說;大家只需作三個模塊,最後一個模塊不用作,我看了一下最後一個模塊,有10幾個頁面,除去10幾個頁面還有90多個呀,頁面還好,最難的是需求文檔的業務邏輯呀,並且這個項目的難度比中小型電商項目類的要難的多,交互至關的頻繁和複雜,怎麼辦呢,一句話,涼拌,畢竟這是boss要求作的項目,只好硬着頭皮往下作,不得不從。javascript
因小程序頁面多,切交互頻繁,若是用原生開發的話,時間來不急,並且頁面的交互不少,這樣原生小程序就顯得那麼的吃力了,最終我將技術選型放在了,wepy和mpvue這兩個框架上,wepy框架是微信官方維護的,兼容性和擴展性很好,mpvue是美團旗下的,我最終選擇了mpvue,緣由是mpvue的語法跟Vue的語法是同樣的,並且咱們的前端同窗都會Vue,因此選擇mpvue是最好的選擇,因而看了一下mpvue的文檔和注意點,最終搭建了小程序的項目結構,將任務安排了下去,因而開啓了加班的苦日子....html
因項目中的登陸方式含有微信登陸,因此三端協商,若是用戶是微信登陸的話,三端統一取,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的,咱們找到緣由以後,立刻換了另一種方法,那就是解碼的方式,也是咱們最終的方法。
vue
<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
,解碼地址下載,注意:解碼這一步最好放在服務端解碼,不要放在客戶端解碼,這樣會形成信息泄露.....
html5
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會數據不一樣步,具體的作法能夠加一個開關,以下..
java
<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) {}
}
//注意:以上代碼只是模擬,僅供查考。
複製代碼
圖片上傳微信小程序給咱們提供了api,wx.chooseImage
,上傳簡單,關鍵是如何轉化base64位呢,咱們的舒同窗用了以下的寫法,看着確實沒什麼問題,用臨時路徑做爲一個請求的url,把數據返回格式設置成arraybuffer,這個也確實是個辦法,在微信開發工具裏面也是ok的,可是天有不測風雲呀,在真機上請求報錯了,那麼這種方法pass掉。react
wx.chooseImage({
success:res=>{
wx.request({
url:url,
responseType: 'arraybuffer', //最關鍵的參數,設置返回的數據格式爲arraybuffer
success:res=>{
let base64 = wx.arrayBufferToBase64(res.data);
}
})
})
複製代碼
針對上面的問題,仔細的看了下微信官方文檔,最終找到了一個代碼少,簡單的方法,wx.getFileSystemManager()
這個api能夠解決咱們上面的問題,微信官方文檔,代碼以下webpack
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這個庫來解決問題。ios
小程序中有個picker組件,他支持5中類型,雖然有5中類型可是每一個項目的不一樣,因此對picker的用途就不一樣,所以咱們將對picker進行封裝,來達到知足咱們項目的需求,咱們封裝省市,時間日期等組件,我這裏就只介紹省市
組件的封裝,其餘的組件封裝原理同省市組件原理同樣的,我這裏就很少說了,代碼以下。git
<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;
}
},
}
}
複製代碼
因項目中要用到定位功能,而小程序中的的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','定位失敗');
}
}
})
}
});
複製代碼
因爲項目用到了城市索引選擇功能,因此就採用 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) {}
},
}
複製代碼
固然實現上面這個功能也能夠用其餘的方法,如scroll-view,我這裏就很少說了。
咱們能夠經過微信中的wx.navigateBack()
這個api就能夠返回上一層頁面,可是怎樣返回上一層頁面而且刷新呢,其實能夠經過onShow這個生命週期函數來刷新頁面,若是那個頁面含有參數的話,最好代碼這麼寫
onShow(){
//之因此用try,是由於mpvue官方說,若是要獲取地址參數的話,最好在mounted週期裏面獲取,咱們用try能夠避免代碼終止和報錯
try {
let id=this.$root.$mp.query.Id;
this.init(id);
}catch (error) {}
}
複製代碼
因爲時間的緣由,我暫時先介紹這幾個在小程序中常見的問題和功能,後面我會陸續介紹,以下技術棧