小程序页面栈最多有几层_微信小程序5层限制的一种解决方案

一、背景

  1. 很多开发者在面对小程序的五层页面限制时,内心大概是崩溃的。
  2. 使用wx.navigateTo()或<navigator>组件(open-type=navigate时)跳转的页面路劲最多只有5层,这些页面路径可以通过wx.navigateBack() API或者左上角返回按钮顺序返回。当页面路径大于5层时,使用wx.navigateTo()跳转下一页不会有任何动静,页面既不跳转也不会报错(这就尴尬了,如果没有细看开发文档,还以为是自己代码写错了呢)。[注:开发工具和ios都不会报错,没有验证android的表现]
  3. 但是,有时候业务场景存在多页面交互的情况,远远不止5层页面,这时候如何轻松处理页面跳转就成了一个不得不考虑的问题。

二、页面栈&小程序导航API接口

  1. 微信小程序中的页面导航API有3个:wx.navigateTo、wx.redirectTo、wx.navigateBack。wx.navigateTo和wx.redirectTo打开新的页面,wx.navigateBack用于返回上一个页面(栈里的页面)。
  2. 这3个页面API的区别在于:
  • navigateTo 不会将旧页面出栈;
  • redirectTo 会将旧页面出栈,再将需要跳转到的页面入栈;
  • navigateBack 则是将页面栈最后一个元素出栈,因此倒数第二个元素会成为最后一个元素,即变成「当前页面」。

1、wx.navigateTo接口与页面栈示意图

bbdcde7f214714060c6482beb8cd298f.png
  • 当栈满了(5层)之后,再调用wx.navigateTo()跳转任何页面,都不会成功。
  • 特别注意的是,调用两次wx.navigateTo('页面B');wx.navigateTo('页面B');,那么栈里存在两个页面B(或者说两个页面B的实例),如下图。

3738f1a79b76caea251cbb9f05e4a530.png

2、wx.redirectTo接口与页面栈示意图

1460d26d0db80b3a6b67e64c2764950d.png

3、wx.navigateBack

  • 这个比较容易理解,就是栈里的页面一个一个出栈。当最后一个页面(首页A)出栈后,也就退出了小程序。
  • 在新版库中,给wx.navigateBack添加了一个参数delta,用于决定需要返回几层页面;如果delta大于等于现有页面数(也就是栈里的页面数),则返回到首页。

32d88ffca017190fe90c212fef3ceaa6.png

4、页面栈与wx.navigateBack

5f7cd131c244ebfd776c59217a119323.png

在此突出wx.navigateBack(OBJECT)和getCurrentPages()接口,因为本文提出的应对页面栈5层限制的方案正是充分利用这两个接口的结果。

三、一种可以解决问题的方案

1、方案的提出

由以上的对导航接口和页面栈的分析可以知道两点:

(1)调用两次wx.navigateTo('页面B'),那么栈里存在两个页面B(或者说两个页面B的实例)。但其实栈里没有必要保留两个页面B实例

(2)wx.navigateBack的参数delta可以返回栈里的指定页面,其中页面信息可以由getCurrentPages()接口得到

据此,提出如下一种解决方案

(1)自定义页面跳转方式

(2)当页面栈里已经存在要跳转的目标页面A,那么使用wx.navigateBack({delta: xx})返回到此页面A,{xx=getCurrentPages().length - 目标页面A在栈里的index - 1}

(3)如果页面栈还没有要跳转的目标页面A

a、若页面栈已经已满(length>=5),那么使用wx.redirectTo(页面A);

b、否则,使用wx.navigateTo(页面A)

(4)页面间数据采用缓存传递

2、方案的实现

/*
* desc:
*  1、如果目标页面已经在栈中,那么wx.navigateBack({delta: xx})到目标页面
*  2、如果目标页面不在栈中,
*    (1)如果栈大小<5,那么wx.navigateTo(目标页面)
*    (2)否则,wx.redirectTo(目标页面)
*  3、所有页面间的数据传输,通过缓存携带
*  4、跳转目标页,用goPage()
*  5、在目标页,通过inPage()接收数据。接收后,数据会被删除
*/
Nav = {
    MAX_VALUE: 5, //页面栈最多5层
    /*
     * desc: 跳转页面
     * param:
     *  obj: {
     *    url: ''  //页面在app.json中的路径,路径前不要加'/'斜杠(也可以加,做了兼容)
     *    data: {}  //需要携带的参数,统一通过缓存携带
     *  }
     */
    goPage: function(obj) {
        var pages = getCurrentPages(),  //页面栈
            len = pages.length,
            dlt = '',
            target = '/' + obj.url.replace(/^//, ''), //如果有,将第一个‘/’去掉,然后再补上(开发者习惯不同,有些人会给url加/,有些则忘了,兼容处理
            navigation_key = target.replace(///g, '_'); //存储数据的下标,每个页面由自己的存储key,保证了页面间数据不会相互污染
        //查找目标页在页面栈的位置
        for (var i = 0; i < len; i++) {
            if (pages[i].route == target) { //
                dlt = i + 1; //目标页在栈中的位置
                break;
            }
        }
        //保存数据
        //由于navigateBack()回到指定页面,不会重新执行onLoad事件,所以加个标兵。
        //只有在isLoad = true;时,才会接收参数并执行类onLoad事件
        var nData = Object.assign({ referer: pages[len - 1].route, _is_load: true }, obj.data || {});
        wx.setStorageSync(navigation_key, JSON.stringify(nData));
        if (!dlt) { //页面不在栈中
            if (len < this.MAX_VALUE) {
                wx.navigateTo({
                    url: target
                });
            } else {
                wx.redirectTo({
                    url: target
                });
            }
        } else {
            wx.navigateBack({
                delta: len - dlt
            });
        }
    },
    /*
     * desc:在目标页接收数据
     * param:
     *    myOnLoad:回调方法,由于通过缓存传递数据,页面onLoad没办法接收,所以要自定义回调
     */
    inPage: function(myOnLoad) {
        var pages = getCurrentPages();
        var navigation_key = pages[pages.length - 1].route.replace(///g, '_');
        //从其他页面跳转过来的,那么isLoad肯定为true,因为goPage中设置了。如果是用户点击左上角后退的,那么isLoad=false,因为下面设置了
        //获取数据
        try {
            var raw = wx.getStorageSync(navigation_key);
            var options = JSON.parse(raw);
            if(options._is_load && myOnLoad) {  //用户点击左上角后退时,不会执行myOnLoad,因为此时_is_load是undefined
              myOnLoad(options);
            }
            wx.setStorage({ //清除数据
                key: navigation_key,
                data: ''  //这之后,_is_load是undefined了
            });
        } catch (e) {
            
        }
    }
};

采用以上方案后,就可以专心写代码逻辑了,不需要再担心页面层级无意间超过5层导致无法跳转的问题。

四、最完美的解决方案

  • 想想,如果经过多次(超过5次)跳转,然后点击左上角后退会出现什么情况?是不是中间经过的一些页面不见了(早已经出栈了)。用户一般的预期是,我点击跳转多次,后退应该原路返回,即从哪里来的回到哪里去&怎么走过来的就怎么走回去。
  • 但这个问题显然是无法解决的,因为,一旦页面超过了5层,总有页面得出栈,“原路返回”已经失去了条件。
  • 其实,对于页面5层限制的问题,官方文档已经给出了完美的解决方案

原文链接:https://blog.csdn.net/weixin_39939012/article/details/102366562

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值