小程序开发4年+踩坑之旅

629 阅读6分钟

1、小程序页面层级不能超过10层

微信小程序路由层级限制在9层,不能超过10层 业务流程比如:首页-搜索结果页-商品详情页-商品详情页-商品详情页-商品详情页-商品详情页...一不小心就超过10层了,要解决这个问题 有如下方案: 1.当页面栈到达第9层,提示用户(贝壳找房的小程序就是这样) 2.自己封装无限层级,做个空白的中间页

navigator: {
    // 小程序支持打开的页面层数
    maxLevel: 9,
    // 中间跳转页
    middlePage: '/pages/navigator/middle',
    // 历史堆栈
    historyStack: [],
    // 跳转
    navigateTo: function (route, reLaunch) {

      // 是否关闭所有页面,打开到应用内的某个页面
      reLaunch = typeof reLaunch !== 'undefined' ? true : false;
      if (reLaunch) {
        wx.reLaunch({
          url: route.url
        })
        return
      }

      // console.log('util.navigator.navigateTo:', route)
      // 小程序路由堆栈
      let pages = getCurrentPages()
      // console.log('util.navigator.navigateTo {pages}:', pages)
      // console.log('util.navigator.navigateTo {pages.length}:', pages.length)
      // 当前页面路由
      let currentPage = pages[pages.length - 1];
      // console.log('util.navigator.navigateTo {currentPage}:',currentPage)

      if (pages.length < this.maxLevel - 1) { // 小于倒数第二层时
        wx.navigateTo({
          url: route.url
        })

      } else if (pages.length == this.maxLevel - 1) { // 等于倒数第二层时
        this.historyStack.push(currentPage)
        // console.log('util.navigator.navigateTo {this.historyStack}:', this.historyStack)
        wx.redirectTo({
          url: this.middlePage + '?url=' + encodeURIComponent(route.url)
        })
      } else { // 等于最后一层时
        this.historyStack.push(currentPage)
        // console.log('util.navigator.navigateTo {this.historyStack}:', this.historyStack)
        wx.redirectTo({
          url: route.url
        })
      }
    },
  },

2、微信生成小程序二维码 scene 参数过长的方法

小程序二维码 scene 参数限定长度为 32 位字符,但是实际开发中可能有很多的参数需要传递,比如pages/index/index?url=xxx%2F%23%2Fquick-ask%3&a=1%2F%23%2Fquick-ask%3&b=2&c=3%2F%23%2Fquick-ask%3,就需要通过特殊处理之后才能使用,常见方式如下

1.与后端约定好这个详情页scene值是个伪字符串 直接接口处理,返回正确的信息

2.短参数(写个中间件拦截onload函数的options,判断有无scene值,如果有请求接口换取完整页面参数,再去调用接口)

3、小程序生命周期-热启动/冷启动及其相关参数获取

