自定义 tabBar 下组件首屏永远空白:pageLifetimes.show 不触发之谜
首页组件上线了。开发者工具里一切正常,真机冷启动……空白。换一个 tab 再切回来,内容突然出现了。这种「第二次才有数据」的现象,排查方向极容易跑偏——以为是接口慢、以为是 onLoad 时序、以为是缓存没清——实际上根子在微信框架对自定义 tabBar 的生命周期处理上。
现象
- 小程序冷启动,落在某个 tabBar 页,页内的自定义 Component 一片空白,或停在「加载中…」。
- 打开 vConsole / 开发者工具,
pageLifetimes.show的回调从未执行。 - 手动点击另一个 tab,再切回来,
pageLifetimes.show正常触发,数据出现。 - 把同一个 Component 放到非 tabBar 的普通页面,首屏完全正常。
根因
app.json 里设置 "custom": true 启用自定义 tabBar 后,框架对 tabBar 页面的生命周期调度发生了变化:宿主页面完成初始化挂载时,不会向子 Component 派发 pageLifetimes.show,该事件只在后续每次「用户切换 tab 回到此页」时才触发。
换句话说:
- 普通 tabBar:
pageLifetimes.show在首次进入时触发 ✓ custom: truetabBar:pageLifetimes.show在首次进入时跳过,从第二次进入开始触发
如果组件把所有初始化逻辑都写在 pageLifetimes.show 里,cold start 那一次的数据请求就悄悄丢失了,没有任何报错。
只要 app.json 中 tabBar.custom === true,子组件的 pageLifetimes.show 在首次挂载时不触发。把初始化请求放在这里,首屏必然空白,且无任何错误日志,极难发现。
正解
把首次加载逻辑移至 lifetimes.attached——这是 Component 自身的挂载生命周期,与 tabBar 类型无关,无论何种场景都可靠触发。
错误写法(自定义 tabBar 下首屏静默失效):
Component({
pageLifetimes: {
show() {
// custom tabBar 首次挂载时永远不执行
this.loadList()
}
}
})正确写法(首屏可靠触发):
const app = getApp()
Component({
data: { list: [] },
lifetimes: {
attached() {
const that = this
app.checkLogin(function () {
that.loadList()
})
}
},
methods: {
async loadList() {
const res = await api.someList({})
this.setData({ list: res.data })
}
}
})如果除了首屏加载,还需要每次切回 tab 时刷新数据,两个生命周期并用即可:
Component({
lifetimes: {
attached() {
// 首屏初始化,只跑一次
this.loadList()
}
},
pageLifetimes: {
show() {
// 从第二次进入开始刷新(custom tabBar 下首次不触发,符合预期)
this.refreshIfStale()
}
}
})lifetimes.attached 是 Component 挂载生命周期,不受 tabBar 类型影响,首屏必触发。pageLifetimes.show 则专门负责「用户再次切回来时」的刷新,两者职责分离、互不干扰。
一句话外卖
微信小程序自定义 tabBar 页内的 Component,首屏初始化必须放
lifetimes.attached,pageLifetimes.show在首次挂载时静默跳过——这是框架行为,不是 bug,但文档里几乎没有任何提示。