微信小程序开发一些经验

微信小程序

对于微信小程序开发入门,仍是比较简单的,只须要具有基本的css+js知识就能够了,成本比较低。 写了小程序和RN以后,有一种原生很笨重的感受,就是小程序或者是RN等这些新的开发方式在效率上面真的有比较大的优点,惟一不足就是运行速度了(使用Canvas就会有这样子的感受)。 感受目前所接触的种类前端开发(包括移动端),都是基本一个套路:UI,网络,数据保存,富文本,图片/视频。 本文也是从这几个方向去总结本身的小程序开发经验。css

小程序的入门

其实小程序的开发过程一直都是查看文档,按照文档去操做就能够了。 通常流程是先看简易教程。看完以后,再去看组件。以后能够开始尝试写需求,这个过程当中,开始不断的去查API框架便可。html

多列列表

在开发中,有一个需求是须要实现相似Android的GridView网格列表的。可是微信中并无提供这样子的组件,可是小程序是跟html/css前端很相似的,他能够经过指定display:flex,而后去设置flex-wrap:wrap就能够。例如,有一个数组data:["A","B","C","D","E","F","G","H","I","J","K","L","M","N"]须要显示为一个三列的列表,能够以下处理:前端

//GridPage.wxml
<view class='grid-container'>
  <view wx:for="{{data}}" wx:key="{{item}}" class="grid-list">
  <view class='grid-item'>
  <text class='grid-item-text'>{{item}}</text>
  </view>
  </view>
</view>

//GridPage.wxss
Page {
  min-height: 100%;
  background-color: #fff;
}
.grid-container {
  margin-left: 4rpx;
  margin-right: 4rpx;
  display: flex;
  flex-wrap: wrap;
  flex-direction: row;
}
.grid-list {
  width: 33.33%;
}
.grid-item {
  margin: 2rpx;
  background: #999;
  display: flex;
  justify-content: center;
  align-items: center;
}
.grid-item-text {
  color: black;
}
复制代码

这里的重点就是grid-container中的flex-wrapwrap,方向是row了。而后他的每个item宽度都是33.33%。须要注意的是必定是去设置外部的contanier而不是内部的list。node

层级布局

在CSS中,须要使用层级布局,就是相似Android的FrameLayout效果,可使用z-index,也可使用一个绝对定位。好比,咱们有一个需求是:下面是一个图片,上面是文字。算法

//PositionPage.wxml
<view class='root'>
<image src='https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3756982450,995202616&fm=27&gp=0.jpg' class='image'></image>
<text class='text'>我是权律二啊</text>
</view>
//PositionPage.wcss
.root{
  align-items: center;
  display: flex;
  flex-direction: column;
  position: relative;
}
.image{
  width: 300rpx;
  height: 300rpx;
}
.text{
  background-color: #999;
  position: absolute;
}
复制代码

主要是两点:父布局的position必须是relative,它自己position必须是absolutejson

网络请求

小程序的网络请求是使用wx.request()方法,可是该方法太臃肿,并无使用Promise那样子简洁。幸运的是小程序支持Promise,因此咱们能够把http封装一下,变成有条理。说到这里,你们作的时候须要注意去微信后台配置各类request域名,upload域名,downloadFIle域名。 下面封装的例子的数据返回格式都是json格式post请求方式发出的:canvas

//真正发起请求
function _request(url, param) {
    if (isDebug) {
        Log.i("http==> params->" + JSON.stringify(param));
        Log.i("http==> url->" + url);
    }
    return new Promise((resolve, reject) => {
        wx.request({
            url: url,
            data: param,
            header: {
                'content-type': 'application/json',
                "Accept": "application/json"
            },
            method: "POST",
            success: function (response) {
                if (isDebug) {
                    const jsonResponse = JSON.stringify(response);
                    Log.i("http==> response->" + jsonResponse);
                }
                const {data, statusCode, ok = false} = response;
                //只有ok为true的是时候才返回成功,data不必定是包含数据的
                if (statusCode === 200 && data && data.ok) {
                    resolve(data, ok);
                } else {
                    if (statusCode != 404 && statusCode < 500 && statusCode > 300) {
                        ToastUtil.showError();
                    }
                    reject(data);
                }
            },
            fail: reject
        });
    });

}
复制代码

