【发布时间】: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 我在下面添加了我的解决方案,感谢它提供的建议:)