小程序開發技巧總結


0.小程序如何請求設置頭信息

由於在前一篇文章中寫過,這里就不重復了。參考下面這個鏈接:

ASP.NET WebAPI 雙向token實現對接小程序登錄邏輯

下面這個鏈接是參考資料,直接參考這一篇就明白怎么設置請求頭
jquery ajax 設置請求頭header參數

1. 微信小程序引用同一js文件中的方法函數(function)

如上圖紅色框所示,引用同一js文件中的函數不像普通js調用,需要加上下面代碼段加粗部分。(不知道在代碼段里面為什么不顯示粗體了,就是**這里)

onLoad: function (options) {
          **var that=this;**
          **this.loadList();**
    }, **loadList**:function(e){
    wx.request({
         url: app.globalData.apiurl + '/api/NoUploadBackBill',
         data: {
         mobile: app.globalData.phone,
         },
         header: {
        'content-type': 'application/json', // 默認值
        'Authorization': "BasicAuth " + util.getToken()
        },
        success(res) {
        console.log(res.data.length);
        }
       })
    },
    

2. 小程序中循環遍歷(即列表渲染)

我的需求是顯示返回的列表數據,頁面需要分條顯示。通常是要用js遍歷,但在小程序里面,只需要返回數據集,在wxml頁面用wx:for綁定數組即可顯示。如下圖所示,使用wx:for后沒有提供wx:key會報一個warning,在這小節后面第一個鏈接是官方的文檔,里面有提到【如不提供 wx:key,會報一個 warning, 如果明確知道該列表是靜態,或者不必關注其順序,可以選擇忽略。】

wxml頁面:
<view  wx:for="{{newBillList}}" wx:key="*this" class="list"></view>

該數組要在js文件的data內聲明。

js文件:
聲明:
data: {
    newBillList: [], //要顯示的列表以及搜索操作后的列表
  },
  
賦值:
 loadList: function(e) { //發起請求,根據手機號加載未上傳回單
    wx.request({
      url: app.globalData.apiurl + '/api/NoUploadBackBill/Loading',
      data: {
        mobile: app.globalData.phone,
      },
      header: {
        'content-type': 'application/json', // 默認值
      },
      success: res => {
        if (res.data.length > 0) {
          var list = [];
          for (var i = 0; i < res.data.length; i++) {
            res.data[i].ImageList = [];
            list.push(res.data[i]);
          }
          this.setData({
            billList: list,
            **newBillList: list**
          });
        }
      },
      fail(res) {
        console.log("loadList fail:" + res.data);
      }
    })
  }

小程序-視圖層-WXML-列表渲染

小程序for循環

3. 小程序js傳遞多個參數

小程序的js里面和通用的js傳參一樣,通過全局變量傳遞,或函數參數傳遞。

     //調用處理列表圖片的方法
        this.addImageList(1, 0);
    
    //重新處理數據,把圖片列表加入
    addImageList: function (type, count) {}

4. this.setData is not a function

Page.prototype.setData(Object data, Function callback)

在微信小程序中,一般通過this.setData來修改值。比如在函數里面修改數據,如下代碼段所示:search要在data內初始化

    searchinput: function (e) {//查詢輸入框賦值
    this.setData({
      search: e.detail.value
    })
  }

但是,當通過wx.request請求數據成功后綁定數據卻出現this.setData is not a function的錯誤。

    //發起請求,根據手機號加載未上傳回單
    wx.request({
      url: app.globalData.apiurl + '/api/NoUploadBackBill',
      data: {
        mobile: app.globalData.phone,
      },
      header: {
        'content-type': 'application/json', // 默認值
      },
      success(res) {
        console.log(res.data);
         if(res.data.length>0){
           this.setData({
             billList: res.data
           });
         } 
      },fail(res){
        console.log("fail"+res);
      }
    })

為什么會出現這個error呢,我當時百思不得其解,也沒有想到作用域這一層,是查找資料才解決該問題。

原因是因為:因為this作用域指向問題 ,success函數實際是一個閉包 , 無法直接通過this來setData。

第一種方法:
var that=this;
this.setData({billList:res.Data});
第二種方法:
success:res=>{
     this.setData({billList:res.data})
   }

具體原因要參考這個鏈接

參考資料:微信小程序中this指向作用域問題this.setData is not a function報錯

5. 小程序點擊控件隱藏一個View,顯示另一個View

隱藏和顯示,一定明白是用樣式控制了。而且是在JS控制樣式,代碼段如下:

 wxml頁面:
 <view  wx:for="{{billList}}" wx:key="*this" class="list" style="display:{{billdisplay}};" >
  /**
   * 頁面的初始數據
   */
  data: {
    **billdisplay**:'block',//回單列表是否顯示
    **searchdisplay**:'none'//查詢列表是否顯示
  },
   searchList:function(e){//搜索事件
     var _this=this;
    //設置首次加載的回單列表隱藏,顯示查詢的列表
     _this.setData({
       billdisplay:'none',
       searchdisplay:'block'
     });
      
  }

后記:當時因為想法不完整,所以把顯示數據列表用兩個View表示,用樣式控制,但其實這兩個View顯示的內容是一樣的。后來通過初始化兩個數組,一個顯示查詢后的列表,一個是原始數據的列表,用兩個數組通過在使用中重新push數據,這樣解決了用兩個view處理的冗余辦法。這個做法在第12點。

6. 小程序里push的用法

在小程序里面,在data里初始化的變量是無法直接push的。要在使用的時候另外聲明變量,push,最后再賦值。如下代碼段加粗部分(即有**的部分):

  //重新處理數據,把圖片列表加入
  addImageList: function (type, count) {
    var that = this;
    **var listArr = [];//聲明一個可操作變量數組**

    for (let i = 0; i < this.data.newBillList.length; i++) {
      if (this.data.shipmentid == this.data.newBillList[i].ShipmetId) {
        //累加上傳的回單
        var cnt = this.data.newBillList[i].DocumentsCnt;
        count=count+cnt;
        let row = {
          ShipmetId: this.data.newBillList[i].ShipmetId,
          EarliestPickTime: this.data.newBillList[i].EarliestPickTime,
          FromAddress: this.data.newBillList[i].FromAddress,
          ToAddress: this.data.newBillList[i].ToAddress,
          DriverName: this.data.newBillList[i].DriverName,
          LicenseNumber: this.data.newBillList[i].LicenseNumber,
          DocumentsCnt: type == 1 ? this.data.newBillList[i].DocumentsCnt : count,
          ImageList:this.data.imageListArr
        }
        **listArr.push(row);**
      } else {
        let row = this.data.newBillList[i];
        **listArr.push(row);**
      }
    }
    //賦值
    that.setData({
      //顯示列表
      **newBillList: listArr**
    });
  },

參考資料
小程序push數組報錯解決辦法

7. 小程序獲取view的ID

wxml頁面:
<button catchtap="removeImg" class="button_img" type="default" id="{{image}}"   data-shipmentid="{{item.ShipmetId}}">移除</button>
 js頁面:
 //直接獲取ID
 var viewId = e.target.id;
 console.log(viewId);
 //獲取data-shipmentid
 var shipmentid=e.target.dataset.shipmentid;
  console.log(shipmentid);

本來想貼一下官方的api有關e.target以及e.current.target的資料,但是忽然搜索不出來.....

8. 字符串拼接值(官方叫字符串運算)

這里比較簡單,又易理解,直接貼官方的代碼

<view>{{"hello" + name}}</view>
Page({
  data:{
    name: 'MINA'
  }
})

9. 引入util.js出錯



如上圖所示,我當前開發中的文件目錄如下:
pages/business/nouploadbackbill/nouploadbackbill,
我在js文件中引用util.js的時候,我以為可以這樣的:

const util = require('../../utils/util.js')

但是,實際上似乎要根據當前開發文件的目錄結構引用

//引用
const util = require('../../../utils/util.js')

不知道是不是這樣理解,如有誤導或錯誤請指正批評~

10. 小程序remove元素

沒有remove,沒法remove,只能通過操作數組處理。代碼段參考第6點以及第12點

11. 小程序獲取上級元素

當時的問題是這樣的,因為有一個view有id,然后view里有一個button,這個button事件需要取到view的id進行移除操作,需要標識是移除哪一個view。
但是后現發現,view可以不用給id屬性,button可以直接給id屬性,直接用它自己的id值判斷就可以操作。
代碼參考第7點。

12. 小程序所有頁面路徑都要放在app.json

當時我以前在app.json文件配置的都是主頁。主頁里面跳轉的頁面不必配置。直到報錯才知道所有頁面都要放在app.json里面配置。不然運行的時候會報not in app.json。如下圖所示:

13. 小程序操作動態循環的數據

因為顯示列表里面還有一個圖片列表的數組,該列表有一個上傳圖片和移除圖片操作,上傳圖片就把圖片push到這個圖片數組,然后重新push列表顯示,移除也一樣,把要移除的圖片從列表里排除,重新push列表顯示。

以下這段代碼非常重要!因為正是看到了以下這段代碼,我遇到的難題得以解決,感恩遇見,哈哈

由於這個鏈接是在小程序社區看到的,所以兩個鏈接都貼出來,參考鏈接如下:

for (var i = 0; i < this.data.newBillList.length; i++) {
      if (e.target.dataset.id == this.data.newBillList[i].shipmentid) {
        newBillList[i] = {
          id: this.data.newBillList[i].id,
          price: this.data.newBillList[i],
          one2one: this.data.newBillList[i],
        }
      } else {
        txtArray1[i] = {
          id: this.data.liuliangItems[i].id, changeColor: false,
          price: this.data.liuliangItems[i].price, name: this.data.liuliangItems[i].name,
          one2one: this.data.liuliangItems[i].one2one
        }
      }
    }

小技巧系列

微信小程序點擊button或view后選中其它反選

我的數據有三次循環量,因為在從一個循環列表里面操作兩個循環。暫且說它是復合循環吧。當時困我好多天的難題用以下這段代碼解決,快誇我~哈哈

