微信小程序開發(fā)遇坑記

  1. 小程序是什么?
  • 騰訊微信端的類原生app開發(fā),用一堆騰訊寫的組件和自己造一些組件,進(jìn)行app開發(fā)吧。
  1. 第一個小程序
  • 之前,自己在下班之后和周末的時候,敲代碼吧。搞了一陣子的小程序,其實就是做了個音樂播放器Music Player,這個播放器最關(guān)鍵的是歌詞的加載吧。畢竟都是要進(jìn)行計算才可以的。
  1. 進(jìn)公司的第一個小程序
  • 好吧,也不是一個完整的小程序,就其中的一部分,寫了幾個組件。然后2018,1,22上線了。
  1. 介紹之后,開始說自己的踩坑之際
  • 名片管理:原理很簡單,用戶輸入信息和上傳頭像到名片模板中,形成個人名片。在點擊按鈕,進(jìn)行下載。名片就保存到相冊中了。
  • 坑:后臺不能單獨地傳一張含有用戶信息地名片的鏈接,讓我進(jìn)行調(diào)用下載。原因是服務(wù)器難做。好吧,畢竟不是專業(yè)后臺,我也說不了什么。所以名片下載的功能由我來開發(fā)。進(jìn)公司看了一個禮拜的文檔,然后接手。心里有點忐忑吧,畢竟后臺搞不定。然后在接手的時候,就說我試試看一兩天行不行,不行就算了。原因你懂的。畢竟用canvas進(jìn)行畫圖,在形成圖片,這行不行我也不知道。動手?jǐn)]起來。
  • 還是看文檔,看到文檔中的canvas部分,和進(jìn)行g(shù)oogle來問問看別人怎么做的。
  • 過程,發(fā)現(xiàn)自己的表達(dá)和書寫能力還是不行啊。還是寫代碼吧
  1. 調(diào)用wx.createCanvasContext(canvasId, this),形成畫布,記得要保存執(zhí)行上下文的統(tǒng)一,即this,
    同時要保存畫布大小跟屏幕一致
      setPixel() {
        const {
          windowWidth,
          windowHeight
        } = wx.getSystemInfoSync();
        // 設(shè)置canvas跟屏幕一樣大小
        this.width = this.rpxToPx(700);
        this.height = this.rpxToPx(1040);
        const ctx = arguments[0];
        ctx.setFillStyle("white");
        ctx.fillRect(0, 0, this.width, this.height);
        ctx.draw();
      },
  1. 調(diào)用canvasContext.drawImage,貼圖片
