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

711 阅读3分钟

一、小程序web-view非调试模式下无法调用微信支付

最近在做公司的小程序项目时,在小程序里嵌入已开发好的H5商城页面,在本地真机调试的时候,H5页面能够支付成功,但是提交到体验版和正式版之后发现不能调起微信支付,最后查看了很多文档发现小程序的 web-view 不支公众号支付,只能通过跳回小程序调用小程序支付的 API,具体查看 API web-view

实现大体思路:

  1. 在H5页面进行下单获取支付参数,然后判断是否小程序环境,如果在,获取到的支付参数返回到小程序;
  2. 小程序新建一个空白页面,在 onLoad 中获取参数,调用 wx.requestPayment(Object object) 接口完成支付;
  3. 在支付成功的回调函数中处理相关逻辑。

二、 web-view 刷新

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

方式一

设置 web-view 动态路由地址

<web-view src="{{url}}" />

在 onShow 中修改 url 地址带时间戳参数

  data: {
    url: ''
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {
    
    const baseUrl = 'https://juejin.cn/user/272334611820302/posts'
    const timeStamp = new Date().getTime()

    this.setData({
      url: `${baseUrl}?=${timeStamp}`
    })
    
  },

方式二

首先,让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

三、wx.miniProgram.getEnv 异步方法

在项目中,先判断当前环境是否小程序,如果是小程序走小程序的逻辑,如果不是走 H5 逻辑,项目中代码如下:


  mounted() {
    this.isWechat()    // 1
    this.init() // 2

  },
  init() {
   // 2-1
    if(this.miniProgramFlag){
        // 小程序打开
        this.getMiniprogramOpenId()
    } else {
        ....
    }
  }
    /**
    * 是否在微信浏览器中打开、是否是小程序
    */
    isWechat() {
        wx.miniProgram.getEnv((res)=> { 
            //  1-1
            if(res.miniprogram) {
              this.weChatFlag = false
              this.miniProgramFlag = true
            } else {
              ....
            }

        })
    },

按照设想,代码执行顺序是:

1 >>> 1-1 >>> 2 >>> 2-1

但实际执行顺序是:

1 >>> 2 >>> 2-1 >>> 1-1

所以 wx.miniProgram.getEnv 异步执行,小程序环境的判断需要写在 getEnv 的回调函数中,最终修改项目代码如下:


  mounted() {
    this.isWechat()    // 1
  },
  init() {
   // 2-1
    if(this.miniProgramFlag){
        // 小程序打开
        this.getMiniprogramOpenId()
    } else {
        ....
    }
  }
    /**
    * 是否在微信浏览器中打开、是否是小程序
    */
    isWechat() {
        wx.miniProgram.getEnv((res)=> { 
            //  1-1
            if(res.miniprogram) {
              this.weChatFlag = false
              this.miniProgramFlag = true
            } else {
              ....
            }

        })
    },

  四、小程序地址栏取参,会截断 = 后面的数据

在做小程序 web-view 内嵌商城H5, 在点击支付时,需要 H5 页面传递支付相关参数到小程序内,在 onLoad 方法中接收地址栏参数, 代码如下:

// H5
clickPay() {
  const package = 'prepay_id=uuduudueyy838'
  wx.miniProgram.navigateTo({
    url:`../payment/index?package=${package}&signType=${pay_data.signType}&timeStamp=${pay_data.timeStamp}&nonceStr=${pay_data.nonceStr}&paySign=${paySign}`
  })
}

  /**
   * 小程序————————生命周期函数--监听页面加载
   */
  onLoad(query:any) {
    console.log('支付页参数query', query)

    this.setData({
      timeStamp: query.timeStamp || '',
      nonceStr: query.nonceStr || '',
      package: query.package || '',
      signType: query.signType || '',
      paySign: query.paySign || ''
    })
   
  },

其中 package 参数包含 prepay_id= 导致在支付请求的时候 package 传递参数是 package: 'prepay_id', 导致在调用小程序支付的时候,一直报错:调用祝福 JSAPI 缺少参数: total_fee 。解决方法在 H5 对该参数进行 encodeURIComponent 在小程序内进行 decodeURIComponent

// H5
clickPay() {
  const encode_package = encodeURIComponent(pay_data.package)
  const encode_paySign = encodeURIComponent(pay_data.paySign)
  wx.miniProgram.navigateTo({
    url:`../payment/index?package=${encode_package}&signType=${pay_data.signType}&timeStamp=${pay_data.timeStamp}&nonceStr=${pay_data.nonceStr}&paySign=${encode_paySign}`
  })
}

  /**
   * 小程序————————生命周期函数--监听页面加载
   */
  onLoad(query:any) {
    console.log('支付页参数query', query)

    this.setData({
      timeStamp: query.timeStamp || '',
      nonceStr: query.nonceStr || '',
      package: decodeURIComponent(query.package) || '',
      signType: query.signType || '',
      paySign: decodeURIComponent(query.paySign) || ''
    })
   
  },