//移除圖片,按id移除
  removeImg: function(e) {
    var that = this;
    var listArr = [];
    var imgArr = [];
    for (var i = 0; i < this.data.newBillList.length; i++) {
      if (e.target.dataset.shipmentid == this.data.newBillList[i].ShipmetId) { //相等的當前選中的數據,移除列表的圖片的需要重新組合數據
        for (var j = 0; j < this.data.newBillList[i].ImageList.length; j++) {
          //第一種寫法
          if (e.target.id != this.data.newBillList[i].ImageList[j]) { //相等的值是要移除的值,不作處理
            imgArr.push(this.data.newBillList[i].ImageList[j]); //重新push圖片

          }
          //第二種寫法,es6的寫法
          //let id = e.target.id;
          //this.data.newBillList[i].ImageList[j].splice(id,1);//刪除 //splice(index,count) 第一個參數是索引,第二個參數是刪除的個數

        }
        //把數據重新push
        var row = {
          ShipmetId: this.data.newBillList[i].ShipmetId,
          EarliestPickTime: this.data.newBillList[i].EarliestPickTime,
          FromAddress: this.data.newBillList[i].FromAddress,
          ToAddress: this.data.newBillList[i].ToAddress,
          DriverName: this.data.newBillList[i].DriverName,
          LicenseNumber: this.data.newBillList[i].LicenseNumber,
          DocumentsCnt: this.data.newBillList[i].DocumentsCnt,
          ImageList: imgArr
        }
        listArr.push(row);
      } else { //數據不變的是不用處理的列表塊,直接push
        var row = this.data.newBillList[i];
        listArr.push(row);
      }
    }

14. 小程序上傳文件wx.uploadFile

這一部分被我形容是第二難題。(當然,是針對我在自己當前開發的功能里面~)
這里分為幾個部分:

 wx.chooseImage({
      count: this.data.count[this.data.countIndex],
      sizeType: ['original', 'compressed'],
      sourceType: ['album', 'camera'],
      success: res => {
        // tempFilePath可以作為img標簽的src屬性顯示圖片
        this.setData({
          shipmentid: e.target.dataset.shipmentid,
          imageListArr: res.tempFilePaths
        })
        //調用處理列表圖片的方法
        this.addImageList(1, 0);//該函數完整代碼在第6點
      },
      fail: function(data) {
        wx.showToast({
          title: "選擇圖片出錯",
          icon: "none",
          duration: 1000
        });

      }
    });
 //預覽圖片
  previewImage: function(e) {
    let current = e.target.dataset.src;
    let imageList = [];
    for (let i = 0; i < this.data.newBillList.length; i++) {
      if (e.target.dataset.shipmentid == this.data.newBillList[i].ShipmetId) {
        imageList = this.data.newBillList[i].ImageList;
      }
      wx.previewImage({
        current: current, //當前顯示圖片的鏈接
        urls: imageList //需要預覽的圖片鏈接列表
      })
    }
  },

這里要說一下,我這邊的需求是先把圖片上傳到開發者服務器,然后再從開發者服務器把圖片讀取保存到另一個系統所在的服務器上。讀取圖片的時候不用下載圖片,我上傳圖片的時候會在數據庫一個表保存圖片的相關信息,列表id,圖片名稱,在開發者服務器的所在路徑等一些相關用到的字段。

第一步:先上傳圖片到開發者服務器,客戶端發起一個 HTTPS POST 請求,其中 content-type 為 multipart/form-data

//上傳圖片,將本地資源上傳到開發者服務器
  uploadImage: function(e) {
    var that = this;
    that.setData({
      shipmentid: e.target.dataset.shipmentid
    });
    var listArr = [];
    var uploadImgCount = 0;
    var uploadArr = [];
    var imgLength = 0;
    for (var i = 0; i < this.data.newBillList.length; i++) {
      if (e.target.dataset.shipmentid == this.data.newBillList[i].ShipmetId) {
        imgLength = this.data.newBillList[i].ImageList.length;
        var index = i;
        console.log("列表的待上傳的回單數:" + imgLength);
        if (imgLength < 1) {
          wx.showToast({
            title: '沒有可上傳的回單',
            icon: 'none',
            mask: true,
            duration: 1000
          });
          var row = this.data.newBillList[i];
          listArr.push(row);
        } else {
          //啟動上傳等待中...
          wx.showToast({
            title: '正在上傳...',
            icon: 'loading',
            mask: true,
            duration: 10000
          });
          //遍歷圖片列表上傳
          for (var j = 0; j < this.data.newBillList[i].ImageList.length; j++) {
            //記錄當前列表的索引,因為到了success里就獲取不到啦
            var index = i;
            //上傳圖片到開發者服務器
            wx.uploadFile({
              url: app.globalData.apiurl + '/api/NoUploadBackBill/PostImageFile',
              filePath: this.data.newBillList[i].ImageList[j], //要上傳文件資源的路徑
              name: 'image', // 這里的具體值,要與后台保持一致
              header: {
                'content-type': 'multipart/form-data',
                'Authorization': "BasicAuth " + util.getToken()
              },
              formData: { //HTTP 請求中其他額外的 form data
                'shipmentid': this.data.shipmentid,
                'imgIndex': j //上傳的圖片編號(后台提供給前端判斷圖片是否全部上傳完)
              },
              success: res => {
                //console.log("res:"+res.data);
                uploadImgCount++;
                uploadArr.push(res.data);

                //判斷是否上傳完畢
                if (uploadImgCount == imgLength) {

                  //顯示數據,調用處理列表圖片的方法,只修改所選運單的回單數即可
                  this.addImageList(2, uploadImgCount);
                  //保存操作的列表數到TMS數據表
                  let row = {
                    ShipmetId: this.data.newBillList[index].ShipmetId,
                    EarliestPickTime: this.data.newBillList[index].EarliestPickTime,
                    FromAddress: this.data.newBillList[index].FromAddress,
                    ToAddress: this.data.newBillList[index].ToAddress,
                    DriverName: this.data.newBillList[index].DriverName,
                    LicenseNumber: this.data.newBillList[index].LicenseNumber,
                    DocumentsCnt: uploadImgCount,
                    ImageList: uploadArr
                  }
                  this.setData({
                    saveImageList: row
                  });

                  //保存圖片到TMS
                  this.saveImage();

                }
              },
              fail: res => {
                console.log("uploadImage fail:" + res);
                wx.hideToast();
                wx.showModal({
                  title: '錯誤提示',
                  content: '上傳圖片失敗',
                  showCancel: false,
                  success: function(res) {}
                });

              }
            });
          }

        }

      }
    }
  }

這里大家一定很關心我的后台代碼是如何編寫的,我是參考第一個鏈接做的。

參考資料:
微信小程序實現圖片上傳功能

.NET WebAPI實現圖片上傳

第二步:把圖片從開發者服務器讀取並保存到另一個服務器

這里當時因為POST數據以及'content-type',還有JSON.stringify也卡住了好久(知識點不扎實)

//保存圖片
  saveImage: function(e) {
    //console.log("新json字符串:" + JSON.stringify(this.data.saveImageList));
    wx.request({
      url: app.globalData.apiurl + '/api/NoUploadBackBill/SaveImageFile',
      data: JSON.stringify(this.data.saveImageList),
      header: {
        'content-type': 'application/json',
        'Authorization': "BasicAuth " + util.getToken()
      },
      method: "POST",
      success: res => {
        console.log(" POST success:" + res.data.Message);
        if (res.data.Code == "0") {
          wx.showToast({
            title: '上傳成功',
            icon: 'none',
            mask: true,
            duration: 2000
          });
        } else {
          wx.showToast({
            title: '上傳圖片到服務器失敗:' + res.data.Message,
            icon: 'none',
            mask: true,
            duration: 2000
          });
        }
      },
      fail: res => {
        console.log("saveImage fail:" + res.data);
      }
    });
  },

這里大家一定也會關心數據的轉換,這里貼一下后台代碼:

    //接收參數為dynamic類型
    public IHttpActionResult SaveImageFile(dynamic obj){
   var s = JsonConvert.SerializeObject(obj);
   //實例化一個能夠序列化數據的類
   JavaScriptSerializer js = new JavaScriptSerializer(); 
   //將json數據轉化為對象類型
   var entity = js.Deserialize<NoUploadBackBillModel>(s);  
   }

還有數據讀取以及保存,這里使用文件流FileStream處理,從圖片轉換為二進制流讀取,這里是調用web service處理的。具體代碼不在我這邊,就沒有辦法貼出來啦~

參考鏈接:
WebAPI 接口參數

15. WebAPI 找到了與該請求匹配的多個操作

找到了與該請求匹配的多個操作的解決辦法

WebApi 找到了與該請求匹配的多個操作

WebAPI post傳遞參數2、實體作為參數

16. 小程序自適應單位rpx

這個rpx我原來不知道是微信小程序推出了新尺寸單位。直到我做完功能測試發現沒有自適應。因為我在里面慣性使用了px和em。后來看這個參考鏈接就全部改過來了,然后頁面在不同的設備不會溢出啦。參考鏈接如下:

細解小程序自適應單位rpx

最后,想說所遇到的問題點幾乎都經過查閱資料解決。在知識紅利的時代,大家無私分享自己的所學,在此非常感謝分享開發總結的伙伴。誠摯感謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM