uni-app 无原生全局事件捕获机制,需用 uni.$on/uni.$emit 实现跨页面通信或页面根元素事件代理;前者需手动注册/卸载防内存泄漏,后者仅限单页伪全局监听。
uni-app 没有原生的「自动捕获所有点击/输入/滚动」的全局事件机制,所谓“监听全局事件”,本质是靠 uni.$on/uni.$emit 手动触发 + 页面级事件代理两种路径实现,选错方案会导致事件收不到、内存泄漏或跨平台失效。
uni.$on 和 uni.$emit 是唯一真正跨页面的全局事件总线
这是 uni-app 官方提供的事件通信机制,不依赖 DOM,全平台(小程序、H5、App)一致生效,也是唯一能天然支持「多页面同时监听同一事件」的方式。
- 必须成对使用:
uni.$on注册监听,uni.$emit主动触发,不能自动感知用户操作 - 监听需在页面生命周期(如
onLoad)中注册,卸载时(onUnload)必须调用uni.$off移除,否则重复注册导致回调执行多次 - 事件名建议用字符串常量统一管理(如
'userLogin'),避免拼写错误导致静默失败 - 传递参数只能是可序列化的对象,函数、DOM 节点、Promise 等无法跨页面传递
想监听真实用户操作?得靠页面根元素事件 + .stop 修饰符
微信小程序和 App 端不支持 document.addEventListener('click'),H5 虽然能加,但会因页面切换丢失监听。可行做法是在每个页面的根 上绑定 @tap 或 @click,并确保子元素不阻止冒泡。
- 根容器必须设
style="width: 100vw; height: 100vh;",否则空白区域点不到 - 子组件或按钮上要加
@tap.stop,否则点击按钮会先触发根元素的 tap,再触发按钮自己的 click - 仅适用于单页内“伪全局”监听,无法跨页面共享状态,也不适用于需要捕获 scroll/touchmove 的场景
- 小程序里优先用
@tap,@click在某些安卓机型上可能不触发
小程序里监听全局行为(如无操作、权限弹窗)要用平台专属 API
微信小程序不开放底层事件钩子,但提供了有限的系统级监听能力,比如权限申请、应用前后台切换等,这些不是靠 uni.$on,而是调用原生接口注册回调。
- 监听权限框弹出:用
uni.createRequestPermissionListener()+.onConfirm,仅 Android 生效 - 监听小程序进入前台:用
uni.onAppShow,退出后台用uni.onAppHide - 模拟“无操作检测”:需手动在页面根元素监听
@touchstart、@tap、@input,再配合定时器重置,不能依赖单一事件 - Component 构造器劫持方案虽存在,但属于黑盒 hack,HBuilderX 更新后极易失效,生产环境不建议使用
最容易被忽略的一点:事件监听的生命周期必须和页面强绑定。写在 App.vue 的 onLaunch 里注册的 uni.$on,如果没配 uni.$off 清理逻辑,页面反复进出就会累积监听器——看起来“有时收不到”,其实是回调被覆盖或执行了 N 次。











