《微信小程序七日谈》- 第四天:页面路径最多五层?导航可以这么玩
《微信小程序七日谈》系列文章:
- 第一天:人生若只如初见;
- 第二天:你可能要抛弃原来的响应式开发思维;
- 第三天:玩转Page组件的生命周期;
- 第四天:页面路径最多五层?导航可以这么玩;
- 第五天:你可能要在登录功能上花费大力气;
- 第六天:小程序devtool隐藏的秘密;
- 第七天:不要捡了芝麻丢了西瓜
本系列的文章并非初学教程,而是笔者在具体开发过程中遇到的问题以及部分解决方案。
微信小程序提供导航相关的API:
wx.navigateTo();wx.redirectTo();wx.navigateBack()。
使用wx.navigateTo()或者<navigator>组件跳转的页面路径最多只有5层,这些页面路径是可以通过wx.navigateBack()API或者左上角返回按钮按顺序返回的。当页面路径大于5层时,使用wx.navigateTo()进行下一页吗跳转会抛出错误:
navigateTo:fail webview count limit exceed.
但是某些业务场景存在多页面互动的交互逻辑,远远不止5层页面栈。比如笔者近期参与开发的58到家小程序中存在如下的业务场景:
1、用户进入小程序,展示首页;
2、首页存在一个如下图的底部导航栏:

用户点击“我的”进入个人中心,此时页面栈为首页->个人中心,共2层。
3、个人中心页面存在“我的收入”入口,如下:

4、用户从个人中心进入我的收入页面,此时页面栈为首页->个人中心->我的收入,共3层;
5、我的收入页面提供“提现”页面的入口,如下:

6、用户进入提现页面,此时的页面栈为首页->个人中心->我的收入->提现,共4层。此时留给我们可支配的页面栈只剩下一层了。提现流程如下:

提现流程存在多页面直接的数据共享和交互,如果是常规的webapp,我们通常会考虑使用hash路由或者干脆做成独立的几个页面使用url传参进行数据通信。但是进入提现页面之后,我们最多只能再添加一个独立页面了。也就是说,银行列表页、绑定银行卡页和提交成功页三者只能再使用一个页面栈(并非一个页面)承载。如何用仅剩的最后一层页面栈实现上述复杂的提现流程呢?
逻辑行为梳理
第一步:细分交互行为
首先第一步是将提现行为细分,因为只能再添加一个独立页面,所以需要合并一些可在一个页面完成的行为。上文的流程图其实遗漏了一个行为:绑定银行卡页面点击银行卡需要显示银行列表页。也就是允许用户重新选择银行。所以其实整体的提现流程如下:

小程序标题栏左上角返回按钮的行为(图中标红的线条)是返回页面栈的上一页面,代码是无法干预的。
整个流程中必须支持“返回”按钮正常返回上一页面的行为有:
- 前置页面进入提现页面,正常返回前置页面;
- 提现页面进入的银行列表页面,正常返回提现页面。
要保证第二条“提现页面进入的银行列表页面,正常返回提现页面”,就必须将银行列表页独立为一个页面。至此,最后一层页面栈就定型了。那么剩下的绑定银行卡和提交成功页面怎么办呢?
第二步:合并逻辑页面
需要注意的是,银行列表页面与绑定银行卡页面之间有一个双向的交互行为,由于最后一个独立页面已经确定为银行列表页了,所以不得不从中牺牲一定的用户体验:绑定银行卡页面跳转到银行列表页后不能正常返回。有了这个前提,我们可以把银行列表和绑定银行卡两个逻辑页面合并为一个实体页面,通过子路由控制行为展示。
再次回顾上文的交互流程图还可以得到另外一个信息:提交成功页面的返回逻辑与提现页面完全相同。所以,两者同样可以合并为一个实体页面,由子路由控制行为展示。
第三步:梳理行为逻辑
以第二步的合并规则为准,实体页面的交互流程如下:

