# 前言
本章节内容分解:
- 小程序路由设计
- webview与路由栈
# 路由
在渲染层中可以看到这一段代码,具体位置在generateFuncReady函数前面,直接搜索history也可以找到。
History.pushState('', '', 'http://127.0.0.1:37434/__pageframe__/pages/index/index');

将pages/index/index地址推入路由堆栈,页面路由就此诞生。这里让我想起了SPA最开始的路由形式。这种history.pushState的方法并不像我们在react 或者 vue中使用的那样,但是底层原理都是一样的。
这里我们可以展开讲解一下。
回顾一下小程序页面加载的原理,如果我们跳转到一个新页面,那么在渲染层中会插入一个webview,渲染层中可以有多个webview。
采用多个webview这种方式类似于多页面应用,而不是单页面应用,因为多页面应用可以保留前一个页面的状态,现在小程序页面跳转的方式可以参考app,新页面都是从右侧向左划入的。所以路由的内部是基于多页应用的架构实现的,基于这个原理路由其实并不复杂。
首先触发路由的行为是可以从渲染层发出,也可以从逻辑层发出。在渲染层中用户可以通过点击回退按钮,或者回退上一页的手势等机制触发。
在逻辑层中发出的信号有打开新页面navigateTo、重定向redirectTo、页面返回navigateBack等,开发者通过官网提供的API触发。
无论是渲染层用户触发的行为,还是逻辑层API触发的行为,这个行为都会被发送到Native层,有Native层统一控制路由。
在微信小程序中页面为webview形式,并且是多个webview叠加的形式,所以路由的打开新页面行为对应添加一个新的webview并且覆盖在前一个webview的上面,并初始化新页面的生命周期。其他宿主环境和承载UI页面的容器原理与此方案一致。顺推,页面返回的行为相对应移除一个webview。
这里对于webview的添加或删除都会有一个载体来维护,这就是路由栈。
打开新页面就会往路由栈上方推入一个页面,删除则从栈顶依次删除。并且前面我们了解到webview不可以无限插入,因为这种多页面形式会有性能问题,所以路由栈有最大的插入限制。退回的话最多删除stack.length - 1个,也就是最多回退到首页。

上图演示了打开页面的路由内部流程,配合pageFrame创建新webview。逻辑层中发出打开页面行为到Native层,Native层收到行为后通过pageFrame快速创建webview,并且推入路由栈。页面创建完后,底层基础库会立刻执行初始化操作,初始化完毕后会发送一个信号通知Native页面已经创建并初始化完毕,随后Native层发送信号到逻辑层中。之所以这样设计流程是因为有两个目的:
- 需要通知开发者页面已经创建成功。
- 在沙箱中创建新页面的“根组件”,并正式开启新页面的生命周期与渲染的流程。
下面总结一下在小程序场景中路由变化相对应的栈变化:
- 小程序初始化的时候需要推入首页,新页面入栈。
- 打开新页面对应
navigateTo,新页面入栈 - 页面重定向
redirectTo,当前页面出栈,而后新页面入栈。 - 页面回退
navigateBack,页面一直出栈,到达指定页面停止。 - Tab切换
switchTab,页面全部出栈,只留下新的Tab页面。 - 重新加载
reLaunch,页面全部出栈,只留下新的页面。
最后附带一下官网注意事项:
navigateTo,redirectTo只能打开非 tabBar 页面。switchTab只能打开 tabBar 页面。reLaunch可以打开任意页面。- 页面底部的
tabBar由页面决定,即只要是定义为tabBar的页面,底部都有tabBar。 - 调用页面路由带的参数可以在目标页面的
onLoad中获取。
