小程序模板網(wǎng)

hss01248:全流程詳解:小程序基本開發(fā)框架的搭建

發(fā)布時(shí)間:2018-03-29 18:28 所屬欄目:小程序開發(fā)教程
使用開發(fā)工具的正確姿勢

微信提供的開發(fā)工具的編輯功能不是一般的水,寫代碼肯定不能用它,否則就是浪費(fèi)生命.不說別的,連自動(dòng)保存都沒有,第一次寫時(shí)寫了一個(gè)多小時(shí),后面下班直接關(guān)掉,也不彈出提示說沒保存.然后第二天過來,寫的代碼全沒了!!! 頓時(shí)感到巨坑無比.這些工具開發(fā)人員吃干飯的么???
(后來的版本已經(jīng)修復(fù)不能自動(dòng)保存的問題了,當(dāng)然編輯功能還是不好用.)

它的正確用法是作為運(yùn)行和調(diào)試工具.

那么適合作為編輯工具的是: webStorm.基于IntelJ內(nèi)核,開啟Dracula主題,跟Android studio的使用習(xí)慣非常接近,so cool!各種方法提示,自動(dòng)保存,快速查找...應(yīng)有盡有.閉源的微信開發(fā)工具就不要用來寫代碼了,珍惜生命.
webStorm要識(shí)別wxml和wxss,還需要配置一下文件類型:(看下面別人截的圖)
記住html和css里都要加上微信小程序?qū)?yīng)的類型

 

綜上,開發(fā)時(shí),用webstorm來寫代碼,用微信開發(fā)工具來運(yùn)行和調(diào)試,速度颼颼的!

 
網(wǎng)絡(luò)請(qǐng)求的封裝
 

微信提供了底層網(wǎng)絡(luò)驅(qū)動(dòng)以及成功和失敗的回調(diào).但對(duì)于一個(gè)項(xiàng)目中的實(shí)際使用而言,仍然還是顯得繁瑣,還有很多封裝和簡化的空間.



wx.request({
  url: 'test.php',//請(qǐng)求的url
  data: {//請(qǐng)求的參數(shù)
     x: '' ,
     y: ''
  },
  header: {//請(qǐng)求頭
      'Content-Type': 'application/json'
  },
  method:"POST",
  success: function(res) {//成功的回調(diào)
    console.log(res.data)
  }
})
 
網(wǎng)絡(luò)框架二次封裝的一般姿勢
 

對(duì)于一個(gè)網(wǎng)絡(luò)訪問來說,請(qǐng)求一般是get和post,拼上各種參數(shù)以及請(qǐng)求頭,然后拿到回來的響應(yīng),解析并得到最終需要的數(shù)據(jù).

對(duì)于具體項(xiàng)目來說,請(qǐng)求時(shí)會(huì)有每個(gè)(或大多數(shù))請(qǐng)求都要帶的參數(shù),都要帶的請(qǐng)求頭,返回的數(shù)據(jù)格式可能都是一致的,那么基于此,對(duì)微信的網(wǎng)絡(luò)請(qǐng)求api進(jìn)行二次封裝:

在我目前的項(xiàng)目中,

請(qǐng)求:

大多數(shù)請(qǐng)求是post,基本上每個(gè)請(qǐng)求都需要攜帶sessionId來與服務(wù)器驗(yàn)證登錄狀態(tài),還有很多請(qǐng)求是基于分頁的,需要帶上pageSize和pageIndex.
再跟頁面邏輯關(guān)聯(lián)起來,請(qǐng)求可能是因?yàn)榈谝淮芜M(jìn)入頁面,或者刷新,或者上拉加載更多.

響應(yīng):

大多數(shù)拿到的數(shù)據(jù)格式是標(biāo)準(zhǔn)json格式,如下



{
    "code":1,
    "data":xxx,//可能是String,也可能是JsonObject,或JsonArray,也可能是null,或undefined
    "msg":yyy//可能為空

}

通過請(qǐng)求的狀態(tài)碼code來判斷這個(gè)請(qǐng)求是否真正成功.我們的項(xiàng)目中還有常見的是code=5:登錄過期或未登錄,code=2: 沒有找到對(duì)應(yīng)的內(nèi)容 等等.

我們實(shí)際使用中需要的:

