微信小程序开发遇坑记

  1. 小程序是什么?
  • 腾讯微信端的类原生app开发,用一堆腾讯写的组件和自己造一些组件,进行app开发吧。
  1. 第一个小程序
  • 之前,自己在下班之后和周末的时候,敲代码吧。搞了一阵子的小程序,其实就是做了个音乐播放器Music Player,这个播放器最关键的是歌词的加载吧。毕竟都是要进行计算才可以的。
  1. 进公司的第一个小程序
  • 好吧,也不是一个完整的小程序,就其中的一部分,写了几个组件。然后2018,1,22上线了。
  1. 介绍之后,开始说自己的踩坑之际
  • 名片管理:原理很简单,用户输入信息和上传头像到名片模板中,形成个人名片。在点击按钮,进行下载。名片就保存到相册中了。
  • 坑:后台不能单独地传一张含有用户信息地名片的链接,让我进行调用下载。原因是服务器难做。好吧,毕竟不是专业后台,我也说不了什么。所以名片下载的功能由我来开发。进公司看了一个礼拜的文档,然后接手。心里有点忐忑吧,毕竟后台搞不定。然后在接手的时候,就说我试试看一两天行不行,不行就算了。原因你懂的。毕竟用canvas进行画图,在形成图片,这行不行我也不知道。动手撸起来。
  • 还是看文档,看到文档中的canvas部分,和进行google来问问看别人怎么做的。
  • 过程,发现自己的表达和书写能力还是不行啊。还是写代码吧
  1. 调用wx.createCanvasContext(canvasId, this),形成画布,记得要保存执行上下文的统一,即this,
    同时要保存画布大小跟屏幕一致
      setPixel() {
        const {
          windowWidth,
          windowHeight
        } = wx.getSystemInfoSync();
        // 设置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. 调用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. 调用canvasContext.fillText进行文字书写。
  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. 然后画好了,开始要导出来。这个时候记得使用jpg格式,因为png,导出来是背景透明的。使用的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: "导出图片失败,请稍后在尝试"
              });
              rej("导出图片失败,请稍后在尝试");
            }
          });
        });
      },
  1. 在调用wx.saveImageToPhotosAlbum(OBJECT),将图片保存到手机中去。(当图片为竖版的时候,导出的时候会变大,需要在相册中对图片先用手放大,然后在缩小,这样就显示正常了,本来想多加些空白距离,但是设计稿。。所以没有办法了。
 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: "名片导出失败,请稍后在尝试"
            })
        });
      },
  1. 使用了promise和async和await。毕竟要画名片,肯定要知道相关信息和图片资源。在这里写的时候,要将图片资源先下载下来,在进行绘制。使用的api是wx.downloadFile,这样得到图片资源,然后使用wx.getImageInfo得到图片的信息,主要宽高,因为说说是画上去,其实还是算上去的。(考虑到rpx和px的转化,还得写两个转化函数),毕竟有些api要求的单位不一样。。。贼烦的换算。。记得我们的名片要得到信息才能输出名片,所以都是在调用接口,和我不知道微信哪些方法是异步的。毕竟文档没有提,然后就使用async,用promise包装一下绘制的操作。等到所有的绘制完成,返回文件地址,进行下载。(不得不说promise真的强大)
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. 竖版好画,横板难画,空间的换算。好吧,我承认自己有点辣鸡。。。算了大半天才换算对的。。还是要多计算啊。这个不好说。看官自己去换算吧。
    坑:对的,记得有时候一行信息来自两段文字,所以要画的时候,考虑到前一段文字对后一段文字的影响,然后又要加个函数
  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());
          // 计算文字距离 去掉空格和|所占据的空间
          console.log('length',text.length,'ddd',this.pxToRpx((text.length - 2) * arr));
          resolve(this.pxToRpx((text.length - 2) * arr));
        });
      },
   // 函数调用
   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. 有时候我们习惯写color:red;但是微信没有这样的api啊。所以使用ctx.fillStyle('color'),ctx,fillRect(x,y,w,h)来进行文字的上色
 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. 画布中无法对字体进行font-weight,所以 多次绘制文字,注意距离。
  2. 还有就是说好的vue的计算属性可以使用呢?然后被大佬吐槽死了,还是在进行复杂运算的时候进行使用吧。有时候自己真的手贱。真的怎么爽怎么来。。。然后今天一堆bug,要上线来一堆bug。mmp。
  3. 所有的元素最好都要包裹在一个元素中去。// vue的语法。😔有时候切不回来是真的麻瓜。
  4. 转发功能,怎么说呢,写慢点。主要看同事都在等自己,才能下班。心急,打错大小写。。
  5. 还有就是微信的wx.request的get请求还是按照格式来,不然小程序会对其中进行改变,然后出错。// 公司的编译器在智能点就无敌了。// 虽然看了部分代码。还是要多学习啊
  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. 然后在绘制过程中,要考虑到两段文字要显示在一行。(昨天在随便玩的时候发现的),后一段文字的位置是根据前一段文字来显示的,不是固定的。所以又要计算,微信有个api是设置字体大小的canvasContext.setFontSize,但是应该是px,没有仔细研究过。毕竟一堆报错等我去解决。幸好有同事的帮忙,不然就炸了。这个时候,又是rpx跟px的换算。然后发现数字跟文字显示不一样。原因待我更新。解决了,看上面的7中的横版。
  2. 少发请求。今天有一个函数写的不好。真的,是因为,当时没有考虑太多,是按照文档的思路写下来的。然后自己写完,丢测试,看看有没有完美实现功能,就没有考虑太多的性能优化的事情。好吧,有考虑到,但是是考虑使用debounce,strolltetimg这样的函数去完成。。然后在同事的提醒下,发现写法不行。虽然自己总结了性能优化的文章,但是哎还是实践的少啊。
    Update:要实时响应的。mmp。被人怼的时候,就忘记了。坚持主见啊。
  3. 幸好今天能上线了。算是自己第一个正式的小程序吧,虽然只是一部分。
  4. 明天还是要修前同事的bug,和看rxjs。rxjs学习好难。。。。。。
  5. 函数式编程看了一些,不得不承认,看懂的少啊,还是要多滚文档啊。react全家桶去实现vue社区2.0还没有做完啊。
  6. 今天碰到的bug都是自己编程过程中第一次碰见的。vue:the infinite update loop 的问题,少了个整个包裹的div。
  7. style 要加scope。 同时当样式显示不对的时候,要考虑到是不是样式冲突了。今天是真的急啊。谁知道上线的今天会出现这么多bug。。。
  8. 幸好四阿哥,哈哈

Update 1.25

  • 好吧,昨天又遇见坑。客户反应名片下载不下来,测试反馈给我,我当然火急火燎地去修bug了。不修还好,一修理就感觉代码逻辑不满意,然后重写代码过程,其中发现自己对promise的特性还是使用不行,简单而言,没有完全搞懂。
  • Promise 是一种承诺,是一种面对未来发现而进行的提前编程。一共有三种状态:padding,resolve,reject。其中对reject的使用不当,其reject出来的东西,应该是被catch所捕捉到的,这点在昨天的编程中忘记了。。。简直麻瓜,
  • 有时候一份代码反复编写测试,有问题在修改,就自己而言是很难受的,这就要求自己要在编写过程中更多的思考,但是自己基本提交测试的代码是自己写的满意才提交的,但是还有问题。这就说明,就小程序而言,我文档还是啃得不熟悉,然后继续啃文档,多啃小程序上线的配置代码。
  • 流程问题,往往写完要给发布测试环境的人员,然后其在转发给正式发布人员,然后测试人员进行测试,然后问题在反馈给我。一个小问题,然后就倒霉了,以前都是自己搞得,所以改起来快,现在只能一步步来,一些小问题不得不让自己烦躁,毕竟一遍遍地滚流程是对自己的折磨,自我感觉。
  • 结论:重写所有的逻辑,然后线上还是报错。当时崩溃,然后测试说有可能token失效,然后大佬问起来我canvas是要下载画图的,告诉我有可能客户的域名没有配置。现在坐等结果。

Update 1.27

问了测试,客户没有说,测试那就说ok,那就ok吧。。。蛋疼,也不知道ok不ok

Update 2019.5.22

在修改别人的小程序的过程中,发现一个现象。

Page({

 /**
  * 页面的初始数据
  */
 data: {
     page:0},
})
handleClick(e){
 this.data.page+=1;} // 这里会直接改变data中的page,而不是通过this.setData({page:this.data.page+1})来改变,这个刚看见的时候我还以为是错的。现在才发现是可以的,还是too young了。然后翻下小程序论坛,说setData是唯一的视图和数据的通信接口。毕竟是数据驱动视图

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容