downAndSetImage(ctx, url, arr) {
        // arr =[x,y,width,height]
        arr = this.rpxToPx(arr);
        ctx.draw(true);
        return new Promise((resolve, rej) => {
          wx.downloadFile({
            url: url,
            success: function(res) {
              let path = res.tempFilePath;
              // ctx.drawImage(path, arr[0], arr[1], arr[2], arr[3]); //還是以px為單位的。//換算
              ctx.save();
              ctx.drawImage(
                path,
                arr.shift(),
                arr.shift(),
                arr.shift(),
                arr.shift()
              ); //還是以px為單位的。//換算
              resolve(1);
              ctx.restore();
            },
            fail: () => {
              ctx.save();
              wx.showModal({
                title: "提示",
                content: `圖片獲取失敗`
              });
              ctx.restore();
              rej("圖片獲取失敗");
            },
          });
        });
      },
  1. 調(diào)用canvasContext.fillText進(jìn)行文字書寫。
  setText(ctx, text, arr) {
        // arr :[x,y,font-size]
        ctx.draw(true);
        arr = this.rpxToPx(arr);
        return new Promise((resolve, rej) => {
          arr.length == 2 ? ctx.setFontSize(14) : ctx.setFontSize(arr.pop());
          ctx.setFillStyle("black");
          ctx.setTextBaseline("top");
          ctx.fillText(text, arr.shift(), arr.shift());
          resolve(3);
        });
      },
  1. 然后畫好了,開始要導(dǎo)出來。這個時候記得使用jpg格式,因為png,導(dǎo)出來是背景透明的。使用的api:wx.canvasToTempFilePath(OBJECT, this)
   // output image path
      outputImage() {
        const ctx = arguments[0];
        const that = this;
        const {
          windowWidth,
          windowHeight,
          pixelRatio
        } = wx.getSystemInfoSync();
        return new Promise((resolve, rej) => {
          wx.canvasToTempFilePath({
            x: 0,
            y: 0,
            // width: 50,
            // height: 50,
            destWidth: pixelRatio * windowWidth, //canvas width*pixelRatio
            destHeight: pixelRatio * windowHeight,
            canvasId: "firstCanvas",
            fileType: "jpg",
            success: function(res) {
              resolve(res.tempFilePath);
            },
            fail: function() {
              wx.showModal({
                title: "提示",
                content: "導(dǎo)出圖片失敗,請稍后在嘗試"
              });
              rej("導(dǎo)出圖片失敗,請稍后在嘗試");
            }
          });
        });
      },
  1. 在調(diào)用wx.saveImageToPhotosAlbum(OBJECT),將圖片保存到手機(jī)中去。(當(dāng)圖片為豎版的時候,導(dǎo)出的時候會變大,需要在相冊中對圖片先用手放大,然后在縮小,這樣就顯示正常了,本來想多加些空白距離,但是設(shè)計稿。。所以沒有辦法了。
 saveCard() {
        const that = this;
        const {
          windowWidth,
          windowHeight,
          pixelRatio
        } = wx.getSystemInfoSync();
        wx.canvasToTempFilePath({
          destWidth: pixelRatio * windowWidth, //canvas width*pixelRatio
          destHeight: pixelRatio * windowHeight,
          canvasId: "firstCanvas",
          fileType: "jpg",
          success: function(res) {
            wx.saveImageToPhotosAlbum({
              filePath: res.tempFilePath,
              success(res) {
                wx.showModal({
                  title: "提示",
                  content: "名片保存到相冊成功"
                });
              },
              fail() {
                wx.showModal({
                  title: "提示",
                  content: "名片保存失敗,請稍后在嘗試!"
                });
              },
              complete() {
                console.log("completed");
              }
            });
          },
          fail: () =>
            wx.showModal({
              title: "提示",
              content: "名片導(dǎo)出失敗,請稍后在嘗試"
            })
        });
      },
  1. 使用了promise和async和await。畢竟要畫名片,肯定要知道相關(guān)信息和圖片資源。在這里寫的時候,要將圖片資源先下載下來,在進(jìn)行繪制。使用的api是wx.downloadFile,這樣得到圖片資源,然后使用wx.getImageInfo得到圖片的信息,主要寬高,因為說說是畫上去,其實還是算上去的。(考慮到rpx和px的轉(zhuǎn)化,還得寫兩個轉(zhuǎn)化函數(shù)),畢竟有些api要求的單位不一樣。。。賊煩的換算。。記得我們的名片要得到信息才能輸出名片,所以都是在調(diào)用接口,和我不知道微信哪些方法是異步的。畢竟文檔沒有提,然后就使用async,用promise包裝一下繪制的操作。等到所有的繪制完成,返回文件地址,進(jìn)行下載。(不得不說promise真的強(qiáng)大)
async getCanvas() {
        const arg = arguments[0];
        await this.setPixel.call(null, arg);
        // 顯示loading
        wx.showLoading({
          title: "繪制中,請稍等"
        });
        //code
        await this.downAndSetImage(arg, this.code, [500, 111, 180, 180]);
        //company
        await this.setText(arg, this.userInfo.company.companyName, [33, 218]);
        ...差不多就這樣
  1. 豎版好畫,橫板難畫,空間的換算。好吧,我承認(rèn)自己有點辣雞。。。算了大半天才換算對的。。還是要多計算啊。這個不好說??垂僮约喝Q算吧。
    坑:對的,記得有時候一行信息來自兩段文字,所以要畫的時候,考慮到前一段文字對后一段文字的影響,然后又要加個函數(shù)
  dynamicSetTextColor(ctx, text, arr, color) {
        // arr :[x,y,font-size]
        arr = this.rpxToPx(arr);
        return new Promise((resolve, rej) => {
          !arr.length == 3 ? ctx.setFontSize(18) : ctx.setFontSize(arr[2]);
          !color ? ctx.setFillStyle("black") : ctx.setFillStyle(color);
          ctx.draw(true);
          ctx.setTextBaseline("top");
          ctx.fillText(text, arr.shift(), arr.shift());
          // 計算文字距離 去掉空格和|所占據(jù)的空間
          console.log('length',text.length,'ddd',this.pxToRpx((text.length - 2) * arr));
          resolve(this.pxToRpx((text.length - 2) * arr));
        });
      },
   // 函數(shù)調(diào)用
   await this.dynamicSetTextColor(
          arg,
          `${this.userInfo.user.userName} |`, [469, 197, 40],
          "#338BF5"
        ).then(r => {
          // r是距離
          that.setText(arg, that.userInfo.user.positionName, [r + 475, 205, 28]);
        });

  1. 一定要使用draw(true),restore,防止一次出錯,畫布崩潰。
  2. 有時候我們習(xí)慣寫color:red;但是微信沒有這樣的api啊。所以使用ctx.fillStyle('color'),ctx,fillRect(x,y,w,h)來進(jìn)行文字的上色
 setTextColor(ctx, text, arr, color) {
        // arr :[x,y,font-size]
        arr = this.rpxToPx(arr);
        return new Promise((resolve, rej) => {
          !arr.length == 3 ? ctx.setFontSize(18) : ctx.setFontSize(arr[2]);
          !color ? ctx.setFillStyle("black") : ctx.setFillStyle(color);
          ctx.draw(true);
          ctx.setTextBaseline("top");
          ctx.fillText(text, arr.shift(), arr.shift());
          resolve(3);
        });
      },
  1. 畫布中無法對字體進(jìn)行font-weight,所以 多次繪制文字,注意距離。
  2. 還有就是說好的vue的計算屬性可以使用呢?然后被大佬吐槽死了,還是在進(jìn)行復(fù)雜運算的時候進(jìn)行使用吧。有時候自己真的手賤。真的怎么爽怎么來。。。然后今天一堆bug,要上線來一堆bug。mmp。
  3. 所有的元素最好都要包裹在一個元素中去。// vue的語法。??有時候切不回來是真的麻瓜。
  4. 轉(zhuǎn)發(fā)功能,怎么說呢,寫慢點。主要看同事都在等自己,才能下班。心急,打錯大小寫。。
  5. 還有就是微信的wx.request的get請求還是按照格式來,不然小程序會對其中進(jìn)行改變,然后出錯。// 公司的編譯器在智能點就無敵了。// 雖然看了部分代碼。還是要多學(xué)習(xí)啊
  6. 忘記最難的是畫頭像,mmp,傳的是正方形的頭像啊,要畫圓啊。還沒有border-radius:50%這樣的api使用。畫圓圈的思路:canvasContext.clip這個api,最難的是對中心點。具體的忘記了,明天在貼。因為google出來,別人也沒有告訴我怎么畫,都是自己琢磨出來的。。。
 avatar(ctx, url, arr) {
       arr = this.rpxToPx(arr);
       ctx.draw(true);
       return new Promise((resolve, rej) => {
         wx.downloadFile({
           url: url,
           success: function(res) {
             let path = res.tempFilePath;
             const r = 30;
             ctx.save();
             ctx.beginPath();
             ctx.arc(arr[0], arr[1], r, 0, 2 * Math.PI);
             ctx.clip();
             ctx.drawImage(path, arr[0] - r, arr[1] - r, arr[2] * 2, arr[3] * 2); //還是以px為單位的。//換算
             ctx.restore();
             resolve(1);
           }
         });
       });
     },
  1. 然后在繪制過程中,要考慮到兩段文字要顯示在一行。(昨天在隨便玩的時候發(fā)現(xiàn)的),后一段文字的位置是根據(jù)前一段文字來顯示的,不是固定的。所以又要計算,微信有個api是設(shè)置字體大小的canvasContext.setFontSize,但是應(yīng)該是px,沒有仔細(xì)研究過。畢竟一堆報錯等我去解決。幸好有同事的幫忙,不然就炸了。這個時候,又是rpx跟px的換算。然后發(fā)現(xiàn)數(shù)字跟文字顯示不一樣。原因待我更新。解決了,看上面的7中的橫版。
  2. 少發(fā)請求。今天有一個函數(shù)寫的不好。真的,是因為,當(dāng)時沒有考慮太多,是按照文檔的思路寫下來的。然后自己寫完,丟測試,看看有沒有完美實現(xiàn)功能,就沒有考慮太多的性能優(yōu)化的事情。好吧,有考慮到,但是是考慮使用debounce,strolltetimg這樣的函數(shù)去完成。。然后在同事的提醒下,發(fā)現(xiàn)寫法不行。雖然自己總結(jié)了性能優(yōu)化的文章,但是哎還是實踐的少啊。
    Update:要實時響應(yīng)的。mmp。被人懟的時候,就忘記了。堅持主見啊。
  3. 幸好今天能上線了。算是自己第一個正式的小程序吧,雖然只是一部分。
  4. 明天還是要修前同事的bug,和看rxjs。rxjs學(xué)習(xí)好難。。。。。。
  5. 函數(shù)式編程看了一些,不得不承認(rèn),看懂的少啊,還是要多滾文檔啊。react全家桶去實現(xiàn)vue社區(qū)2.0還沒有做完啊。
  6. 今天碰到的bug都是自己編程過程中第一次碰見的。vue:the infinite update loop 的問題,少了個整個包裹的div。
  7. style 要加scope。 同時當(dāng)樣式顯示不對的時候,要考慮到是不是樣式?jīng)_突了。今天是真的急啊。誰知道上線的今天會出現(xiàn)這么多bug。。。
  8. 幸好四阿哥,哈哈

Update 1.25

  • 好吧,昨天又遇見坑??蛻舴磻?yīng)名片下載不下來,測試反饋給我,我當(dāng)然火急火燎地去修bug了。不修還好,一修理就感覺代碼邏輯不滿意,然后重寫代碼過程,其中發(fā)現(xiàn)自己對promise的特性還是使用不行,簡單而言,沒有完全搞懂。
  • Promise 是一種承諾,是一種面對未來發(fā)現(xiàn)而進(jìn)行的提前編程。一共有三種狀態(tài):padding,resolve,reject。其中對reject的使用不當(dāng),其reject出來的東西,應(yīng)該是被catch所捕捉到的,這點在昨天的編程中忘記了。。。簡直麻瓜,
  • 有時候一份代碼反復(fù)編寫測試,有問題在修改,就自己而言是很難受的,這就要求自己要在編寫過程中更多的思考,但是自己基本提交測試的代碼是自己寫的滿意才提交的,但是還有問題。這就說明,就小程序而言,我文檔還是啃得不熟悉,然后繼續(xù)啃文檔,多啃小程序上線的配置代碼。
  • 流程問題,往往寫完要給發(fā)布測試環(huán)境的人員,然后其在轉(zhuǎn)發(fā)給正式發(fā)布人員,然后測試人員進(jìn)行測試,然后問題在反饋給我。一個小問題,然后就倒霉了,以前都是自己搞得,所以改起來快,現(xiàn)在只能一步步來,一些小問題不得不讓自己煩躁,畢竟一遍遍地滾流程是對自己的折磨,自我感覺。
  • 結(jié)論:重寫所有的邏輯,然后線上還是報錯。當(dāng)時崩潰,然后測試說有可能token失效,然后大佬問起來我canvas是要下載畫圖的,告訴我有可能客戶的域名沒有配置。現(xiàn)在坐等結(jié)果。

Update 1.27

問了測試,客戶沒有說,測試那就說ok,那就ok吧。。。蛋疼,也不知道ok不ok

Update 2019.5.22

在修改別人的小程序的過程中,發(fā)現(xiàn)一個現(xiàn)象。

Page({

 /**
  * 頁面的初始數(shù)據(jù)
  */
 data: {
     page:0},
})
handleClick(e){
 this.data.page+=1;} // 這里會直接改變data中的page,而不是通過this.setData({page:this.data.page+1})來改變,這個剛看見的時候我還以為是錯的?,F(xiàn)在才發(fā)現(xiàn)是可以的,還是too young了。然后翻下小程序論壇,說setData是唯一的視圖和數(shù)據(jù)的通信接口。畢竟是數(shù)據(jù)驅(qū)動視圖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容