如果是大多數(shù)情況的請(qǐng)求時(shí),只需要指定:

  1. url的尾部
  2. 該請(qǐng)求的非一般的參數(shù)
  3. 該請(qǐng)求由什么動(dòng)作引起的(第一次進(jìn)入,刷新,加載更多)

對(duì)于響應(yīng),我們只需要:

  1. 成功時(shí):拿到data里面的數(shù)據(jù)
  2. 失敗時(shí),拿到失敗的信息(細(xì)分一下,包括可以直接顯示給用戶的和不能讓用戶看到的),以及失敗狀態(tài)碼
  3. 數(shù)據(jù)為空的回調(diào):(常見于列表數(shù)據(jù)的加載)

我們期望的api是:



netUtil.buildRequest(page,urlTail,params,callback)//必須的參數(shù)和回調(diào)
.setXxx(xxx)//額外的設(shè)置,鏈?zhǔn)秸{(diào)用
..
.send();//最終發(fā)出請(qǐng)求的動(dòng)作
 
基于上面的分析,封裝如下:

定義好攜帶構(gòu)建請(qǐng)求的對(duì)象:



//這兩個(gè)錯(cuò)誤碼是項(xiàng)目接口文檔統(tǒng)一定義好的
const code_unlogin = 5;
const code_unfound = 2;

function requestConfig(){
    this.page;  //頁面對(duì)象
    this.isNewApi = true;
    this.urlTail='';
    this.params={
        pageIndex:0,
        pageSize:getApp().globalData.defaultPageSize,
        session_id:getApp().globalData.session_id
    };
    this.netMethod='POST';
    this.callback={
        onPre: function(){},
        onEnd: function(){

        },
        onSuccess:function (data){},
        onEmpty : function(){},
        onError : function(msgCanShow,code,hiddenMsg){},
        onUnlogin: function(){
            this.onError("您還沒有登錄或登錄已過期,請(qǐng)登錄",5,'')
        },
        onUnFound: function(){
            this.onError("您要的內(nèi)容沒有找到",2,'')
        }
    };

    this.setMethodGet = function(){
        this.netMethod = 'GET';
        return this;
    }

    this.setApiOld = function(){
        this.isNewApi = false;
        return this;
    }

    this.send = function(){
        request(this);
    }
}
 
請(qǐng)求的封裝 供我們調(diào)用的頂層api:


//todo 拷貝這段代碼去用--buildRequest里的callback
/*
 onPre: function(){},
 onEnd: function(){
       hideLoadingDialog(page);
 },
 onSuccess:function (data){},
 onEmpty : function(){},
 onError : function(msgCanShow,code,hiddenMsg){},
 onUnlogin: function(){
 this.onError("您還沒有登錄或登錄已過期,請(qǐng)登錄",5,'')
 },
 onUnFound: function(){
 this.onError("您要的內(nèi)容沒有找到",2,'')
 }

* */



/**
 * 注意,此方法調(diào)用后還要調(diào)用.send()才是發(fā)送出去.
 * @param page
 * @param urlTail
 * @param params
 * @param callback  拷貝上方注釋區(qū)的代碼使用
 * @returns {requestConfig}
 */
function buildRequest(page,urlTail,params,callback){
    var config = new requestConfig();
    config.page = page;
    config.urlTail = urlTail;

    if (getApp().globalData.session_id == null  || getApp().globalData.session_id == ''){
        params.session_id=''
    }else {
        params.session_id = getApp().globalData.session_id;
    }
    if (params.pageIndex == undefined || params.pageIndex <=0 || params.pageSize == 0){
        params.pageSize=0
    }else {
        if (params.pageSize == undefined){
            params.pageSize = getApp().globalData.defaultPageSize;
        }
    }
    log(params)
    config.params = params;

    log(config.params)

    //config.callback = callback;

    if(isFunction(callback.onPre)){
        config.callback.onPre=callback.onPre;
    }

    if(isFunction(callback.onEnd)){
        config.callback.onEnd=callback.onEnd;
    }

    if(isFunction(callback.onEmpty)){
        config.callback.onEmpty=callback.onEmpty;
    }

    if(isFunction(callback.onSuccess)){
        config.callback.onSuccess=callback.onSuccess;
    }

    if(isFunction(callback.onError)){
        config.callback.onError=callback.onError;
    }

    if(isFunction(callback.onUnlogin)){
        config.callback.onUnlogin=callback.onUnlogin;
    }
    if(isFunction(callback.onUnFound)){
        config.callback.onUnFound=callback.onUnFound;
    }
    return config;
}
 
最終請(qǐng)求的發(fā)送:


function request(requestConfig){

    //檢驗(yàn)三個(gè)公有參數(shù)并處理.這里與上面有所重復(fù),是為了兼容之前寫的幾個(gè)api,不想改了.
    requestConfig.params.sessionId= getApp().globalData.sessionId;
    if (requestConfig.params.sessionId ==null  || requestConfig.params.sessionId == ''){
      delete  requestConfig.params.sessionId;
    }
    if (requestConfig.params.pageIndex ==0 || requestConfig.params.pageSize == 0){
       delete requestConfig.params.pageIndex ;
        delete  requestConfig.params.pageSize;
    }


    //var body = getStr("&", requestConfig.params);//拼接請(qǐng)求參數(shù)
    requestConfig.onPre();//請(qǐng)求發(fā)出前
    wx.request({
       // url: getApp().globalData.apiHeadUrl+requestConfig.urlTail+"?"+body,貌似這樣寫,同時(shí)不給data賦值,post請(qǐng)求也是可以成功的
        url: getApp().globalData.apiHeadUrl+requestConfig.urlTail,
        method:requestConfig.netMethod,
        data:requestConfig.params,
        header: {'Content-Type':'application/json'},
        success: function(res) {
            console.log(res);
            if(res.statusCode = 200){
                var responseData = res.data
                var code = responseData.code;
                var msg = responseData.message;

                if(code == 0){
                    var data = responseData.data;
                    var isDataNull = isOptStrNull(data);
                    if(isDataNull){
                        requestConfig.onEmpty();
                    }else{
                        requestConfig.onSuccess(data);
                    }
                }else if(code == 2){
                    requestConfig.onUnFound();
                }else if(code == 5){
                    requestConfig.onUnlogin();
                }else{
                    var isMsgNull = isOptStrNull(msg);
                    if(isMsgNull){
                        var isCodeNull = isOptStrNull(code);
                        if (isCodeNull){
                            requestConfig.onError("數(shù)據(jù)異常!,請(qǐng)核查",code,'');
                        }else {
                            requestConfig.onError("數(shù)據(jù)異常!,錯(cuò)誤碼為"+code,code,'');
                        }

                    }else{
                        requestConfig.onError(msg,code,'');
                    }
                }
            }else if(res.statusCode >= 500){
                requestConfig.onError("服務(wù)器異常!",res.statusCode,'');
            }else if(res.statusCode >= 400 && res.statusCode < 500){
                requestConfig.onError("沒有找到內(nèi)容",res.statusCode,'');
            }else{
                requestConfig.onError("網(wǎng)絡(luò)請(qǐng)求異常!",res.statusCode,'');
            }
        },
        fail:function(res){
            console.log("fail",res)
            requestConfig.onError("網(wǎng)絡(luò)請(qǐng)求異常!",res.statusCode,'');

        },
        complete:function(res){
            // that.setData({hidden:true,toast:true});
        }
    })
}
 
將方法暴露,并在需要時(shí)引用:

方法寫在netUtil.js下,在該js文件最下方暴露方法:



module.exports = {
 buildRequest:buildRequest

}

實(shí)際引用:


var netUtil=require("../../utils/netUtil.js");
 
實(shí)際使用時(shí):
 

小技巧: js無法像java一樣定義好了接口,然后IDE自動(dòng)生成代碼.可以這樣: 將callback的空方法寫到netUtil的buildRequest方法上方的注釋區(qū),每次用時(shí),點(diǎn)擊方法名跳到那邊去拷貝即可.


 var params = {};
params.id = id;

netUtil.buildRequest(that,API.Album.DETAIL,params,{
  onPre: function(){
    netUtil.showLoadingDialog(that);
  },
  onEnd:function(){

  },
  onSuccess:function (data){
    netUtil.showContent(that);
        ....
  },
  onEmpty : function(){

  },
  onError : function(msgCanShow,code,hiddenMsg){
    netUtil.showErrorPage(that,msgCanShow);
  },
  onUnlogin: function(){
    this.onError("您還沒有登錄或登錄已過期,請(qǐng)登錄",5,'')
  },
  onUnFound: function(){
    this.onError("您要的內(nèi)容沒有找到",2,'')
  }
}).send();
 
