文章目录
  1. 1. 小程序的启动
    1. 1.1. 小程序启动过程
    2. 1.2. 注册 App 实例
    3. 1.3. 获取 App 实例
  2. 2. 小程序页面
    1. 2.1. 页面生命周期
    2. 2.2. 页面导航
    3. 2.3. 页面层级准备
  3. 3. 参考
  4. 4. 结束语

一个小程序有很多页面,每个页面又有各自的线程、生命周期和功能逻辑。关于小程序的生命周期、页面之间的跳转有哪些特殊的地方呢?

小程序的启动


小程序启动过程

初次进入小程序的时候,微信客户端初始化好宿主环境,同时从网络下载或者从本地缓存中拿到小程序的代码包,把它注入到宿主环境。大概是这么个过程:

  1. 创建线程(渲染层和逻辑层),启动小程序。
  2. 载入基础库(WebView 基础库和 AppService 基础库)。
  3. 载入小程序业务代码(下载或者从本地缓存中拿到)。
  4. 使用App()注册程序实例。

为了让小程序业务代码能够调用 API 以及组件,就需要在启动小程序后先载入基础库,接着再载入业务代码。
由于所有小程序都需要注入相同的基础库,所以小程序的基础库会被提前内置在微信客户端。而基础库是热更新的,故一般等微信客户端携带上一个稳定版的基础库正式发布后,再进行新版本基础库的灰度和推送。

注册 App 实例

宿主环境提供了App()构造器用来注册一个程序 App。App 实例是单例对象,在其他 JS 脚本中可以使用宿主环境提供的getApp()来获取程序实例。

App() 必须在 app.js 中调用,必须调用且只能调用一次。不然会出现无法预期的后果。

App()函数用来注册一个小程序。接受一个Object参数,其指定小程序的生命周期回调等。

onLaunch
小程序初始化完成时(全局只触发一次)触发onLaunch回调。
在微信客户端中打开小程序有很多途径,对不同途径的打开方式,小程序有时需要做不同的业务处理。所以微信客户端会把打开方式带给onLaunchonShow的调用参数options,我们可以根据参数来判断一些进入方式,以及做对应的逻辑处理。

例如,我需要拿到从另外一个小程序跳转过来携带的信息,此时场景值应该是1037(参考场景值):

1
2
3
4
5
6
7
8
9
App({
// ...
onShow: function(e) {
if(e.scene === 1037){
const data = e.referrerInfo && e.referrerInfo.extraData; // 拿到对应的数据
const refAppid = e.referrerInfo && e.referrerInfo.appId; // 拿到对应的小程序appid
}
}
})

onShow
小程序启动,或从后台进入前台显示时触发onShow回调。通常我们用来处理数据和状态的更新。
小程序进入后台状态:当用户点击左上角关闭,或者按了设备 Home 键离开微信,小程序并没有直接销毁。

onHide
小程序从前台进入后台时触发onHide回调。
小程序进入前台状态:当再次进入微信或再次打开小程序,又会从后台进入前台。

获取 App 实例

我们可以使用全局的getApp()函数来获取到小程序 App 实例(在App()内的函数中使用this就可以拿到app实例。)。

前面我们可以看到,App 的生命周期是由微信客户端根据用户操作主动触发的。故我们通过getApp()获取实例之后,不应该私自调用生命周期函数。

具体的原理是什么呢?小程序的 JS 脚本是运行在 JsCore 的线程里,小程序的每个页面各自有一个 WebView 线程进行渲染,所以小程序切换页面时,小程序逻辑层的 JS 脚本运行上下文依旧在同一个 JsCore 线程中。

因此,App 构造器可以传递其他参数作为全局属性以达到全局共享数据的目的。

由于所有页面的脚本逻辑都跑在同一个 JsCore 线程,页面使用setTimeout或者setInterval的定时器,即使切换了页面,也需要自行清理定时器。可以选择:

  • 在页面离开onUnloadonHide等的时候自行清理
  • 做全局的定时器管理(当然也还是需要关闭时清理)

说到页面之间的数据共享,我们也该来讲讲小程序里页面的启动。

小程序页面


页面生命周期

宿主环境提供了Page(Object)构造器用来注册一个小程序页面,接受一个Object类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。

注意:Object 内容在页面加载时会进行一次深拷贝,需考虑数据大小对页面加载的开销。

这里我们先来看看官方的生命周期图:

image

左侧是渲染层,右侧是逻辑层。几件事:

  1. 渲染层和逻辑层之间通信,是通过 Native 转发实现的。
  2. 逻辑层通过 Page 实例的setData方法传递数据到渲染层。由于需要两个线程的一些通信消耗,为了提高性能,每次只设置需要改变的最小单位数据。
  3. 生命周期顺序:onLoad -> onShow -> onReady

