github地址(歡迎star):https://github.com/xiaobinwu/dj
版本:0.15.152900(暫未升級原因:升級后需要圖片無法本地引用,必須使用image或是遠程路徑引用)


目錄結構

css => 放置公用wxss,目前只有一個font.wcss
image => 靜態資源目錄
lib => 第三方庫(如:qqmap-wx-jssdk.min.js)
pages => 小程序頁面(包括四個文件,.wxml/.wxss/.js/.json)
template => 抽離出來的template,具有復用性
utils => 工具類
app.js/app.json/app.wxss => 配置
踩過的坑
1. promise封裝
官方request代碼:
wx.request({
url: 'test.php', //僅為示例,並非真實的接口地址
data: {
x: '' ,
y: ''
},
header: {
'content-type': 'application/json'
},
success: function(res) {
console.log(res.data)
}
})
但是有很多場景需要promise化的,所以使用第三方promise庫(es6-promise.min.js),對request進行了一層包裝:
/* utils/util.js */
/* api接口promise 柯里化*/
var Promise = require('../lib/es6-promise.min.js');
function wxPromisify(fn, scope) {
return function (obj = {}) {
return new Promise((resolve, reject) => {
obj.success = function (res) {
resolve(res);
}
obj.fail = function (res) {
reject(res);
}
if(scope){
//改變this指向
var newFn = fn.bind(scope);
newFn(obj);
}else{
fn(obj);
}
})
}
}
/* request 封裝*/
var wxrequest = wxPromisify(wx.request);
function wxRequest(options, tokenNotRequired){
return wxrequest(options).then(res => {
var data = res.data;
if(data.status === 404404) {
if(tokenNotRequired){
delete options.headers;
return wxRequest(options);
}else{
return updateToken().then(token => {
return wxRequest(object.assignIn(options, {
headers: { 'X-Auth-Token': token }
}));
});
}
}else {
return Promise.resolve(data);
}
}).catch(err => {
return Promise.reject(err);
});
}
2. Javascript作用域問題
由於小程序默認給的微信地圖api有些需求達不到要求,於是使用第三方庫(qqmap-wx-jssdk.min.js,這是絕配),這樣定位功能也比較好做,以及后續要做的地址管理模塊也比較好下手,但是有個問題,對微信地圖jdk接口進行promise化后,使用過程會報錯,導致定位失敗,所以需要改變其執行作用,於是對wxPromisify()方法做了些改造,重新綁定作用域至qqmapsdk,調用如下:
//address.js // 引入SDK核心類 var QQMapWX = require('../lib/qqmap-wx-jssdk.min.js'); // 實例化API核心類(需要配置安全域名https://apis.map.qq.com) var qqmapsdk = new QQMapWX({ key: 'xxxxx' //需要到騰地圖上申請key }); ... ... // 請求用戶授權定位 //逆地址解析 var ReverseGeocoder = util.wxPromisify(qqmapsdk.reverseGeocoder, qqmapsdk); //需改變作用域
對於小程序是需要配置對應的安全域名的,這樣才能執行request
3. 如何衍生出組件模板
模板頁(template)沒有天生配對js,但是也可以實現,實現面向對象的思想,對模板所需要的js進行一層類的封裝,保證構造函數需要接受父頁面的上下文對象,然后可以把聲明好的類方法綁定到父頁面上面去,對於模板頁js方法,以_FUN()方式命名。下面是為圖片懶加載優化而做的swiper模板組件,可以參考一下。
/** * 圖片預加載組件 * * @author xiaobin_wu * template/silder/silder.js */ class Slider { constructor(pageContext, options = { picList: [], showArr:[] }){ this.page = pageContext; //獲取頁面上下文 this.page.data.slider = { picList: options.picList, showArr: options.showArr }; //初始化data this.page._sliderChange = this._sliderChange.bind(this); } //監聽滑動事件,實現圖片懶加載 _sliderChange(e){ if(this.page.data.slider.showArr){ let showArr = this.page.data.slider.showArr; for(let i = 0; i < showArr.length; i++){ if(i === e.detail.current){ showArr[i] = true; } } this.page.setData({ 'slider.showArr': showArr }); } } initData(imgs){ const arr = new Array(imgs.length).fill(false); this.page.setData({ 'slider.picList': imgs, 'slider.showArr': arr.fill(true, 0 , 1) }); } } module.exports = Slider
以類形式module.exports出去,Page頁面,以var Slider = require('../../template/slider/slider.js');形式引入,然后new操作,模板wxml也參考template/silder/silder.wxml,也可以對應寫wxss,這樣做模板頁復用性高,類似組件的模式。
4. scroll-view使用scroll-x失效問題
剛開始使用scroll-view,scroll-x一直失效,不能水平scroll,折騰了好多時間,結果這樣就成了,大概如下結構(home.wxml):
<scroll-view scroll-x="{{true}}" scroll-left="{{scrollLeft}}" class="scroll-bar" style="width:100%;" >
<view style="width: {{idxData.navbar.length * 168}}rpx">
<view wx:for="{{idxData.navbar}}" wx:for-item="cate" class="cate-item {{index == currentIndex ? 'active' : ''}}" data-id="{{cate.nav_id}}" data-index="{{index}}" bindtap="cateClick">{{cate.nav_name}}</view>
</view>
</scroll-view>
忽略其他亂起八糟的代碼,主要是這個<view style="width: {{idxData.navbar.length * 168}}rpx">,需要保證scroll-view下面的view的width必須要大於100%,充滿整個scroll-view
4. swiper高度無法自動撐開,暫時不支持

於是對於紅線部分的產品分類swiper,就只能手動計算swiper高度,來實現swiper的效果,但是由於對應每個swiper-item還會有個下拉加載,所以產品數目會一直變化,所以計算起來相當於耗性能,希望官方能盡快讓swiper高度允許自動撐開
5. template模板
template模板,對象傳遞方式=>data={{a: x1,b: x2}},x1、x2對應data綁定的變量
6. setData設置動態數據
可能你會遇到這種情況(設置動態數據):
this.setData({ 'array[0]': 1 }); /* 上面這樣設置是沒問題的,但是是動態的,那該怎么辦?這樣... */ this.setData({ 'array['+ index +']': 1 }); /* 很遺憾,無法怎么做 */
解決辦法,聲明中間量,如下:
/* utils/util.js */ //動態setData function dynamicSetData(field, index, value, suffix, type='object'){ var param = {}; var string = field + '[' + index + ']' + (typeof suffix !== 'undefined' ? type === 'object' ? '.' + suffix : '[' + suffix + ']' : ''); param[string] = value; return param; }
這樣最后就可以這樣,this.setData(util.dynamicSetData('firstLoadDataFlag', index, true));,即可用於對象的改變,也可以用於數組的改變。
7. 設置頂層標簽Page的樣式,處理安卓機的背景色問題
8 px與rpx之間轉化
對於小程序中,也有一些組件需要傳遞變量單位為px的,如果這個變量是需要計算出來的,但是我們使用的確是rpx單位,那么他們之間的轉化比例是有必要知道的
/* utils/util.js */ //獲取px與rpx之間的比列 function getRpx(){ var winWidth = wx.getSystemInfoSync().windowWidth; return 750/winWidth; }
8. image問題
image組件,其實對於src圖片路徑,是以背景圖展示的,並不是真的類似img,auto是不生效的。
9. wx.navigateBack返回無法傳參數通知
wx.navigateBack返回通知上一頁執行指定函數的作用,可以使用getCurrentPages()來獲取上一頁page對象,事先執行,如下:
/* pages/order-detail/order-detail.js */ //返回執行上一個頁面的函數,good navigateBackFun: function(){ var pages = getCurrentPages(); var prevPage = pages[pages.length - 2]; if(prevPage.__route__.indexOf("pages/order/order") != -1) { prevPage.actionCallback(this.data.btnAction,this.data.page); } }
10. class可以多組操作
<view class="status-item {{index == orderData.progress.last_index? 'active' : ''}} {{index === orderData.progress.info.length - 1 ? 'last-status-item' : ''}}"></view>
11. 對於字體文件的使用
對於下面的字體文件的引用會導致報錯,微信小程序似乎不支持怎么使用
@font-face { font-family: 'Glyphicons Halflings'; src: url('/assets/fonts/glyphicons-halflings-regular.eot'); src: url('/assets/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('/assets/fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('/assets/fonts/glyphicons-halflings-regular.woff') format('woff'), url('/assets/fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('/assets/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); }
解決辦法,將ttf文件拿出,轉化成base64,以wxss引入。base64轉化
12. 購物車功能
對於購車功能也是相當折騰的,通過在app.js定義全局變量:
cartData:{ list:[], totalCount:1, totalPrice:0, // 起送價 floorPrice:0, // 總價達到此價免配送費 freeShipPrice:0, // 運費 deliveryFee:0, storeId:0, storeName:'' }
然后每次加減產品,清空購物車來操作cartData的變化,list存儲購物車產品數據,在首頁和產品詳情頁,可以來獲取購物車的數據,當然也會把購物車數據的商品id和門店id存儲到Storage,可以用來異步更新最新的購物車數據,在首頁和產品詳情頁的來回切換,對於購物車需要時刻去檢查,映射到對應分類的swiper產品的加減變化,這里有沒有像vue中vuex的狀態管理能對數據集中管理,(對於vuex的使用 點擊),導致監聽變化變得很復雜,有把加減部件cart-ctrl和購物車cart提取成template模板組件,結果處理起來,這里一萬個省略號,很悲催!github地址(歡迎star):https://github.com/xiaobinwu/dj
