onShow 和 onHide 必须写在 App.vue 中,用于监听应用级前后台切换;onShow 启动时也会触发,需区分冷启动与热切回;onHide 仅作最后存档,不可依赖后台执行。

onShow 和 onHide 必须写在 App.vue 里
这两个函数只在 App.vue 中生效,写在任何页面(比如 pages/index/index.vue)或组件里都监听不到应用级的前后台切换。这是最容易踩的坑:很多人把逻辑放在页面的 onShow 里,结果发现 App 从后台切回来时根本没触发——因为那只是页面级的 onShow,和应用状态无关。
正确位置是 App.vue 的 export default 对象中:
export default {
onShow() {
console.log('应用真正进入前台')
},
onHide() {
console.log('应用真正进入后台')
}
}
注意:onShow 在 App 启动时也会触发一次(不只是后台切前台),所以业务逻辑里要区分场景,比如用时间戳或标志位判断是否为“冷启动”还是“热切回”。
onHide 不是后台执行入口,而是“最后通牒”
iOS 和 Android 系统对后台 JS 执行限制极严,onHide 触发后几十秒内,定时器、WebSocket、甚至 setTimeout 都会被系统挂起或终止。指望它持续跑任务等于白忙。
你应该在 onHide 里做这些事:
- 立刻保存关键状态到
uni.setStorageSync(如表单草稿、上传断点、定位上报进度) - 调用一次强心跳或状态上报(
uni.request发送最后一条“我还活着”的信号) - 清除前台可能还在跑的
setInterval或requestAnimationFrame,避免切回前台后重复执行 - 暂停
uni.startLocationUpdateBackground等原生后台能力(如果已启用)
别在这里启动新定时器、开新 WebSocket 连接,或者试图“保持活跃”——系统不会买账。
onShow 是恢复逻辑的唯一可靠时机
用户切回前台后,onShow 是你重连、刷新、校验的第一站。但要注意几个现实问题:
- 网络可能已切换(Wi-Fi → 流量),需重新检测
uni.getNetworkType - 登录态可能过期,
uni.getStorageSync('token')存在不代表有效,建议先发个轻量 API(如/auth/validate)校验 - 页面可能已被系统回收(尤其 Android 低内存机型),所以不要依赖上一次的 Vue 实例数据,一切从本地存储或服务端拉取
- 如果用了原生插件(如定位、蓝牙),
onShow里需手动重启对应模块,不能假设它们还在线
示例片段:
onShow() {
// 检查 token 是否仍有效
uni.request({
url: '/auth/validate',
success: (res) => {
if (!res.data.valid) this.$router.push('/login')
}
})
// 拉取最新未读消息
this.fetchUnreadCount()
}
uni.onAppShow 和 uni.onAppHide 的兼容性陷阱
虽然文档写了 uni.onAppShow,但它在 iOS 上存在明显延迟(有时晚于 onShow 几百毫秒),且无法在 onLaunch 外提前注册(否则无效)。更麻烦的是,它不支持移除监听(uni.offAppShow 无效果),容易造成多次绑定。
所以实际项目中建议:
- 优先使用
App.vue内置的onShow/onHide,稳定、及时、可控 - 仅在需要跨多个子包(subNVue、nvue 页面)同步状态时,才配合
uni.$emit/uni.$on做事件广播 - 避免混合使用
onShow和uni.onAppShow,否则逻辑分散、调试困难
真要用 uni.onAppShow,必须确保它只在 onLaunch 里注册一次,且不要期望它比 onShow 更早触发。
前后台切换不是“后台常驻”的开关,而是状态交接的边界。所有关键动作都要围绕“进入前台时恢复”和“进入后台前存档”来设计,别跟系统对抗。