使用data.route实现子路由
微信小程序的Page是没有子路由概念的,我们在此讨论的子路由其实就是根据Page组件的某个data字段进行不同模板的分发渲染。
首先定义支持的子路由列表:
// 路由列表
const ROUTES = {
index: 'index',
banklist: 'banklist',
setcard: 'setcard',
done: 'done'
};
我们在代码上又进一步的融合,将第四层页面和第五层页面两个实体页面融合为同一个Page组件,通过子路由控制模板的渲染,之所以这样做有以下几点考虑:
- 两个实体页面之间有很多共用的数据;
- 58到家的小程序是复用了现存的部分接口,两个页面之间的数据是混合在一起的,融合也是为了避免接口的重构;
既然融合为一个Page组件,那么如何实现页面的跳转呢?其实很简单,使用wx.navigateTo()API如下:
wx.navigateTo({
url: './index?route=' + ROUTES.banklist
});
上述代码实现了跳转到同一Page组件的功能,并且跳转的页面会被加入到页面栈中。
然后在index.wxml中增加路由数据的逻辑判断分发:
<block wx:if="{{route=='index'}}">
<include src="_part/basic/index.wxml"/>
</block>
<block wx:if="{{route=='banklist'}}">
<include src="_part/banklist/index.wxml"/>
</block>
<block wx:if="{{route=='setcard'}}">
<include src="_part/setcard/index.wxml"/>
</block>
<block wx:if="{{route=='done'}}">
<include src="_part/done/index.wxml"/>
</block>
前置页面进入第四层页面时默认的是index子路由页面,有第五层页面的绑定银行卡提交后返回第四层页面时显示done子路由。这个逻辑中需要注意的是:
- 第四层页面跳转第五层页面是隐藏(Hide)而不是卸载(Unload);
- 第五层页面返回第四层页面后会触发第四层页面的
onShow钩子函数。
也就是说,我们可以再onShow钩子函数中进行路由的分发。但是如何获取路由字段呢?大家可能想到的第一个方案就是通过url传参,可惜这个方案是行不通的。首先,微信小程序官方文档中关于Page组件钩子函数的说明,只有onLoad函数可以获取由url query传递的数据,其余的任何钩子函数都不能获取;其次,第五层页面的提交行为返回第四层页面是由wx.navigateBack()API实现的,这个API的功能是返回页面栈中的上一层页面,并不支持指定的修改url,所以url传参这条路是走不通的。
那么使用cookie是否可行呢?虽然微信小程序不支持cookie,但cookie的理念可以提供给我们解决问题的思路:将数据先储存在本地,跳转页面后获取本地数据进行相应处理。
有了思路,自然而然地便想到类似cookie的本地storage。
使用storage进行页面间的数据通信
第一步:点击第五层页面的提交按钮后,首先在storage中储存第四层页面的route值:
wx.setStorage({
key: 'dj_deposits_route',
data: ROUTES.done
});
第二步:在第四层页面的onShow函数内获取storage中的route数据并赋值给data中的route字段,模板便会同步刷新:
let _route = wx.getStorageSync('dj_deposits_route');
this.setData({
route: _route
});
总结
微信小程序的页面路径限制为最多5层,多于5层的页面将不会跳转并且会抛出错误信息。而我们产品的某些业务场景不止存在5层的页面路径,在这种情况下,我们不得不牺牲一定的用户体验,以保证功能的完整。本文提到的方案是与业务场景息息相关的,只是一家之言,并非最佳实践。希望能够给大家一点参考。
《微信小程序七日谈》- 第四天:页面路径最多五层?导航可以这么玩的更多相关文章
- 微信小程序开发(四)页面跳转
承接上篇博客. 通过点击按钮跳转到新的页面. 先创建新页面home: 代码如下: // home.js Page({}) // 注册页面 // home.json {} // home.wxml &l ...
- 《微信小程序七日谈》- 第三天:玩转Page组件的生命周期
<微信小程序七日谈>系列文章: 第一天:人生若只如初见: 第二天:你可能要抛弃原来的响应式开发思维: 第三天:玩转Page组件的生命周期: 第四天:页面路径最多五层?导航可以这么玩 前两篇 ...
- 《微信小程序七日谈》- 第二天:你可能要抛弃原来的响应式开发思维
<微信小程序七日谈>系列文章: 第一天:人生若只如初见: 第二天:你可能要抛弃原来的响应式开发思维: 第三天:玩转Page组件的生命周期: 第四天:页面路径最多五层?导航可以这么玩 上篇文 ...
- 《微信小程序七日谈》- 第一天:人生若只如初见
<微信小程序七日谈>系列文章: 第一天:人生若只如初见: 第二天:你可能要抛弃原来的响应式开发思维: 第三天:玩转Page组件的生命周期: 第四天:页面路径最多五层?导航可以这么玩 微信小 ...
- 《微信小程序七日谈》- 第五天:你可能要在登录功能上花费大力气
<微信小程序七日谈>系列文章: 第一天:人生若只如初见: 第二天:你可能要抛弃原来的响应式开发思维: 第三天:玩转Page组件的生命周期: 第四天:页面路径最多五层?导航可以这么玩: 第五 ...
- 《微信小程序七日谈》- 第六天:小程序devtool隐藏的秘密
<微信小程序七日谈>系列文章: 第一天:人生若只如初见: 第二天:你可能要抛弃原来的响应式开发思维: 第三天:玩转Page组件的生命周期: 第四天:页面路径最多五层?导航可以这么玩: 第五 ...
- 《微信小程序七日谈》- 第七天:不要捡了芝麻丢了西瓜
<微信小程序七日谈>系列文章: 第一天:人生若只如初见: 第二天:你可能要抛弃原来的响应式开发思维: 第三天:玩转Page组件的生命周期: 第四天:页面路径最多五层?导航可以这么玩: 第五 ...
- 微信小程序把玩(四十)animation API
原文:微信小程序把玩(四十)animation API 动画水还是比较深的,这里只是简单介绍下小程序中动画的一些属性和注意事项,做动画前一定要整理好思路将动画一步步分解,再进行组合!这里只做引入. w ...
- 微信小程序把玩(四十一)canvas API
原文:微信小程序把玩(四十一)canvas API 绘图是每个移动应用必备的技术,基本上和Android,IOS,等移动开发都是相同的,创建个上下文,给你个画布再上画,官网给的小例子都比较全了自己去看 ...
随机推荐
- LeetCode:Container With Most Water,Trapping Rain Water
Container With Most Water 题目链接 Given n non-negative integers a1, a2, ..., an, where each represents ...
- JavaScript过滤除连续的数字
if (!Array.prototype.forEach) { Array.prototype.forEach = function (callback, thisArg) { var T, k; i ...
- benchmark pm2的cluster模式发布web app的性能与相关问题解决方法
pm2以cluster集群方式发布app,可以高效地利用多核cpu,有效提升吞吐量.在上周对公司的redmine服务器进行性能调优后,深感ruby on rails的性能低下,这次测试nodejs的s ...
- 转:如何学习javascript
ps:每过一段时间就会发觉自己懂的越来越少,打开编辑器的时候不知道从何入手.兴许是过于急于求成,总没有系统地去对这门语言进行学习,囫囵吞枣,只想着能够解决工作需求.是时候让自己重新出发,从零开始,一页 ...
- [转载] Redis
转载:http://snowolf.iteye.com/blog/1630697 大约一年多前,公司同事开始使用Redis,不清楚是配置,还是版本的问题,当时的Redis经常在使用一段时间后,连接爆满 ...
- T 泛型转换
T为左值 result = (T)Convert.ChangeType(o,typeof(T));
- Xiph基金会成员:Timothy B. Terriberry
Speex,CELT,Opus的发明人之一 还特意写了高中:Thomas Jefferson High School for Science and Technology Shit 一查,全美第一名的 ...
- Android多国语言文件夹命名方式
多國語言: 在res目錄下建立不同名稱的values文件來調用不同的語言包Values文件匯總如下:中文(中國):values-zh-rCN中文(台灣):values-zh-rTW中文(香港):val ...
- Cubieboard2裸机开发之(一)点亮板载LED
前言 CUbieboard2板载两个LED,一个绿色的,一个蓝色的,其中绿色LED通过三极管与PH20管脚连接,蓝色LED通过三极管与PH21管脚连接,这里只以蓝色LED为例,电路原理图如图1和图2所 ...
- 基情四射的两个css样式
自定义blog样式时,代码段的line-height继承样式post的line-height,间隔太大了,决定再减小点,css都玩了几年了,感觉中这是很容易的事情.然后,就悲剧了好久,原先自定义样式表 ...