小程序页面栈详解

在做小程序项目的时候不难发现,使用navigateTo进行页面跳转后,点击左上角或使用navigateBack返回,总是会按照之前的页面进入倒序来展示页面,那么问题来了,它们的跳转规则是什么样的呢?结合到实际业务中如何灵活运用呢?
什么是页面栈?
首先先来了解一下小程序的运行环境: 小程序的运行环境分成渲染层和逻辑层,其中 WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层 。小程序的渲染层和逻辑层分别由2个线程管理:渲染层的界面使用了WebView 进行渲染;逻辑层采用JsCore线程运行JS脚本 。一个小程序存在多个界面,所以渲染层存在多个WebView线程,这两个线程的通信会经由客户端做中转,逻辑层发送网络请求也经由Native转发,小程序的通信模型下图所示 。

小程序页面栈详解

文章插图
 
我们可以看到,一个页面使用一个 WebView 线程进行渲染 。如果打开10个页面,则会开启 10 个 WebView 线程,此时内存中的十个webView线程我们称之为页面栈 。当然小程序也会对这块内存做限制,目前页面栈的限制是不能超过十条 。在小程序中页面的路由是小程序框架本身控制的我们不要去手动管理,小程序框架通过一个页面栈的设计来管理所有的界面,当发生路由跳转时,页面栈就会做出相应的变化,在小程序页面中通过 getCurrentPages() 就可以获取到当前的页面栈 。
举个栗子: 在父页面中先获取页面栈:
const page = getCurrentPages(); // 父页面console.log('父页面', page); //父页面复制代码通过wx.navigateTo跳转子页面,在子页面中再获取页面栈:
const page = getCurrentPages(); // 子页面console.log('子页面', page); //子页面复制代码输出:
小程序页面栈详解

文章插图
 
通过上面的例子可以看到,我们可以在页面中通过 getCurrentPages() 方法来获取当前页面栈,并且获取到的是一个数组,其中每个item都是每个页面的Page对象(也就是在页面中的this对象),由此我们引发一些思考……
路由跳转时页面栈表现?
当发生路由切换的时候,页面栈的表现如下: 当发生路由切换的时候,页面栈的表现如下:
情景页面栈表现对应路由跳转API小程序初始化新页面入栈打开新页面新页面入栈wx.navigateTo 或使用组件页面重定向当前页面出栈,新页面入栈wx.redirectTo 或使用组件页面返回页面不断出栈,直到目标页wx.navigateBack 或使用组件或用户按左上角返回按钮Tab 切换页面全部出栈,只留下新的 Tab 页面wx.switchTab 或使用组件 或用户切换 Tab重加载页面全部出栈,只留下新的页面wx.reLaunch 或使用组件
我们在做项目的时候,巧妙运用路由跳转和页面栈会节省很多代码,用户体验也会得到相应的提升,所以,在开始项目之前,定好页面跳转规则相当重要 。
页面栈的实际运用分析
下面我们分析一下页面栈的变化过程,从分析中,我们需要明白的一个重要问题就是,当客户按返回按钮的时候究竟会跳转到那个界面,这是我们分析页面栈变化的的意义 。首先我们在页面中调用两次navigateTo,页面栈情况如下
小程序页面栈详解

文章插图
 
这时显示的界面是pageC ,如果客户在此时返回则会一切正常,回退的第一个界面是pageB,然后是pageA 。但是如果在pageC 界面调用 wx.redirectTo({url:'pageD'}) 则情况就会不一样,我们先看一下跳转到pageD后页面栈的情况如何 。
小程序页面栈详解

文章插图
 
根据栈的情况,我们可以分析出 。如果使用 wx.redirectTo跳转到pageD页面,然后在回退的时候是不能再次回退到pageC的,而会直接回退到pageB 。通过上面对页面栈的分析,我们可以看到栈的变化是会影响客户回退页面的顺序的,所以根据自己的需求合理的使用不同的跳转方法是非常重要的 。如果使用不当就会导致跳转混乱让人摸不清头脑 下面分析一种调转重复页面的情况:
小程序页面栈详解

文章插图
 
如图所示栈中出现了两个相同的pageB界面,这个时候如果用户按退出键就会出现一个页面出现2次的情况,而且有一个界面的数据也是旧的数据 。因此为了避免这个问题,我们应该在 PageC 页面避免将 PageB重复压入栈中,所以在pageC页面使用wx.navigateBack({delta:1}); 进行页面回退 。而数据刷新的问题则在页面的onShow函数中进行即可 。


推荐阅读