小程序的运行机制

  • 冷启动: 首次打开小程序;或小程序销毁后打开,此时小程序需要重新加载启动,即冷启动。(冷启动会触发app.js中的onLaunch生命周期函数)

  • 热启动: 点击右上角胶囊退出、或者home键离开微信、或者左右滑动返回到微信等动作,都是热启动,并没有销毁小程序, 如果用户已经打开过某小程序,然后在一定时间内再次打开该小程序,此时小程序并未被销毁,只是从后台状态进入前台状态,这个过程就是热启动。(所以热启动不会触发onLaunch函数,但会触发onShow函数

在app.js调用该函数

/** 检测当前的小程序,是否是最新版本,是否需要下载、更新 */
  checkUpdateVersion: function () {
    // console.log('util.checkUpdateVersion')
    //创建 UpdateManager 实例
    const updateManager = wx.getUpdateManager()
    //检测版本更新
    updateManager.onCheckForUpdate(function (res) {
      // 请求完新版本信息的回调
      if (res.hasUpdate) {
        //监听小程序有版本更新事件
        updateManager.onUpdateReady(function () {
          wx.showModal({
            title: '更新提示',
            content: '新版本已经准备好,是否重启应用?',
            success(res) {
              if (res.confirm) {
                // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
                updateManager.applyUpdate()
              }
            }
          })
        })
        updateManager.onUpdateFailed(function () {
          // 新版本下载失败
          wx.showModal({
            title: '已经有新版本咯~',
            content: '请您删除当前小程序,到微信 “发现-小程序” 页,重新搜索打开呦~',
          })
        })
      }
    })
  }

4、分包的问题

微信小程序分包

为什么需要分包

微信客户端在打开小程序之前,会把整个小程序的代码包下载到本地的,这种策略可以缓解页面跳转时白屏的问题。同时微信还对小程序代码包大小设置了 2M (最初只有 1M)的上限来确保小程序能有还不错的启动速度。

分包应该注意的地方

  1. 微信小程序每个分包的大小是 2M,总体积一共不能超过 20M;

  2. 需要尽量保持主包只加载必须的内容,主要包括一些必须公共资源/JS 脚本,tabBar 页面,最好只包括这些页面;

  3. 分包越早越好,如果后期进行分包,不然后期进行分包,就要处理前期被内部及外部调用的地址;

    1. 对于已经对外放出的页面就更没法修改了;
    2. 页面不能通过路由进行重定向,也就是路由与页面位置是绝对对应的;
  4. 主包不可以引用子包内容,子包只可以引用自己包内和主包内的内容,子包内不能嵌套子包;

    1. 独立分包是小程序中一种特殊类型的分包,可以独立于主包和其他分包运行。从独立分包中页面进入小程序时,不需要下载主包。当用户进入普通分包或主包内页面时,主包才会被下载,这个我们通常不会用到。
  5. 子包预下载:开发者可以通过配置,在进入小程序某个页面时,由框架自动预下载可能需要的分包,提升进入后续分包页面时的启动速度。对于独立分包,也可以预下载主包。

5、 setData 数据量不能超过2M

当 setData 过大时会提示错误

vdSyncBatch 数据传输长度为 2260792 已经超过最大长度 1048576
复制代码

因为setData设置的数据量是有限制的,单次设置的数据大小不得超过1024kb,否则就会出现如上错误

解决方案:将数组转成二维数组后进行setData,并且需要修改wxml的循环结构,多套一层循环。

伪代码

    data:{  
        currentpage:0,// 当前页数
        list:[], // 数据源  
    }, 
    getListData:function(){ 
        // 本次加载的数据 
        let _list = [];
        ... setData({ [list[' + currentpage + ']']: _list, }); 
    }

6、超长滚动列表,上拉加载过多后内存溢出性能优化

当列表页面上拉加载数据到一定量时,占内存过高,导致小程序卡顿甚至黑屏关闭。

解决思路:让不在当前窗口区域内的内容wxml结构移除。

操作思路:封装一个列表item的容器组件,利用 createIntersectionObserverrelativeToViewportobserve 方法监听当前 item 所在位置,进行移除或者插入

核心代码

组件skeleton.wxml

<view class="list-item" id="list-item-{{uniqueId}}" style="min-height: {{height}}px;">
	<block wx:if="{{showSlot}}">
		<slot></slot>
	</block>
</view>
复制代码

组件skeleton.js

...

ready() {
    // 修改了监听是否显示内容的方法,改为前后showNum屏高度渲染
    // 监听进入屏幕的范围relativeToViewport({top: xxx, bottom: xxx})
    const { windowHeight = 667 } = systemInfo()
    const showNum = this.data.showNum //超过屏幕的数量,目前这个设置是上下2屏
    try {
      this.IntersectionObserver = this.createIntersectionObserver()
      this.IntersectionObserver.relativeToViewport({
        top: showNum * windowHeight,
        bottom: showNum * windowHeight
      }).observe(`#list-item-${this.data.uniqueId}`, res => {
        let { intersectionRatio } = res
        if (intersectionRatio === 0) {
          console.log('【卸载】#', this.data.uniqueId, '超过预定范围,从页面卸载')
          this.setData({ showSlot: false })
        } else {
          console.log('【进入】#', this.data.uniqueId, '达到预定范围,渲染进页面')
          this.setData({
            showSlot: true,
            height: res.boundingClientRect.height
          })
        }
      })
    } catch (error) {
      console.log(error)
}
...

7、图片处理

图片资源放在cos上,压缩加裁剪

/**
* oldurl 图片地址
* width 图片裁剪的宽
* height 图片裁剪的高
* identification 图片裁剪方式
* multiples 裁剪倍数
*/
 cropimg: function (oldurl, width, height, identification,multiples) {
    let newurl = ''
    if (identification == 'crop') {
      newurl = oldurl + '?imageMogr2/thumbnail/!' + width*(multiples?multiples:1.5) + 'x' + height*(multiples?multiples:1.5) + 'r/interlace/0|imageMogr2/gravity/center/crop/' + width*(multiples?multiples:1.5) + 'x' + height*(multiples?multiples:1.5) + '/auto-orient'
      // newurl =`${oldurl}?imageView2/1/w/${width*(multiples?multiples:1.5)}/h/${height*(multiples?multiples:1.5)}`
      // 
    } else if (identification == 'cropwidth') {
      newurl = oldurl + '?imageMogr2/thumbnail/' + width + 'x/auto-orient'
    }

    return newurl
  }

8、小程序分享朋友圈

目前仅安卓分享朋友圈有效 如果分享朋友圈的页面需要走wx.login授权接口的话 需要判断

    const { scene, mode } = wx.getLaunchOptionsSync() 
    // mode === 'singlePage' OR scene === 1154 && isIOS