页面生命周期函数
onLoad(Object query)
页面加载时触发。一个页面只会调用一次,可以在onLoad的参数中获取打开当前页面路径中的参数。

onShow()
页面显示/切入前台时触发。

onReady()
页面初次渲染完成时触发。一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。

onHide()
页面隐藏/切入后台时触发。

onUnload()
页面卸载时触发。

和小程序实例的生命周期对比,其实页面也是有些相似。这里需要注意几点:

  • 当前页面路径的参数获取,只能在onLoad(query)query参数中获取,无法在onShow()中获取
  • onLoadonReadyonUnload,一个页面都只会调用一次
  • 页面是卸载还是切换到后台,这些除了与小程序的后台切换有关系,还会与页面的跳转、切换逻辑有关系

下面我们就来看下页面的逻辑。

页面导航

我们知道,一个小程序会拥有多个页面。在小程序里会有页面的层级关系,例如通过wx.navigateTo推入一个新的页面,在首页使用2次wx.navigateTo后,页面层级会有三层:

image

获取页面栈
getCurrentPages()函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面。
需要注意的是:

  • 修改页面栈会导致路由以及页面状态错误
  • App.onLaunch的时候 page 还没有生成,不能在这调用getCurrentPages()

但是其实不是每一次切换页面,都会被记录到页面栈里,我们看看页面导航的一些方法和行为:

路由方式 触发时机 页面栈表现 进入方式
初始化 小程序打开的第一个页面 新页面入栈 从下往上升起
打开新页面 调用 API wx.navigateTo 新页面入栈 从右往左切入
页面重定向 调用 API wx.redirectTo 当前页面出栈,新页面入栈 页面重新加载
页面返回 返回/调用 API wx.navigateBack 页面不断出栈,直到目标返回页 从右往左切回
Tab 切换 切换/调用 API wx.switchTab 页面全部出栈,只留下新的 Tab 页面 页面重新加载
重加载 调用 API wx.reLaunch 页面全部出栈,只留下新的页面 页面重新加载

关于导航 API 的几个补充点:

  • wx.navigateTowx.redirectTo只能打开非 TabBar 页面,wx.switchTab只能打开 Tabbar 页面,wx.reLaunch可以打开任意页面
  • TabBar 页面指在 app.json 的 TabBar 字段定义的页面(客户端窗口的底部或顶部有 tab 栏可以切换页面)
  • 跳转到 TabBar 页面,路径后不能带参数(注意,Tabbar 页面初始化之后不会被销毁)
  • 调用页面路由带的参数可以在目标页面的onLoad中获取

页面层级准备

我们知道页面栈的表现,以及一些常见的导航方法,而小程序基础库也在页面层级做了些体验优化。

对于每一个新的页面层级,视图层都需要进行一些额外的准备工作:

  • 在小程序启动前,微信会提前准备好一个页面层级用于展示小程序的首页
  • 每当一个页面层级被用于渲染页面,微信都会提前开始准备一个新的页面层级,减少每次新开页面的耗时

每个页面的准备都有三个阶段:

  1. 启动一个 WebView。
  2. WebView 中初始化基础库(此时还会进行一些基础库内部优化,以提升页面渲染性能)。
  3. 注入小程序 WXML 结构和 WXSS 样式(小程序能在接收到页面初始数据之后马上开始渲染页面)。

PS:wx.redirectTo不会打开一个新的页面层级,而是将当前页面层级重新初始化。

参考

结束语


页面的路由和跳转、切入方式,其实和用户的使用和交互紧紧相关,设计合理也是能大大提升用户体验的。
其实这一节的内容,大部分都是小程序文档里面有的。只不过好些相关的内容被分散在各个地方,理解和使用起来还是需要查找,这一节就当作整理笔记吧。

码生艰难,写文不易,给我家猪囤点猫粮了喵~

查看Github有更多内容噢:https://github.com/godbasin
更欢迎来被删的前端游乐场边撸猫边学前端噢
如果你想要关注日常生活中的我,欢迎关注“牧羊的猪”公众号噢

作者:被删

出处:https://godbasin.github.io

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

文章目录
  1. 1. 小程序的启动
    1. 1.1. 小程序启动过程
    2. 1.2. 注册 App 实例
    3. 1.3. 获取 App 实例
  2. 2. 小程序页面
    1. 2.1. 页面生命周期
    2. 2.2. 页面导航
    3. 2.3. 页面层级准备
  3. 3. 参考
  4. 4. 结束语