1、背景android
不少开发者在面对小程序的五层页面限制时,心里大概是崩溃的。 使用wx.navigateTo()或<navigator>组件(open-type=navigate时)跳转的页面路劲最多只有5层,这些页面路径能够经过wx.navigateBack() API或者左上角返回按钮顺序返回。当页面路径大于5层时,使用wx.navigateTo()跳转下一页不会有任何动静,页面既不跳转也不会报错(这就尴尬了,若是没有细看开发文档,还觉得是本身代码写错了呢)。[注:开发工具和ios都不会报错,没有验证android的表现] 可是,有时候业务场景存在多页面交互的状况,远远不止5层页面,这时候如何轻松处理页面跳转就成了一个不得不考虑的问题。
2、页面栈&小程序导航API接口ios
微信小程序中的页面导航API有3个:wx.navigateTo、wx.redirectTo、wx.navigateBack。wx.navigateTo和wx.redirectTo打开新的页面,wx.navigateBack用于返回上一个页面(栈里的页面)。 这3个页面API的区别在于:
一、wx.navigateTo接口与页面栈示意图json
当栈满了(5层)以后,再调用wx.navigateTo()跳转任何页面,都不会成功。 特别注意的是,调用两次wx.navigateTo('页面B');wx.navigateTo('页面B');,那么栈里存在两个页面B(或者说两个页面B的实例),以下图。
二、wx.redirectTo接口与页面栈示意图小程序
三、wx.navigateBack微信小程序
这个比较容易理解,就是栈里的页面一个一个出栈。当最后一个页面(首页A)出栈后,也就退出了小程序。 在新版库中,给wx.navigateBack添加了一个参数delta,用于决定须要返回几层页面;若是delta大于等于现有页面数(也就是栈里的页面数),则返回到首页。
四、页面栈与wx.navigateBack缓存
在此突出wx.navigateBack(OBJECT)和getCurrentPages()接口,由于本文提出的应对页面栈5层限制的方案正是充分利用这两个接口的结果。
3、一种能够解决问题的方案
一、方案的提出微信
由以上的对导航接口和页面栈的分析能够知道两点: (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)页面间数据采用缓存传递
二、方案的实现app
/* * desc: * 一、若是目标页面已经在栈中,那么wx.navigateBack({delta: xx})到目标页面 * 二、若是目标页面不在栈中, * (1)若是栈大小<5,那么wx.navigateTo(目标页面) * (2)不然,wx.redirectTo(目标页面) * 三、全部页面间的数据传输,经过缓存携带 * 四、跳转目标页,用goPage() * 五、在目标页,经过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层致使没法跳转的问题。
4、最完美的解决方案工具
以上方案是完美的吗? 想一想,若是通过屡次(超过5次)跳转,而后点击左上角后退会出现什么状况?是否是中间通过的一些页面不见了(早已经出栈了)。用户通常的预期是,我点击跳转屡次,后退应该原路返回,即从哪里来的回到哪里去&怎么走过来的就怎么走回去。 但这个问题显然是没法解决的,由于,一旦页面超过了5层,总有页面得出栈,“原路返回”已经失去了条件。 其实,对于页面5层限制的问题,官方文档已经给出了完美的解决方案: