App端切后台必须用uni-app的onHide/onShow而非visibilitychange或blur,因原生WebView不透出标准可见性事件;需在app.vue中用v-show挂载高z-index遮罩层,阻止所有交互并预加载DOM以确保零延迟、零穿透。

App端切后台时自动显示隐私遮罩,不能靠监听页面visibilitychange或blur——这些事件在iOS/Android原生WebView里基本不触发或延迟严重。必须用uni-app官方提供的onHide和onShow生命周期钩子。
为什么document.hidden和window.onblur在App端失效
uni-app打包成App后运行在原生WebView容器中,多数安卓/iOS系统不会向Webview透出标准页面可见性事件。实测发现:document.hidden长期为false,blur几乎不触发,尤其iOS上切到微信、短信等应用时完全无响应。
- 真机调试时console.log(document.hidden)始终输出
false,哪怕App已完全退到后台 - 依赖
visibilitychange监听的代码在App端形同虚设,H5端可用,但App端必须换路子 - 别试图用定时器轮询
document.hasFocus()——App端该API返回恒为true
正确做法:用onHide/onShow配合全局遮罩组件
uni-app在App端对onHide支持稳定,只要App进入后台(包括锁屏、切换应用、Home键退出),该钩子100%触发;onShow则在App重新回到前台时执行。这是唯一可靠入口。
- 在
app.vue的onHide里调用uni.$loading.show()或你自建的showPrivacyMask() - 遮罩组件必须用
v-show而非v-if,否则onShow里hide()可能找不到DOM节点 - 遮罩层
z-index至少设为99999,App端WebView对层级敏感,9999有时会被原生导航栏盖住 - 遮罩背景色建议用纯黑
rgba(0, 0, 0, 0.9),避免半透明下隐约透出敏感内容
遮罩层必须阻止所有交互,且不响应任何触摸事件
用户切回App时,如果遮罩层没彻底阻断操作,可能误点后台残留的按钮或输入框,造成隐私泄露。
- 遮罩
<view>上必须同时写@touchmove.stop.prevent=""和@click.stop.prevent="",只写一个不够 - 不要依赖
pointer-events: none——App端部分Android机型(尤其华为EMUI)不识别该CSS属性 - 遮罩内部不能放任何可聚焦元素(如
<input>、<button>),否则iOS键盘可能意外弹出 - 若页面用了
scroll-view,遮罩需挂载到page根节点外层,否则会被scroll-view的overflow: hidden裁掉
切后台瞬间白屏或闪一下?检查这几个点
遮罩出现前有短暂空白,本质是onHide触发与DOM渲染之间存在微小延迟,尤其低端安卓机明显。
- 遮罩组件提前在
app.vue中mounted时就show()一次(隐藏状态),确保DOM已挂载 - 遮罩样式里加
will-change: opacity,提前告诉GPU该元素会动,减少首帧卡顿 - 避免在
onHide里做复杂计算或请求,只干一件事:this.$refs.privacyMask.show() - 真机测试务必关掉“开发者模式”里的“GPU渲染”开关——某些机型开启后反而导致遮罩层撕裂
真正难的不是显示遮罩,而是保证它在任意机型、任意后台切换路径(锁屏/多任务切换/来电中断)下都零延迟、零穿透、零残留。所有逻辑必须收束到app.vue的onHide/onShow,其他地方补丁越多,越容易漏场景。


















