0%

微信小程序路由栈不能超过 10 的解决方案

微信小程序路由跳转有个隐藏的坑,就是 wx.navigateTo打开新页面,最多只能打开10个,超过10个之后就没反应,控制台也不会报错。

方案一:最粗暴…navigateTo不行,那就redirectTo

小程序路由跳转的方式有五种,分别是wx.navigateTo(打开新页面,新页面入栈)、wx.redirectTo(重定向,当前页面出栈,新页面入栈)、wx.navigateBack(返回,页面不断出栈,直到目标返回页)、wx.switchTab(切换tab页面,页面全部出栈,只留下新的 Tab 页面)、wx.reLaunch(页面全部出栈,只留下新的页面)

由此产生了第一种方式,当页面栈超过 10 时,直接用redirectTo

但这样太粗暴了,显然很多场景是需要保留访问过的页面的,由此有了方案一的升级版。

方案一升级版:根据页面栈决定当前跳转方式

每次跳转先去页面栈中查找目标页面是否已经访问过,如果访问过则用wx.navigateBack返回,如果没有访问过则判断页面栈中是否已经有10个页面,有则用wx.redirectTo,没有则navigateTo
js code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class RouteMp {
constructor(opt={}) {
this.MAX_DEEP = opt.MAX_DEEP || 10
this.IS_AUTO_BACK = opt.IS_AUTO_BACK || true
this.PAGE_STACk = getCurrentPages()
}

_findPageInHistory(path) {
const { PAGE_STACk } = this
let delta = -1
for (let i = 0; i < PAGE_STACk.length; i++) {
if (PAGE_STACk[i].route === path) {
delta = i + 1 // 目标页在栈中的位置
break
}
}
return delta
}

_dataToUrlQuery(data={}) {
let query = '?';
for (const prop in data) {
if (data.hasOwnProperty(prop)) {
const value = data[prop];
query += `${prop}=${value}&`
}
}
return query.replace(/&$/, '');
}

goPage(opt) {
if (!opt) return new Error('缺少参数')
if (opt && !opt.path) return new Error('缺少跳转目标path')
const { PAGE_STACk } = this
const pageStackLen = PAGE_STACk.length
let { path, data } = opt
let delta = this._findPageInHistory(path)
path = '/' + path.replace(/^\//, '') + this._dataToUrlQuery(data)

if (delta > -1 && this.IS_AUTO_BACK) {
// 如果有目标页已经是被访问过的
const backPage = PAGE_STACk[pageStackLen - delta]
backPage.setData({data});
wx.navigateBack({
delta: pageStackLen - delta
})
} else {
if (pageStackLen < this.MAX_DEEP) {
wx.navigateTo({
url: path
})
} else {
wx.redirectTo({
url: path
})
}
}
}

}

module.exports = RouteMp

但是这样依然有问题,页面传参数变得无法统一,而且明明是前进页面,用户使用的时候很可能看着就是返回了几个页面。

方案二:在小程序页面栈之外维护多一个自己的逻辑栈

这个方案并非我们自己想到的,出处是某位清华学霸,我是在掘金-小程序无限层级路由方案看到的。

总的来说就是:vim

  1. 9层(含9层)以内时:走小程序自己的历史栈就ok了,跳转时候更新一下逻辑栈,这没啥可说的
  2. 从9层跳转10层:需要把第9层重定向到中转页,再由中转页跳转到10层
  3. 10层以后跳转:在navigateTo方法中处理,到10层之后,再跳转就第10层页面一直做redirectTo(重定向)操作了
  4. 10层以上返回:会返回到中转页,由中转页判断,具体返回到哪个页面,然后navigateTo(跳转)过去
  5. 从10层返回到9层:返回到中转页,将中转页redirectTo(重定向)到第9层页面
  6. 9层内的返回:直接返回就好了,返回时候不会更新逻辑栈,但没有关系,因为只有中转页才会用到逻辑栈
  7. 逻辑栈更新机制:
    • 跳转、返回中转页时更新
      • navigateTo时更新
      • redirectTo时更新
      • reLaunch时更新
      • navigateBack时更新