頁面狀態(tài)管理 對(duì)于大多數(shù)網(wǎng)絡(luò)請(qǐng)求后顯示的頁面,有這么幾種頁面狀態(tài):
  1. 第一次進(jìn)入時(shí),網(wǎng)絡(luò)請(qǐng)求過程中:顯示"加載中"的狀態(tài)
  2. 加載的內(nèi)容為空,顯示"空白頁面"
  3. 加載發(fā)生錯(cuò)誤,顯示"錯(cuò)誤頁面",此頁面一般有一個(gè)點(diǎn)擊重試的按鈕.該按鈕一般的邏輯是:如果沒有網(wǎng)絡(luò)則點(diǎn)擊后去打開網(wǎng)絡(luò)設(shè)置,如果有網(wǎng)絡(luò),則重新發(fā)送網(wǎng)絡(luò)請(qǐng)求.
  4. 加載成功,就顯示內(nèi)容頁.
對(duì)于已經(jīng)加載成功了,顯示了內(nèi)容頁的"下拉拉刷新":
  1. 頁面上方會(huì)有"刷新中"的ui顯示,這個(gè)微信已經(jīng)原生集成,無需處理.
  2. 刷新成功,最好是彈出toast提示數(shù)據(jù)刷新成功
  3. 刷新失敗,可以不提示,也可以提示,看具體選擇.
對(duì)于一些分批加載的列表數(shù)據(jù),一般還有上拉"加載更多"的功能:
 

參考微信文檔中ui設(shè)計(jì)規(guī)范,上拉加載更多的ui提示應(yīng)該放在頁面最下部占一行,而不應(yīng)該在頁面中間顯示一個(gè)大大的loading的效果.

  1. scrollview拉到最底部,觸發(fā)加載事件,顯示"加載中"的ui
  2. 加載成功,直接就將數(shù)據(jù)添加到原list上,這時(shí)也看不到最底部那行ui,所以不用處理
  3. 加載失敗,則在那一行顯示"加載失敗"的字樣,同時(shí)提示用戶"上拉重試",或者在那一行放置一個(gè)按鈕,點(diǎn)擊按鈕重試.
封裝
 

通過上面的分析,可以確定大部分頁面的通用狀態(tài)管理邏輯,那么就可以設(shè)計(jì)通用的狀態(tài)管理模板了.

ui的顯示是通過Page里的data中的數(shù)據(jù)來控制的,并通過page.setData({xxx})來刷新的,原先每個(gè)頁面都拷貝同樣的js屬性和wxml代碼去實(shí)現(xiàn)封裝,后來進(jìn)行了封裝,js屬性用方法來封裝,通過微信提供的template封裝共同的wxml代碼,通過import或include導(dǎo)入到wxml中(但是不知什么bug,template一直無法起作用).

控制ui顯示與否的屬性的封裝



function netStateBean(){
//toast的是老api,工具升級(jí)后無需設(shè)置了
    this.toastHidden=true,
    this.toastMsg='',

    this.loadingHidden=false,
    this.emptyHidden = true,
    this.emptyMsg='暫時(shí)沒有內(nèi)容,去別處逛逛吧',

    this.errorMsg='',
    this.errorHidden=true,

    this.loadmoreMsg='加載中...',
    this.loadmoreHidden=true,
}
 

頁面js里的使用:



Page(
    data: {
      title:'名師',//todo 設(shè)置標(biāo)題欄
      emptyMsg:'暫時(shí)沒有內(nèi)容,去別處逛逛吧',//todo 空白頁面的顯示內(nèi)容
      netStateBean: new netUtil.netStateBean(),
      ...
      },
      ...
    )
 

wxml里:模板


    <template name="pagestate" >
        <view class ="empty_view" wx:


易優(yōu)小程序(企業(yè)版)+靈活api+前后代碼開源 碼云倉庫:starfork
本文地址:http://22321a.com/wxmini/doc/course/22962.html 復(fù)制鏈接 如需定制請(qǐng)聯(lián)系易優(yōu)客服咨詢:800182392 點(diǎn)擊咨詢
QQ在線咨詢