在 uni-app 开发中,跨页面、跨组件的事件通信是一个常见需求。除了通过 Vuex 或全局状态管理工具外,uni-app 提供了简洁的事件机制,即 uni.$on
、uni.$off
、uni.$once
和 uni.$emit
。它们可以理解为一个简化版的全局事件总线,方便页面之间快速通信。
本文将详细介绍这四个方法的作用、用法及注意事项,并结合实际案例帮助大家掌握。
一、基础概念
uni.$on(eventName, callback)
注册一个全局事件监听器,用于监听某个事件。uni.$emit(eventName, data)
触发一个全局事件,并携带数据,通知监听者执行回调。uni.$off(eventName, callback?)
移除事件监听器,可以移除指定事件,也可以移除所有事件。uni.$once(eventName, callback)
注册一个只执行一次的事件监听器,执行后自动移除。
二、常用场景
- 页面 A 更新数据,通知页面 B 刷新列表
- 弹窗关闭时,通知父组件更新状态
- 登录成功后,通知多个页面同步用户信息
- 消息推送触发事件,应用内多个页面响应
三、使用示例
1. uni.$on
和 uni.$emit
配合
页面 A(触发方)
<template><view><button @click="sendMessage">发送消息</button></view>
</template><script>
export default {methods: {sendMessage() {uni.$emit('refreshList', { msg: '页面A发来刷新指令', time: Date.now() });}}
}
</script>
页面 B(监听方)
<template><view><text>接收到的消息:{{ message }}</text></view>
</template><script>
export default {data() {return {message: '暂无消息'}},onLoad() {// 注册事件监听uni.$on('refreshList', (data) => {console.log('收到事件:', data);this.message = data.msg + ' at ' + data.time;});},onUnload() {// 页面卸载时移除监听,防止内存泄漏uni.$off('refreshList');}
}
</script>
2. uni.$once
示例
uni.$once
会在第一次触发后自动注销,适合只执行一次的场景,比如 登录成功通知。
<script>
export default {onLoad() {uni.$once('loginSuccess', (user) => {console.log('用户登录成功:', user);this.username = user.name;});}
}
</script>
在登录页面:
uni.$emit('loginSuccess', { name: '张三', id: 1001 });
3. uni.$off
用法
移除单个事件
uni.$off('refreshList');
移除多个事件
uni.$off(['refreshList', 'loginSuccess']);
移除所有事件
uni.$off();
⚠️ 注意:如果不在页面卸载时移除事件监听,可能会导致事件被多次触发或内存泄漏。
四、最佳实践与注意事项
- 事件注册和注销成对出现
建议在onLoad
或created
中注册,在onUnload
或beforeDestroy
中注销。 - 避免过度使用全局事件
小型通信可用,复杂业务建议使用 Vuex 或 Pinia 来做状态管理。 - 防止重复注册
如果在一个页面多次进入并注册事件,而没有注销,可能会导致回调执行多次。 - 调试建议
可以在事件触发和监听时console.log
日志,方便追踪。
五、总结
uni.$on
:注册全局事件监听uni.$emit
:触发事件并传递数据uni.$once
:只执行一次的事件监听uni.$off
:移除监听,防止内存泄漏
它们本质上是 uni-app 提供的全局事件总线,简单易用,适合中小型项目的跨页面通信。
在实际开发中,如果项目规模较大,推荐用 Vuex/Pinia 做数据驱动;如果只是临时通信,使用 uni.$on
等方法就足够了。