微信小程序开发遇到的那些坑

一、Webview内嵌H5页面不可以使用微信支付

最近在做公司的小程序项目时,需要做一个充值页面,打算直接复用微信公众号上已经开发好的H5页面,谁知在本地真机调试的时候调到H5页面能够支付成功,但是提到体验版和正式版后发现不能调起微信支付,最后查了很多文档发现小程序的web-view不支持微信支付,只能通过跳回小程序调用小程序支付的API。实现大体思路:在H5页面获取支付参数,然后判断是否在小程序环境中,如果在,获取到支付参数后返回到小程序并将支付参数传给小程序,小程序调用wx.requestPayment(OBJECT)接口完成支付,需要注意的是,获取支付参数的appId为小程序的appId.下面是我的实现方式:

  1. 在H5页面引入JSSDK 1.3.2,判断小程序环境,获取支付参数,将支付参数返回给小程序,这里需要注意的是“package”参数,因为其包含“=”,因此传的时候注意使用encodeURIComponent编码,获取后decodeURIComponent解码
  2. 在小程序新建一个空白page,在onLoad中获取参数,获取成功后发起微信支付请求
  3. 支付完成,处理相关逻辑

二、小程序获取不到unionId

在小程序发布到线上之后发现有些新用户在登录页面卡死,最后发现是没有获取到unionId,为什么获取不到unionId呢,看下微信对UnionId机制的原文解释:
如果开发者拥有多个移动应用、网站应用、和公众帐号(包括小程序),可通过unionid来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号(包括小程序),用户的unionid是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。
同一个微信开放平台下的相同主体的App、公众号、小程序,如果用户已经关注公众号,或者曾经登录过App或公众号,则用户打开小程序时,开发者可以直接通过wx.login获取到该用户UnionID,无须用户再次授权。
注意: 后边这句话的描述
用户关注过公众号,或者曾经登录过App或公众号,则用户打开小程序时,开发者可以直接通过wx.login获取到该用户UnionID
即:如果用户没有关注过公众号,或者没有登陆过App,通过wx.login是无法获取到该用户UnionID,只能通过wx.getUserInfo来获取UnionId
经验证,系统不存在UnionId的小程序用户都是没有关注公众号或未在App中使用微信授权的用户
解决方案:
获取小程序UnionId获取不到时,wx.getUserInfo可以获取敏感数据,其中包含UnionId字段。
实现:参考https://www.cnblogs.com/cai-r...链接描述

三、扫普通链接二维码打开小程序

(使用该功能,小程序必须已经是已发布状态)小程序提供了扫描普通二维码跳转小程序的功能,首先在微信公众平台配置二维码规则,域名路径必须是校验文件所在路径,可以配置测试链接进行测试,可以配置最多5个测试链接,可以指定测试链接打开的测试范围(开发、测试、正式),必须是具有体验权限的用户才可以进行测试,非体验用户进入正式版本。规则发布后,配置符合规则的链接均可进入到小程序。

四、可拖拽元素遇上canvas二维码

小程序官方组件movable-area、movable-view说明

刚开始做这个可拖拽元素的时候,是准备将其做成一个组件,在每个需要的地方引入即可,但是有一个很大的问题就是所在页面有一个canvas生成的二维码,原生组件在小程序中的层级是最高的,即不管怎么布局或者给z-index都是不生效的,所以拖拽元素拖拽过程中会在二维码下面。
解决这个问题的过程中遇到了很多坑,首先想到的是小程序中有没有直接生成二维码图片的插件,有是有,但是我的字符串太长了,生成的base64编码均太长了,所以我还是用的weapp-qrcode.js插件,这个插件自带导出图片的方法,用的就是wx.canvasToTempFilePath将画布导出生成图片,页面上canvas所在位置放置一个image组件,将canvas移到可视区域外面,但是生成的图片一直是乱的,原来是我没给canvas样式的高度和宽度导致生成出现问题,但是这样还是在一些安卓机上出现问题,调用wx.canvasToTempFilePath已经是在draw回调之后了,但是还是需要给延时才可以,在这里我给的500ms,基本上就可以了。
原生组件层级最高的问题解决了,但是又出现一个问题,就是可拖拽元素是一个组件,所在页面又有很多按钮,如果直接将可拖拽组件的层级设置最高,那么按钮就不可点击,如果不设置最高,那么就不可拖拽了,有两种方式可以解决,一种是将按钮以插槽的方式放在组件中,另一种是不将拖拽元素写成组件,之间将movable-area放在wxml的最外层,我采用的是第二种,如果每个按钮都写成插槽的话维护起来太麻烦了

