微信小程序页面生命周期详解:onLoad、onShow、onReady、onHide 与 onUnload
微信小程序页面生命周期并不复杂,真正容易出错的是把“一次初始化”和“每次回到前台都要执行”的工作混在一起。最常见的结果是:返回页面后数据不刷新、事件监听重复注册,或者定时器在页面离开后仍继续运行。
这篇文章用 onLoad、onShow、onReady、onHide 与 onUnload 五个回调,把首次打开、页面跳转、返回和销毁串成一条可验证的执行路径。示例基于原生小程序 Page,不依赖框架。
先记住五个页面生命周期回调
| 回调 | 触发时机 | 同一页面实例是否可能重复 | 适合处理 |
|---|---|---|---|
onLoad | 页面实例加载 | 否 | 读取路由参数、一次性初始化 |
onShow | 页面显示或重新进入前台 | 是 | 刷新可能变化的数据、恢复页面任务 |
onReady | 首次渲染完成 | 否 | 依赖首屏节点或组件就绪的操作 |
onHide | 页面进入后台但未销毁 | 是 | 暂停定时器、停止可见页任务 |
onUnload | 页面实例被销毁 | 否 | 解绑监听、释放资源 |
首次打开一个页面时,常见顺序是 onLoad → onShow → onReady。从下一级页面返回时,当前页面实例通常还在页面栈中,因此只会重新触发 onShow,不会再次执行 onLoad 和 onReady。
用一段代码观察完整顺序
Page({
onLoad(query) {
console.log('onLoad', query)
},
onShow() {
console.log('onShow')
},
onReady() {
console.log('onReady')
},
onHide() {
console.log('onHide')
},
onUnload() {
console.log('onUnload')
}
})
把它放进任意页面的 index.js,分别尝试进入下级页面、返回、重定向和切换 Tab。页面的目录和四件套文件不熟悉时,可以先看微信小程序项目目录结构详解;全局与页面配置的边界则可对照微信小程序 app.json 与 page.json 配置实战。
不同路由动作会触发什么
| 路由动作 | 离开的页面 | 目标页面 |
|---|---|---|
wx.navigateTo | onHide | 新实例:onLoad → onShow → onReady |
wx.navigateBack | onUnload | 原页面:onShow |
wx.redirectTo | onUnload | 新实例:onLoad → onShow → onReady |
wx.switchTab | onHide | 已有 Tab 页:onShow |
wx.reLaunch | 页面被销毁 | 新实例:onLoad → onShow → onReady |
这里的关键不是死记顺序,而是先判断页面实例有没有被销毁。隐藏的页面仍留在页面栈里,回来时走 onShow;被销毁的页面再次进入时会创建新实例,从 onLoad 开始。
onLoad:只做一次的初始化
onLoad 会收到打开当前页面时携带的查询参数,适合解析 ID、初始化不会随前后台切换而变化的状态,以及注册“页面实例级”的监听。
Page({
data: {
orderId: ''
},
onLoad(query) {
const orderId = decodeURIComponent(query.orderId || '')
this.setData({ orderId })
this.loadOrderDetail(orderId)
},
loadOrderDetail(orderId) {
// 根据 orderId 请求详情
}
})
不要把“每次返回页面都必须刷新”的请求只放在 onLoad。从编辑页返回详情页时,详情页实例没有重新加载,旧数据就会继续留在界面上。
onShow:恢复和刷新易变数据
onShow 可能执行多次,适合读取登录状态、刷新列表或恢复被暂停的任务。请求结果写回页面时,仍要控制更新粒度,避免无关字段一起传给 setData;可以结合微信小程序 setData 性能与更新策略检查数据路径。
Page({
data: {
orderStatus: ''
},
async onShow() {
if (!this.data.orderId) return
const orderStatus = await this.fetchOrderStatus(this.data.orderId)
if (orderStatus !== this.data.orderStatus) {
this.setData({ orderStatus })
}
}
})
onReady:只处理首次渲染后的工作
onReady 表示页面首次渲染完成,同一页面实例只触发一次。确实依赖首屏节点或组件已经就绪的操作可以放这里,但普通数据请求通常没有必要等到 onReady 才开始。
Page({
onReady() {
const query = wx.createSelectorQuery()
query.select('#chart').boundingClientRect(rect => {
if (!rect) return
this.initChart(rect.width, rect.height)
}).exec()
}
})
onHide 与 onUnload:暂停和彻底清理
onHide 说明页面暂时不可见,但以后可能回来;onUnload 则代表实例已经销毁。定时器、事件监听和持续订阅要按资源生命周期处理,否则容易出现后台运行或重复回调。
Page({
refreshTimer: null,
messageHandler: null,
onLoad() {
this.messageHandler = message => this.handleMessage(message)
eventBus.on('message', this.messageHandler)
},
onShow() {
this.startRefreshTimer()
},
onHide() {
this.stopRefreshTimer()
},
onUnload() {
this.stopRefreshTimer()
eventBus.off('message', this.messageHandler)
},
startRefreshTimer() {
this.stopRefreshTimer()
this.refreshTimer = setInterval(() => this.refresh(), 30000)
},
stopRefreshTimer() {
if (!this.refreshTimer) return
clearInterval(this.refreshTimer)
this.refreshTimer = null
}
})
常见错误:在 onShow 重复注册监听
下面这种写法每次显示页面都会增加一个监听。往返页面几次后,同一消息可能触发多次回调。
// 不推荐
onShow() {
eventBus.on('message', this.handleMessage)
}
如果监听只属于当前页面实例,在 onLoad 注册并在 onUnload 解绑更清晰;如果业务要求仅在页面可见时监听,就在 onShow 注册、在 onHide 解绑,并保存同一个函数引用。
用静态断言核对五种场景
为了避免把页面栈行为写反,我用 Node.js 22 对照官方路由与生命周期文档,给首次打开、navigateTo、navigateBack、redirectTo 和已有 Tab 页重访写了 10 条静态期望断言,全部通过。它验证的是文档映射和文章表格,不等同于微信开发者工具里的运行时日志。
import assert from 'node:assert/strict'
const expected = {
firstOpen: ['onLoad', 'onShow', 'onReady'],
navigateTo: {
source: ['onHide'],
target: ['onLoad', 'onShow', 'onReady']
},
navigateBack: {
source: ['onUnload'],
target: ['onShow']
},
redirectTo: {
source: ['onUnload'],
target: ['onLoad', 'onShow', 'onReady']
},
tabRevisit: {
source: ['onHide'],
existingTarget: ['onShow']
}
}
assert.deepEqual(expected.firstOpen, ['onLoad', 'onShow', 'onReady'])
assert.deepEqual(expected.navigateBack.target, ['onShow'])
assert.deepEqual(expected.redirectTo.source, ['onUnload'])
排查时按这个顺序检查
- 先确认当前动作是隐藏页面还是销毁页面。
- 检查刷新逻辑是否只写在
onLoad,导致返回后不执行。 - 检查
onShow是否重复注册监听或重复启动定时器。 - 确认解绑时传入的是注册时的同一个函数引用。
- 涉及节点尺寸或组件实例时,再判断是否应放进
onReady。 - 在开发者工具和真机分别记录日志,避免只凭一次预览下结论。
结论
页面生命周期的核心是实例状态:onLoad 和 onReady 面向一次创建,onShow 和 onHide 面向反复显示与隐藏,onUnload 负责最终清理。把数据刷新、可见页任务和资源释放分别放到对应阶段,页面返回不刷新、监听累积和后台定时器这三类问题会少很多。
官方资料:页面生命周期、Page 构造器、页面路由(访问于 2026-09-10);本文静态期望检查使用 Node.js 22,10 条断言全部通过。