使用:小程序

function getInfo(fid) {
    const params = {};
    params.token = user.token;
    params.uid = user.uid;
    return _request("INFO_URL", params);
}
复制代码

而后须要发起请求就调用该方法便可,处理Promise。微信小程序

上传图片到阿里云

须要注意微信upload接口配置目前好像不能够直接配置阿里云的URL,须要阿里云先 跟咱们的域名绑定,以后再去把设置到微信后台的upload接口中。能够参考博客:小程序图片上传阿里OSS使用方法,获取签名阿里云Demo地址:JavaScript客户端签名直传,经过打log得到policy和signature(签名时间能够稍微设置久一点)以后,就开始封装upload方法了。 以下:api

/**
    * 真实上传代码
    */
    function _upload(file, success, fail) {
        const suffix = file.substring(file.lastIndexOf("."));
        //作一下md5处理
        const fileName = hex_md5(file);
        Log.i("fileName=" + (fileName + suffix));
        wx.uploadFile({
            url: ALIYUNPHOTOADDRESS,
            formData: {
                "OSSAccessKeyId": "你的阿里云accessKey",
                "key": DIR+ (fileName + suffix),
                "policy": "你的policy",
                "success_action_status": '200',
                "signature": "你的signature"
            },
            filePath: file,
            name: 'file',
            success: function (res) {
                const {statusCode} = res;
                if (statusCode === 200) {
                    console.log(JSON.stringify(res));
                    success("" + fileName + suffix);
                } else {
                    console.log("上传失败");
                    fail(res);
                }
            },
            fail: function (e) {
                fail(e);
                console.log("上传失败");
                console.log("e=" + JSON.stringify(e));
            }, complete: function () {
                console.log("上传过程结束");
            }
        })
    }

}
复制代码

其中url是上传OOS的地址,key是须要上传的文件夹+上传以后的文件名。这里的fileName咱们经过一个md5去计算得来,保证惟一性又没有什么特殊字符。md5的算法来自JS-MD5加密

咱们能够顺带封装一个上传多张图片的方法,并且使用Promise返回:

