Vue.js 3事件总线

问题描述

如何在Vue 3中创建事件总线?


在Vue 2中,它是:

export const bus = new Vue();
bus.$on(...)
bus.$emit(...)

在Vue 3中,Vue不再是构造函数,并且Vue.createApp({});返回的对象没有$on$emit方法。

解决方法

按照官方docs中的建议,您可以使用mitt库在组件之间分派事件,假设我们有一个侧边栏和标题,其中包含一个用于关闭/打开侧边栏的按钮,我们需要该按钮切换侧边栏组件内的某些属性:

在main.js中导入该库并创建该发射器的实例并定义为global property

安装:

 npm install --save mitt

用法:

import { createApp } from 'vue'
import App from './App.vue'
import mitt from 'mitt';
const emitter = mitt();
let app=createApp(App)
app.config.globalProperties.emitter = emitter
app.mount('#app')

标题中的toggle-sidebar事件带有一些有效载荷:

<template>
  <header>
    <button  @click="toggleSidebar"/>toggle</button>
  </header>
</template>
<script >
export default { 
  data() {
    return {
      sidebarOpen: true
    };
  },methods: {
    toggleSidebar() {
      this.sidebarOpen = !this.sidebarOpen;
      this.emitter.emit("toggle-sidebar",this.sidebarOpen);
    }
  }
};
</script>

在边栏中接收带有有效负载的事件:

<template>
  <aside class="sidebar" :class="{'sidebar--toggled':!isOpen}">
  ....
  </aside>
</template>
<script>
export default {
  name: "sidebar",data() {
    return {
      isOpen: true
    };
  },mounted() { 
    this.emitter.on("toggle-sidebar",isOpen => {
      this.isOpen = isOpen;
    });
  }
};
</script>

对于使用composition api的用户,他们可以如下使用emitter

import { getCurrentInstance } from 'vue'
export default{

   setup(){
      const internalInstance = getCurrentInstance(); 
      const emitter = internalInstance.appContext.config.globalProperties.emitter;

       ...
     },...

}

,

在Vue.js的第3版上,您可以使用第三方库,也可以使用以Publisher-Subscriber(PubSub概念)编程模式编写的功能。

event.js

//events - a super-basic Javascript (publish subscribe) pattern

class Event{
    constructor(){
        this.events = {};
    }

    on(eventName,fn) {
        this.events[eventName] = this.events[eventName] || [];
        this.events[eventName].push(fn);
    }

    off(eventName,fn) {
        if (this.events[eventName]) {
            for (var i = 0; i < this.events[eventName].length; i++) {
                if (this.events[eventName][i] === fn) {
                    this.events[eventName].splice(i,1);
                    break;
                }
            };
        }
    }

    trigger(eventName,data) {
        if (this.events[eventName]) {
            this.events[eventName].forEach(function(fn) {
                fn(data);
            });
        }
    }
}

export default new Event();

index.js

import Vue from 'vue';
import $bus from '.../event.js';

const app = Vue.createApp({})
app.config.globalProperties.$bus = $bus;
,

借助 Vue 组合和 defineEmit,您甚至可以更轻松:

<!-- Parent -->
<script setup>
  import { defineEmit } from 'vue'
  const emit = defineEmit(['selected'])
  const onEmit = (data) => console.log(data)
</script>

<template>
    <btnList
        v-for="x in y"
        :key="x"
        :emit="emit"
        @selected="onEmit"
    />
</template>
<!-- Children (BtnList.vue) -->
<script setup>
  import { defineProps } from 'vue'
  const props = defineProps({
      emit: Function
  })
</script>

<template>
    <button v-for="x in 10" :key="x" @click="props.emit('selected',x)">Click {{ x }}</button>
</template>

我只是给一个孩子展示了它,但是你可以通过 emit 函数传递给其他孩子。

,

在Vuejs项目中,您可以在与App.vue相同的根目录下创建一个新文件,并实例化Vue构造函数。

eventBus.js文件

import Vue from 'vue';
export default new Vue();

然后,您只需要在要发送或接收事件的每个vue文件上导入事件,如下所示:

import EventBus from "../eventBus.js";

要发出和接收事件,请使用$ emit / $ on标记

EventBus.$emit("evMsg",someData);
EventBus.$on("evMsg",(someData) => {});

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...