五、微信小程序缓存-------缓存时效性

/**
 * 数据缓存没有设置有效期
 */
class Storage {
  /**
   * 获取缓存
   * @param String $key  key
   * @param String $def  若想要无缓存时,返回默认值则get('key','默认值')(支持字符串、json、数组、boolean等等)
   * @return value;
   */
  get(key, def = '') {
    const timeout = parseInt(wx.getStorageSync(`${key}__separator__`) || 0);

    // 过期失效
    if (timeout) {
      if (Date.now() > timeout) {
        this.remove(key);
        return;
      }
    }
    let value = wx.getStorageSync(key);
    return value ? value : def;
  }
  /**
   * 设置缓存
   * @param String $key       key
   * @param String $value     value(支持字符串、json、数组、boolean等等)
   * @param Number $timeout   过期时间(单位:分钟)不设置时间即为永久保存
   * @return value;
   */
  put(key, value, timeout = 0) {
    let _timeout = parseInt(timeout);
    wx.setStorageSync(key, value);
    if (_timeout) {
      wx.setStorageSync(`${key}__separator__`, Date.now() + 1000 * 60 * _timeout);
    } else {
      wx.removeStorageSync(`${key}__separator__`);
    }

    return value;
  }

  remove(key) {
    wx.removeStorageSync(key);
    wx.removeStorageSync(`${key}__separator__`);
    return undefined;
  }
}
export {
  Storage
}

六、小程序跳转另小程序遇到的坑(监听返回)

场景:在跳转另一个小程序之前需要调用接口获取跳转所需参数,在另一个小程序返回时需要重新调用接口或许参数。
问题:首先想到的是点击跳转的时候调用接口,之后wx.navigateToMiniProgram跳转,将接口返回数据携带上,但是,这种不是用户直接触发的跳转,微信不支持。。。
然后,那就先在页面的onload事件中直接调用一次,然后再监听另一个小程序返回,再调用一次接口,文档上写的很明白,监听App.onShow就好了,于是我在该页面的onshow直接wx.onAppShow监听场景值为1038,但是!!!这里遇到了巨坑,第一次返回,wx.onAppShow调用一次,第二次返回,wx.onAppShow调用两次,第三次返回,wx.onAppShow调用三次,直接导致整个流程出问题了。。。
解决:思考了好久,决定不用wx.onAppShow监听场景值的办法,直接在该页面直接定义一个变量,比如navigateToOther,默认为false,跳转成功后置为true,然后在onshow里判断是否为true,如果为true,调用接口,将navigateToOther置为false。完美解决!!!

七、小程序H5页面分享

H5页面中的分享转发按钮不能直接分享给好友,只能用折中的方式来做,点击H5页面的分享按钮时,弹出提示框,指向右上角的转发按钮,并通过wx.miniProgram.postMessage将所需信息发送给小程序,用户点击转发按钮时可以通过bindmessage接收到消息
参考链接:小程序内嵌web-view之分享(2)

八、webview刷新

小程序嵌套H5页面时,有时页面在来回切换时需要刷新该H5页面,但是微信未提供相关接口,但是可以通过折中的方式来实现。

首先,让webview做条件渲染:

<web-view wx:if="{{url}}" src="{{url}}" />
data: {
    base_url: config.kalatong_base_url + '……',
    url: ''
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function(options) {
    let url = this.data.base_url + "#wechat_redirect"
    this.data.url = decodeURIComponent(url)
  },
  
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function() {
    this.refreshWebview()
  },

需要刷新时,先把url设为空,销毁当前webview。然后再把url设为当前值。如下:

refreshWebview: function () {
    let tmpUrl = this.data.url;
    this.setData({
      url: ''
    });
    setTimeout(() => {
      this.setData({
        url: tmpUrl
      })
    }, 500);
  }

这样便可以在不影响导航栏历史的情况下刷新页面,也可以是跳转url。
这里setData之后,页面内容的更新应该是异步执行的,因此我们后一次修改url需要延时一小段时间,否则会出现error。
猜测setData后页面实际更新应该是在下一次的requestAnimationFrame,因此如果页面完全不卡顿可能16ms就可以了,保险起见,我设了100ms。
但是100ms也不保险,有些页面会空白,最后置成500ms

相关推荐