uni-app跨端开发微信小程序之页面栈超过10层时无法跳转的解决方案
0
阅: - 评:0 - 积分:摘要:正常情况下,一个微信小程序中的页面栈是不会超过10层的。如果在商品详情面添加相关商品,链接处理不当时就会出现页面栈超10层导致页面无法点击的情况。在上一篇提到的提前购流程中,由于链路太长,必然也会出现页面栈超10层的现象。但又考虑到用户体验,直接使用redirectTo或reLaunch都是流氓行为......
使用uni-app开发微信小程序可以做到一套编码适配10端(目前官方是这样介绍的,随着时间推移可能会发生变化。),已经diao炸天了,但有些平台本身的限制还是无法解除的哈。标题中提到的页面栈超过10层是微信小程序自身的限制,超过10层的页面无法进行操作。什么意思呢?说直白点儿就是:当页面栈达到10层时,在该页面上点击不能正常跳转,像卡死了一样(部分情况例外,比如:switchTab、reLaunch)。如果看官在开发过程中碰到页面假死时,不要第一时间怀疑是自己写的代码有bug,首先应该检查下是不是页面栈到达了10层[:笑哭]。有关页面栈10层限制的描述,详情见微信官方文档说明:戳我访问 wx.navigateTo
一、页面栈是什么
微信官方解释:框架以栈的形式维护了当前的所有页面。当发生路由切换的时候,页面栈的表现如下:
路由方式 | 页面栈表现 | 代码实现 |
---|---|---|
初始化 | 新页面入栈 | 小程序打开的第一个页面 |
打开新页面 | 新页面入栈 | 1、API方式:wx.navigateTo({url:'链接'}); 2、使用组件 <navigator open-type="navigate" url="链接" ></navigator> |
页面重定向 | 当前页面出栈,新页面入栈 | 1、API方式:wx.redirectTo({url:'链接'}); 2、使用组件 <navigator open-type="redirectTo" url="链接" ></navigator> |
页面返回 | 页面不断出栈,直到目标返回页 | 1、API方式:wx.navigateBack({delta:'数量'}); 2、使用组件 <navigator open-type="navigateBack"></navigator> 3、点击手机左上角返回按钮; 4、部分手机滑屏 |
Tab 切换 | 页面全部出栈,只留下新的 Tab 页面 | 1、API方式:wx.switchTab({url:'链接'}); 2、使用组件 <navigator open-type="switchTab" url="链接" ></navigator> |
重加载 | 页面全部出栈,只留下新的页面 | 1、API方式:wx.reLaunch({url:'链接'}); 2、使用组件 <navigator open-type="reLaunch" url="链接" ></navigator> |
更多官方术语请→→戳我访问详情
二、如何查看页面栈数量
通过执行getCurrentPages()
这个函数可以查看当前小程序中页面栈的数量。如图:在控制台中输入getCurrentPages方法可查看页面栈数量.png
三、为什么有人会遇到页面栈达上限而有的人不会遇到?
前面都是官方的术语,下面以实际开发为例来说说这个页面栈。
在之前开发的一些微信小程序中,我并没有遇到页面栈达到10层上限的问题,即使是上一个鲜德小程序。但后来为什么就因为复制了一个发现页面而暴露出这个问题呢?原因就是:之前的发现页面属于tabBar
,当从其他页面进入到Tab页面时,页面栈中的页面会全部出栈只留下当前Tab页。
说到这里,再回想下提前购的流程,当时的页面栈是这个样子的:
[发现页面, 选择日期页面, 选择三餐时间页面, 提前购页面]
此时提前购页面中的页面栈中已经有4个了,因为下一步还是发现页面且又是Tab页,所以只能使用switchTab
来实现跳转,所以跳转后页面栈的层级恢复到1。此时的操作会发生如下变化:
[发现页面, 菜谱详情页, 提前购页面]
当用户一餐选购完成时,页面栈的层数为3,如果此时选择下一步比如午餐,那么此时页面栈的数量又变成1了。如果此时用户继续选购,那么页面栈是这个样子的:
[发现页面, 菜谱详情页, 提前购页面, 商家主页, 跳转到提前购页面]。所以在这种情况下,页面栈是不会达到10层的。
3.1、如何让页面栈达到10层
可能有看官会问了,那怎样才能快速让页面栈达到10层呢?我想康康。其实很简单,只需要在商品详情页中展示其他商品即可!
虽然在商品详情页中放相关推荐或关联商品可以增加曝光率,但是处理不当就会出现页面栈超10层的问题。
另外再说一下,虽然在开发商品详情页时我们都用的是一个页面,但只要你使用了navigateTo
那页面栈中就会+1!证明操作见下方视频:wx.navigateTo会一直向页面栈中添加.mp4(友情提示:点击上面的图片即可播放视频)
四、如何优雅的解决?
4.1、近一步分析问题
现在再来看看文章开头提到的页面栈,不难发现:redirectTo、navigateBack、switchTab、reLaunch这4个方法都能实现我们想要的。但不同的方法有不同的功能,不能随便乱用。就拿凯哥来说,他喜欢左右滑屏实现页面的切换。那此时使用switchTab、reLaunch
后,用户再滑屏时就会直接用户退出小程序,因为页面栈只有1了。那只用redirectTo
行吗?显然也不行,只用redirectTo
的话会造成用户无法后退到上一页,因为这是一个替换的操作。现在只剩下navigateBack
了,但这个又法传递参数......
再来看看我们的需求,用户在提前购的链路上既要可以使用返回功能、又要链路间可以正常跳转不受微信小程序官方的10层限制,确实有点儿难办。另外再说一句,虽然微信官方说不建议删除页面栈,但我在网上找了下也没有找到删除的方法。虽然控制台显示可以删除,但并没有实际意义。
4.2、最终方案:封装方法,拦截跳转
你看,说到这里,关于这个页面栈的问题就属于上篇提到的:用户体验和功能取舍上了。古语有云:鱼与熊掌不可兼得,那怎么办呢?加班想办法喽......
后来思考了下,打算自己封装一个名叫linkJump
的方法,然后页面上的链接跳转时全部要通过这个方法。这也就意味着:之前页面上使用<navigator>
标签跳转的地方要全部换成js事件,否则就无法走我的linkJump
方法了。于是,又是一波页面大改动。因为组件是通用的,a页面使用js进行跳转,b页面也要加js事件呀,否则b页面点击商品时就无法正常跳转了。由于同一页面组件有时会出现多次,我又不得不对组件进行改进,否则就可能出现本来是2个组件跳转不同的页面的,但由于事件同名导致跳同一页面的现象。所以,这个工作量也让我加了几次班......
4.3、linkJump做了些什么?
这里有四种情况需要考虑,具体见下方表格。
大场景 | 小场景 | 方案 |
---|---|---|
1:要跳转的页面不在页面栈中 | 1.1、非Tab页面 | 此时最简单,直接navigateTo完事儿 |
1.2、Tab页面 | 此时需要使用switchTab | |
2:要跳转的页面在页面栈中 | 2.1、跳转页面为当前页面(例如:从a商品详情页跳转到b商品详情页) | 此时使用redirectTo,别无他法,此时就牺牲了一次回退的功能 |
2.2、剩余情况 | 根据getCurrentPages()动态计算出delta,然后使用navigateBack实现跨多页面后退 |
这里还需要解决一个参数的问题。由于navigateBack
无法携带新页面所需要的参数,所以我们还得把参数另外处理。这里我使用了vuex来存储原url
中所带的参数,具体方法是:在页面跳转前使用vuex进行存储,跳转到新页面后通过computed()
来接收,再适情况在onShow()
或watch
中做出对应的更新。使用微信小程序自带的getStorage也是可以的,注意在适当时机清除数据。
五、如何使用?
5.1、linkJump 的长这样
- /* url: 要跳转的链接,例如:pages/find/index?id=15 */
- /* callback: 回调方法,做些特殊的事情 */
- function linkJump ({ url, callback }) {
- if (!url) { return }
- let newUrl = url
- if (url[0] === '/') { /* 过滤首位的/ */
- newUrl = url.substring(1)
- }
- const pathname = newUrl.split('?')[0]
- const tabBarUrl = ['pages/index/index', 'pages/find/index', 'pages/user/index', 'pages/cart/index'] /* Tab页中的路径,请根据自己项目实际情况进行修改 */
- const page = getCurrentPages()
- const index = page.findIndex(item => item.route === pathname)
- /* 如果是Tab中的链接,直接跳转 */
- if (tabBarUrl.includes(pathname)) {
- uni.switchTab({
- url: url,
- success: () => {
- callback && callback()
- }
- })
- return
- }
- if (index !== -1) { /* 在页面栈中找到时 */
- const step = page.length - 1 - index
- if (step === 0) {
- uni.redirectTo({
- url: url,
- success: () => {
- callback && callback()
- }
- })
- } else {
- callback && callback()
- uni.navigateBack({ delta: step })
- }
- return
- }
- /* 否则就直接跳转 */
- uni.navigateTo({
- url: url,
- success: () => {
- callback && callback()
- }
- })
- }
为了方便管理,可以把linkJump
放到util.js
中,也可以单独放一个文件中,然后再局部调用或放main.js
中全局调用都是可以的。具体怎么用,看官自己斟酌。
5.2、在.vue页面中使用
比如用户在商家主页中点击了“评价”时,那么此时会跳转到对应的页面展示商家信息。大致代码如下:
- linkJump({
- url: '/pages/merchant/info?id=' + this.locationId + '¤t=0', /* 商家信息页的url */
- callback: () => {
- this.$store.commit('setLinkJumpInfo', { location_id: this.locationId, current: 0 }) /* vuex中保存信息,用于在info页面接收并做出相应的处理。除此之外,还可以使用微信小程序自身的存储功能,比如:wx.getStorage() */
- }
- })
这里放一个简单的示例视频:linkJump方法自动处理页面栈间的跳转避免页面栈超过10层.mp4(友情提示:点击上面的图片即可播放视频)
通过上面的视频可以看到,当页面栈到达7时通过走linkJump这个方法,页面栈的数量直接变成了2且能成功接收到url中传递过来的参数。页面栈一下子就空出了5个位置,这是一个很棒的操作。只要相关页面上链接都走这个方法,那就可以做到自动清空页面栈,不会出现页面栈堆到10层的情况。当然了,除非有另外一种情况发生,那就是:非Tab的页面存在10个不同的链接地址!如果是这种情况,那就没办法了。不过正常情况下业务逻辑也不会这么干,一条链路上有10个递进关系的页面,你咋不上天呢!
六、源码下载
demo源码已上传到了github
上的dev-pagestack-20201002
分支中。如果看官需要研究源码,可以点击下面的链接进行访问并下载。若看官发现有bug可及时和我联系,我会尽可能第一时间优化。
- 网址: 戳我前往github查看源码
七、最后
一写就是大半天,可真费时间。下两篇会说说关于《uni-app开发地图时的一些坑》,比如:定位不准、用户拒绝授权后无法唤醒授权......,敬请期待。
转载声明:
若亲想转载本文到其它平台,请务必保留本文出处!
本文链接:/xwzj/2020-10-02/uni-app-pagestack.html
若亲不想直保留地址,含蓄保留也行。艺灵不想再看到有人拿我的技术文章到他的地盘或者是其它平台做教(装)程(B)而不留下我的痕迹。文章你可以随便转载,随便修改,但请尊重艺灵的劳动成果!谢谢理解。
亲,扫个码支持一下艺灵呗~
Tag: uni-app 微信小程序 跨端开发 switchTab 页面栈 tabBar getCurrentPages vuex getStorage
上一篇: 复盘自己在开发生鲜类小程序时犯下的几个错 下一篇: uni-app跨端开发微信小程序之wx.chooseLocation打开地图并实现定位功能