/**
* files须要上传的文件,是一个数组,里面是文件的绝对路径
*/
function uploadFiles(files) {
  if (!files || files.length <= 0) {
    wx.showModal({
      title: '图片错误',
      content: '请重试',
      showCancel: false,
    });
    return Promise.reject();
  }
  Log.i("开始上传" + files);

  return new Promise((resolve, reject) => {
    //上传成功的文件名称
    let uploadPaths = [];
    for (let i = 0; i < files.length; i++) {
      _upload(files[i], (path) => {
        //成功的文件名
        uploadPaths[uploadPaths.length] = path;
        if (uploadPaths.length >= files.length) {
          //把url+name返回
          resolve([ALIYUNPHOTOADDRESS + "/" +DIR, uploadPaths]);
        }
      }, () => {
        //error
        reject(res);
      });
    }

  });
复制代码

Canvas使用

  • 因为须要使用Canvas画一棵树,因此仍是在这里走了比较多的坑的。个人需求是Canvas全屏,除了画一个树以外还须要画别的一些独立Button。 首先,设置Canvas全屏和不可滑动,能够经过如下方式:
<canvas  disable-scroll='true' style="width: {{width}}px; height: {{height}}px;background-color:#efeff4;flex:1;" canvas-id="canvas" bindtouchstart="touchStart" bindtouchmove="touchMove" bindtouchend="touchEnd"></canvas>
复制代码
  • 其中,在设置了disable-scroll设置为true,同时须要绑定三个touch事件,才能响应画布的触摸event。其中这里的width+height是经过wx.getSystemInfo()得到。
  • 其次,canvas没有相似View的catchtap事件,只有一些touch事件,详情能够看Canvas
  • 而后在微信小程序中Canvas是层级最高的,没法经过设置z-index去调,因此假如你的Canvas全屏,还须要一些其余的Button,那么只能经过最后canvas去draw了。
  • 在canvas中,假如经过moveTo+lineTo去画线,通常须要先调用canvas.beginPath()画完成以后,先调用canvas.stoke(),而后在调用canvas.closePath();
c.beginPath();
    c.setLineWidth(this.arrowPaint.width);
    c.setStrokeStyle(this.arrowPaint.color);
    c.setLineCap("square");

    c.moveTo(this.arrowStartPointF.x, this.arrowStartPointF.y);
    c.lineTo(this.arrowCenterPointF.x, this.arrowCenterPointF.y);
    c.moveTo(this.arrowCenterPointF.x, this.arrowCenterPointF.y);
    c.lineTo(this.arrowEndPointF.x, this.arrowEndPointF.y);
    c.stroke();
    c.closePath();
复制代码
  • 在连续画多种图片/线条的时候,不要连续屡次调用draw(true)方法, 消耗性能,通常最后调用fill()/stoke()方法便可。好比
//绘制点
        c.beginPath();
        let y = node.noteView.pointFrameCenter.y + Constant.FRAME_HEIGHT / 2 + Constant.GAP_BETWEEN_DOT + Constant.RADIUS_DOT;

        c.setFillStyle(Constant.LINE_COLOR_RED);
        c.setLineWidth(Constant.LINE_WIDTH);
        c.arc(node.noteView.pointFrameCenter.x, y, Constant.RADIUS_DOT, 0, 2 * Math.PI);

        //
        y += (Constant.GAP_BETWEEN_DOT + Constant.RADIUS_DOT);
        c.arc(node.noteView.pointFrameCenter.x, y, Constant.RADIUS_DOT, 0, 2 * Math.PI);
        //
        //
        y += (Constant.GAP_BETWEEN_DOT + Constant.RADIUS_DOT);
        c.arc(node.noteView.pointFrameCenter.x, y, Constant.RADIUS_DOT, 0, 2 * Math.PI);

        c.fill();
        c.closePath();
复制代码
  • 对于draw方法,建议只是调用draw()就好,不要调用draw(true)方法,draw(true)是在原画布之上再去画,不会清空旧画布,draw()会清空。通常,咱们会在全部的image,rectangle,line,circle去fill/stoke完以后,再调用draw()方法,这样子就能够避免draw(true)屡次,性能耗损。并且再次去reDraw的时候也不用先去清空画布。
  • Canvas的跟随手势拖动
//index.wxml
  <canvas disable-scroll='true' style="width: {{width}}px; height: {{height}}px;background-color:#efeff4;" canvas-id="canvas" bindtouchstart="touchStart" bindtouchmove="touchMove" bindtouchend="touchEnd"></canvas>
//index.wcss
Page {
  overflow: hidden;
  display: flex;
}
//index.js
const app = getApp()

Page({
  data: {
    width: 0,
    height: 0,
  },
  onLoad: function (e) {
    this.time = (new Date()).valueOf();
    this.x = 0;
    this.y = 0;
    this.moveX = 0;
    this.moveY = 0;

    const that = this;
    wx.getSystemInfo({
      success: function (res) {
        that.setData({ width: res.screenWidth, height: res.screenHeight })
      },
    })
    const ctx = wx.createCanvasContext("canvas", this)
    this.canvas = ctx;
  },
  onReady: function () {
    this.draw();
  },
  draw: function () {
    this.canvas.fillRect(10, 10, 150, 100)
    this.canvas.fill();
    this.canvas.draw()
  },
  touchMove: function (e) {
    console.log("touchMove")
    let xOffset = e.touches[0].x - this.x;
    let yOffset = e.touches[0].y - this.y;
    this.x = e.touches[0].x;
    this.y = e.touches[0].y;
    this.moveX = this.moveX + xOffset;
    this.moveY = this.moveY + yOffset;
    this.canvas.translate(this.moveX, this.moveY);
    this.draw();
  },
  touchStart: function (e) {
    this.x = e.touches[0].x;
    this.y = e.touches[0].y;
  },
  touchEnd: function (e) {
    console.log("touchEnd")
  }
})
复制代码

其余的scale等方法相似。

相关文章
相关标签/搜索