Bootstrap

微信小程序爬坑记录

微信小程序爬坑记录

开发微信小程序近两个月的小白,简单记录一下记忆比较深刻的坑

一 固定定位fixed

scroll-view下不能通过fixed进行固定定位,无法到达页面底部,使用view即可。

二 canvas

业务中需要实现这样一个效果


vantWeapp 中有一个Circle 环形进度条的组件

大家需要注意的是size默认单位为px 而不是rpx 也就是说不可以自适应 需要通过 wx.getSystemInfoSync().windowWidth获取设备宽度后根据当前宽度得出一个系数实现自适应 另外canvas 标签默认宽度300px、高度150px。

三 lottie-miniprogram

这绝对是一个大坑,微信小程序对lottie的兼容性真的很差,真机调试情况下无法获取canvas,会报错,只能通过预览去看效果,这就给调试带来了困难。
但这只是开始,

需要注意的是在组件中获取canvas需要加上in(this) 要不然无法获取到canvas节点

本来以为这样就结束了,但现实很残酷,第一次进入页面渲染正常,但是再次进入页面,动画就不动了,然后去社区发现了很多类似的情况,应该是官方的bug,看到github上有人提出通过destory方法在退出页面时进行销毁就可以解决这个问题,但遗憾的是这个destory方法并未被官方采纳。于是又到处去搬砖(参考:https://developers.weixin.qq.com/community/develop/doc/000c6c7330ce30571a1a4537556c00?highLine=lottie)

略加修改后如下:

let frameFn = function () {};
let rid = 0;
let canvasDom = null;

 wx.createSelectorQuery()
      .select("#canvas")
      .node((res) => {
        const canvas = res.node;
        const requestAnimationFrame = canvas.requestAnimationFrame;
        canvas.requestAnimationFrame = function () {
          console.log("句子评测中的动画");
          frameFn = arguments[0];
          rid = requestAnimationFrame.apply(canvas, arguments);
          return rid;
        };
        // 页面第二次打开时动画默认不会开始,这里需要手动调用一次动画
        canvas.requestAnimationFrame(frameFn);
        canvasDom = canvas;
        lottie.setup(canvas);
        lottie.loadAnimation({
          autoplay: true,
          loop: true,
          path: PUBLIC_RES + "data.json", //lottie json包的网络链接
          rendererSettings: {
            context: canvas._ctx,
          },
        });
      })
      .exec();
      
    onUnload: function () {
        canvasDom.cancelAnimationFrame(rid);
这样总能解决了吧,可是又出现了新的问题,小程序中有两个地方使用到了动画,单个页面多次进入渲染没有问题,但是如果A页面正常,切换到B页面,那B页面就又不动了,两个页面只有一个页面的动画正常,然后又去爬坑,这次,你猜怎么着,没爬出来果断放弃,一个页面仍然使用lottie-miniprogram,另一个页面直接用gif动画,嗯,真香
还有就是canvas不能直接用wx:if进行显示隐藏,获取不到节点会报错,可以考虑采用定位left:1000rpx实现
.canvas {
  position: absolute;
  bottom: 190rpx;
  z-index: 100;
  width: 226rpx;
  height: 114rpx;
  left: 10000rpx;
  &.show {
    left: 261rpx;
  }
}

四 获取用户信息

获取用户昵称时,用到了wx.getUserInfo,但这个API需要用户授权,尝试用wx.authorize
拉取授权,但失败了,返回12007错误,好像这个API废弃了,必去通过button的开发能力拉取授权

<button wx:if="{{flag}}" class="login-btn" type="primary" open-type="getUserInfo" bindgetuserinfo="getUserInfo">
        授权用户信息
      </button>

五 关于云知声(语音评测API)

之前小程序保存用户录音用的是微信临时文件 tempFilePath,但只能保存三天,通过云知声url拼接的路径可以实现三个月的保存,但是需要获取header,尝试去监听第三方接口的请求头,但是没成功,后来发现可以直接在云知声返回的结果中拿到

export function hivoiceHttp({ recordPath, voiceData = {} }) {
  wx.showLoading({
    title: "评测中",
    mask: true, 
  });
  return new Promise((reslove, reject) => {
    wx.uploadFile({
      url: HIVOICE_BASEURL_HTTP,
      header: {
        "session-id": "uuid-t" + Date.now(),
        appkey: "",
        "score-coefficient": HIVOICE_LEVEL,
      },
      filePath: recordPath,
      name: "voice",
      formData: {
        ...voiceData,
      },
      // 在这可以拿到请求头
      success(res) {
        // 拿到header中的Session-Id并进行拼接
        let headerArr = res.header["Session-Id"].split(":");
        let myVoiceUrl = `https://edu.hivoice.cn/WebAudio-1.0-SNAPSHOT/audio/play/${headerArr[2]}/${headerArr[1]}/${headerArr[0]}`;
        console.log(myVoiceUrl, "=三个月=");
        wx.hideLoading();
        let data = res.data || "{}";
        // // console.log('uploadFile', data, voiceData)
        if (res.statusCode === 200) {
          if (typeof data === "string") {
            data = JSON.parse(data);
          }
          // 音质检测
          if (data.audioCheck) {
            let flag = false;
            const audioCheck = data.audioCheck;
          }
          data.myVoiceUrl = myVoiceUrl;
          reslove(data);
        } else {
          // console.log('uploadFile-succ-statusCode', res.statusCode)
          reject({ message: "非预期结果", res: data });
        }
      },
      fail(err) {
        wx.hideLoading();
        reject(err);
      },
    });
  });
}

六 引导层相关

坑一


灰色引导层采用固定定位,在ios下进行下拉刷新的时候,仍然置顶,但是在安卓下则会随着下拉刷新一起下来,找了一下,好像是官方的bug,需要手写一个下拉刷新的方法。

坑二


在做这个引导栏的时候,遮罩无法覆盖tabbar,有两种解决方案,一种是自己重写tabbar,但是可能兼容性不好,另一种也就是我才采用的方法,效果一般,仅供参考
我是先切一张tabbar的图片,在进入页面时先将tabbar隐藏,通过回调在隐藏结束后显示页面,同时显示定位到原来tabbar位置的切图,作为第二层,然后这时遮罩就可以进行覆盖了。

 wx.hideTabBar({
          success: () => {
            this.setData({ firstLogoin: true, tabbarFlag: true });// firstLogoin为整个页面显示状态位,tabbarFlag为tabber状态位
          },
        });

七 SwipeCell 滑动单元格


这个组件直接引用后删除是没有样式的,需要手动添加一个样式

.van-swipe-cell__right {
  display: inline-block;
  width: 65px;
  height: 44px;
  font-size: 15px;
  line-height: 44px;
  color: #fff;
  text-align: center;
  background-color: #EC714F;
}

需求中要求一次只能进行一次删除,因而一条右滑删除打开,另一条右滑删除就需要自动闭合,这就需要open事件,但是重点是通过bind:open="onOpen"绑定,居然不触发,需要修改源码,通过triggerEvent进行触发


然后就可以触发了,如果不是当前打开的列表项,就通过selectComponent调用close()方法即可,代码已贴

 <van-swipe-cell class="{{'van-swipe' + index}}" right-width="{{ 65 }}" wx:for="{{errorList}}" id="{{index}}" data-index="{{index}}" wx:key="{{index}}" async-close bind:open="onOpen" bind:close="onClose">
onOpen(event) {
    const { position, name } = event.detail;
    const { index } = event.currentTarget.dataset;

    this.data.errorList.forEach((error, errorIndex) => {
      if (errorIndex !== index)
        this.selectComponent(".van-swipe" + errorIndex).close();
    });
  },

八 关于分享

想要让一个页面可以分享,调用onShareAppMessage就可以了,但是同一个页面通过不同页面跳转过来,需要根据跳转的来源判断是否可以进行分享,可以通过hideShareMenu来实现

if (...) {
      wx.hideShareMenu({
        menus: ["shareAppMessage", "shareTimeline"],
      });
    }

如果分享出去的页面需要调用接口进行页面的渲染,可以将登陆后置,放开当前接口的鉴权,涉及到鉴权的操作时再弹出登录提示即可。

九 IOS字体适配

诸如fish中i在ios下面i不显示.且会和f连在一起,所以需要更改字体为:
font-family: Helvetica Neue;

十 视频播放完返回按钮异常


视频播放完成后中间的暂停按钮层级高于左侧返回按钮,导致返回按钮失效,可以去掉中间的结束按钮

show-center-play-btn="{{false}}"

十一 音频播放

const back = wx.getBackgroundAudioManager()

播放背景音乐时,发现音频没有及时更新,加上时间戳后正常

back.src = `${src}?t=${Date.now()}`;

还需要注意的是 createInnerAudioContext 可以播放微信临时文件,getBackgroundAudioManager 不支持

十二 自定义微信小程序tabbar上边框的颜色

两个小程序项目均提到原生tabbar颜色较深的问题,但是


所以只能自己模拟

在app.less中,通过伪类添加tabbar上边框定位下去
page::after {
  content: '';
  position: fixed;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 2rpx;
  background-color: #eeeeee;
  z-index: 9999;
}
在app.json中将tabbar颜色设为白色
 "tabBar": {
    "borderStyle": "white",
  },
;