导读
在Vue2中,我们遇到复杂的组件通信时,经常采用事件总线的方式来通信。其具体的思路就是实例化一个空白的Vue,并通过其提供的$on
、$once
、$emit
方法来进行通信。而在Vue3中,上述三个API已经被移除了,那么我们又如何使用事件总线呢?
事件总线的本质
Vue2中的$on
、$once
、$emit
本质上就是其内部实现了一个EventEmitter
(事件派发器),每一个事件都和若干回调相对应,只要事件被触发,那么就将执行此事件所有对应的回调。同时,在JavaScript中,该思想被广泛地使用,尤其在Node.js的事件机制中,就是创建了一个EventEmitter
实例,具体请自行查阅相关资料。因此,我们只需要实现一个简单的EventEmitter
,并全局传递到每一个组件中,就可以实现一个事件总线了。而全局传递,我们可以使用config.globalProperties
绑定到每一个组件,也可以在根组件(main)中,通过provide
提供总线,需要使用的组件使用inject
注入。下面就让我们来实现一下吧。
构建一个EventEmitter
由于我们可能会有多条总线,我们还是把EventEmitter
写成类的方式,每一条总线都将是一个EventEmitter
实例。以下是EventEmitter
的简单实现,其只实现了on
、once
、emit
三个API。
- class EventEmitter{
- constructor(){
- this.callbacks={};
- }
- on(envetName,callback){
- if(!Array.isArray(this.callbacks[envetName])){
- this.callbacks[envetName]=[];
- }
- this.callbacks[envetName].push(callback);
- }
- emit(eventName,...args){
- if(Array.isArray(this.callbacks[eventName])){
- this.callbacks[eventName].forEach(callback=>callback(...args));
- }
- }
- off(eventName,callback){
- if(!Array.isArray(this.callbacks[eventName])){
- return
- }
- if(callback){
- this.callbacks[eventName].forEach(cb=>{
- if(callback===cb){
- this.callbacks[eventName].splice(this.callbacks[eventName].indexOf(callback),1);
- }
- });
- } else{
- this.callbacks[eventName]=[];
- }
- }
- once(eventName,callback){
- const that=this;
- const fn=function(){
- callback.apply(that,[...arguments]);
- that.off(eventName,fn);
- }
- that.on(eventName,fn);
- }
- }
具体的代码基本上还是很好理解的,就不在本文解释了,具体请自行查阅相关的资料。
将EventEmitter实例化并全局引入
上文已经说了有两种引入EventEmitter
的方法,这里简单地给个参考实例吧。
config.globalProperties方法
在main.js中
- import { createApp } from 'vue'
- import './style.css'
- import App from './App.vue'
- const app=createApp(App);
- app.config.globalProperties.$event=new EventEmitter();
- app.mount('#app')
在组件中:
- //Comp1
- <script setup>
- import {getCurrentInstance} from "vue"
- const vm=getCurrentInstance();
- vm.proxy.$event.on('test',()=>{
- console.log('test event emit!')
- })
- </script>
-
- //Comp2
- <script setup>
- import {getCurrentInstance} from "vue"
- const vm=getCurrentInstance();
- vm.proxy.$event.emit('test',"a","b")
- </script>
但这种方法不太优雅,不方便定义多条总线,建议使用下述的方法。
provide/inject
在main.js中
- provide("eventBus1",new EventEmitter());
- provide("eventBus2",new EventEmitter());
在组件中
- //Comp1
- <script setup>
- import {inject} from "vue";
- const bus1=inject("eventBus1")
- bus1.on("bus1-on-event",()=>{
- console.log('eventBus1 on event emit!')
- })
- </script>
- //Comp2
- <script setup>
- import {inject} from "vue";
- const bus1=inject("eventBus1")
- const bus2=inject("eventBus2")
- bus2.on("bus2-on-event",()=>{
- console.log('eventBus2 on event emit!')
- })
- bus1.emit("bus1-on-event")
- </script>
- //Comp3
- <script setup>
- import {inject} from "vue";
- const bus2=inject("eventBus2")
- bus2.emit("bus2-on-event")
- </script>
此方法中,使用inject也比使用getCurrentInstance
再.proxy
更优雅一些,且不使用就不必使用inject注入。
结束语
到此这篇关于Vue3中事件总线的具体使用的文章就介绍到这了,更多相关Vue3 事件总线内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!