【问题标题】:Unique EventBus for multiple instances of the same Vue application同一 Vue 应用程序的多个实例的唯一 EventBus
【发布时间】:2025-12-30 20:35:10
【问题描述】:

我有一个 Vue 应用程序(基本上是一个视频播放器),它使用 EventBus 跨通常无法轻松通信的组件进行通信。这在我开发视频播放器时效果很好,但现在我使用 Rollup 将其捆绑在一起,当我尝试将视频播放器的多个实例放在同一页面上时,一个实例发送的任何事件也将被所有应用程序的其他实例。

现在事后看来,我明白为什么人们似乎不喜欢 EventBus,但我找不到一个很好的解决方案来改进或替换它。我无法动态命名 EventBus 实例,因为这样我的应用程序的其余部分将不会被告知新名称。我什至不能在我的 EventBus 侦听器中使用类似 videoId 的东西来控制唯一性,因为如果一个视频多次出现在同一页面上,我会遇到同样的问题。

一些帖子建议使用 VueX,但我的应用程序不需要是有状态的,而且它看起来不像是事件和侦听器的替代品(尽管我可能错了。)这似乎需要更多的开销比我需要的功能。再说一次,我可能是错的。

我试图尽可能多地删除不相关的代码,但要说明我是如何实现 EventBus 的: event-bus.js:

import Vue from 'vue';

const EventBus = new Vue();

export default EventBus;

MediaPlayer.vue:

<template>
  <div>
    <div>
      <div id='media-player'>
        <end-screen v-if="videoIsFinished"/>
        <tap-video
          ref="tapVideoRef"
          :source='sourceUrl'
          :videoId='videoId'
          @videoEndHandler='videoEndHandler'
        >
        </tap-video>

        <div id="control-bar-container">
          <transition name="slide-fade">
            <div v-show='(showControls || !playing)' >
              <media-controls
                :playing="playing"
                :videoLength="videoLength"
              />
            </div>
          </transition>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import TapVideo from './TapVideo.vue';
import EventBus from './event-bus';

export default {
  data (){
    return{
      playing: false,
      showControls: false,
      videoLength: 0,
      tapVideoRef: null
    }
  },
  mounted() {
    this.tapVideoRef = this.$refs.tapVideoRef;

    EventBus.$on('videoLoaded', videoLength => {
      this.videoLength = videoLength;
    });

    EventBus.$on('playStateChange', playing => {
      this.onPlayStateChange(playing);
    });
  },
  beforeDestroy() {
    EventBus.$off(['playStateChange','closeDrawer']);
  },
  props: ['sourceUrl', 'platformType', 'videoId'],
}
</script>

【问题讨论】:

  • 您可以通过 prop 在父组件和子组件之间传递事件总线引用。这是我的解决方案:codesandbox.io/s/polished-dust-jfh1z?file=/src/App.vue
  • @big-guy 你得到什么错误?
  • @ChunbinLi 我在制作本地化事件总线方面取得了一些成功,但这会更干净!我试试看
  • @JegadeshBS 没有错误 - 它有效。但由于没有唯一的命名,如果我的应用程序的一个实例发出事件,则该应用程序的所有实例都准备好监听
  • @ChunbinLi 我在下面添加了我的解决方案,感谢它提供的建议:)

标签: vue.js vuex event-bus


【解决方案1】:

万一有人遇到这个问题,我找到了一个适合我的解决方案。感谢@ChunbinLi 为我指明了正确的方向——他们的解决方案确实有效,但是到处传递道具有点笨拙。

相反,我使用了 Vue 支持的提供/注入模式:https://v3.vuejs.org/guide/component-provide-inject.html

一些最小的相关代码:

*别的祖父母将提供 EventBus,

Grandparent.vue

export default {
   provide() {
    return {
      eventBus: new Vue()
    }
  }
}

那么任何后代都有能力注入该总线,

Parent.vue

export default {
  inject: ['eventBus'],
  created() {
    this.eventBus.$emit('neededEvent')
  }
}

Child.vue

export default {
  inject: ['eventBus'],
  created(){
    this.eventBus.$on('neededEvent', ()=>{console.log('Event triggered!')});
  }
}

这仍然是一个 GLOBAL EventBus,因此事件的方向性和父级关系很容易,只要所有通信的组件都是“提供”总线的组件的后代。

【讨论】:

    最近更新 更多