Vue.js EventBus组件重复加载时监听重复事件问题
Vue EventBus 重复触发监听器的解决方案
这绝对是Vue EventBus最容易踩的坑之一!我当初刚用EventBus的时候也被这个问题折腾了好一阵子,太懂你的崩溃了😂
问题根源
你每次进入组件时,都会在mounted钩子中通过eventBus.$on注册一个新的load-item事件监听器,但当你切换到其他组件时,当前组件被销毁(或缓存),这个监听器并没有被移除——EventBus会一直保留着这个监听器的引用。所以每次返回组件,就会多注册一个监听器,触发事件时自然会执行多次,次数随着访问次数递增。
解决方法(按推荐程度排序)
1. 在组件销毁时移除对应监听器(最稳妥)
要注意:如果用了箭头函数,必须把它存到组件实例里,因为$off需要精准匹配同一个函数引用才能移除。代码示例:
export default { data() { return { // 存下监听器函数的引用 loadItemHandler: null } }, mounted() { this.loadItemHandler = () => { // 你的AJAX加载数据逻辑 console.log('加载数据') } // 注册监听器 eventBus.$on('load-item', this.loadItemHandler) }, beforeDestroy() { // 组件销毁前移除监听器 eventBus.$off('load-item', this.loadItemHandler) } }
2. 配合<keep-alive>使用时的处理
如果你的组件是被<keep-alive>缓存的,那么组件不会触发destroyed钩子,而是会触发activated(激活)和deactivated(失活)钩子。这时候应该在activated里注册监听器,deactivated里移除:
export default { data() { return { loadItemHandler: null } }, activated() { this.loadItemHandler = () => { // 你的AJAX加载数据逻辑 } eventBus.$on('load-item', this.loadItemHandler) }, deactivated() { eventBus.$off('load-item', this.loadItemHandler) } }
3. 用$once替代$on(仅适用于只需要执行一次的场景)
如果你的业务逻辑是每个组件实例只需要监听一次load-item事件,那可以直接用eventBus.$once,它会在事件触发一次后自动移除监听器:
mounted() { eventBus.$once('load-item', () => { // 你的AJAX加载数据逻辑 }) }
但要注意:这种方式下,如果你再次回到组件,监听器不会重新注册,所以如果需要每次进入组件都能响应事件,这个方法就不适用了。
总结
核心原则就是:注册了多少个监听器,就要在组件生命周期结束时移除多少个,不然不仅会出现重复执行的问题,还会造成内存泄漏——EventBus一直持有组件实例的引用,导致组件无法被GC回收。
内容的提问来源于stack exchange,提问作者rut2
相关产品推荐
相关产品推荐

