【问题标题】:How to create a local event bus on Vue 3如何在 Vue 3 上创建本地事件总线
【发布时间】:2021-09-04 11:21:36
【问题描述】:

如何在一个页面上使用事件总线,以便所有组件和页面都可以在那里读取和接收事件 例如,在 vue 2 中,我创建了一个对象,该对象在创建页面时为字段分配了上下文,并且我在页面的所有组件中都使用了该上下文 示例

//main.js
global.context = new Object();
global.context.app = Vue;

//field assignment with context
global.context.authorization = this;
 
//using context
global.context.authorization.$emit(
  "authorizationMessage",
  this.t("Password fields didn't match")
);

我可以使用导入来改进这种方法吗? 在 vue 3 中使用时出现错误

global.context.authorization.$on("authorizationMessage", (msg) => {
  alert(msg);
});
Uncaught (in promise) TypeError: global.context.authorization.$on is not a function
    at Proxy.created (Messenger.vue?1b1a:25)
    at callWithErrorHandling (runtime-core.esm-bundler.js?5c40:154)
    at callWithAsyncErrorHandling (runtime-core.esm-bundler.js?5c40:163)
    at callHookWithMixinAndExtends (runtime-core.esm-bundler.js?5c40:6032)
    at callSyncHook (runtime-core.esm-bundler.js?5c40:6018)
    at applyOptions (runtime-core.esm-bundler.js?5c40:5956)
    at finishComponentSetup (runtime-core.esm-bundler.js?5c40:6636)
    at setupStatefulComponent (runtime-core.esm-bundler.js?5c40:6567)
    at setupComponent (runtime-core.esm-bundler.js?5c40:6503)
    at mountComponent (runtime-core.esm-bundler.js?5c40:4206)

【问题讨论】:

    标签: vue.js vuejs3


    【解决方案1】:
    1. Vue 3 中没有事件总线。所以$on 将不起作用。见:https://v3.vuejs.org/guide/migration/events-api.html#events-api

    2. 建议您使用外部库创建事件总线,除非您想利用受支持的基于父子事件的通信,在这种通信中,子节点发出只能由父节点监听的事件。见:https://v3.vuejs.org/guide/component-custom-events.html#custom-events

    3. 要为您的应用程序实现事件总线,请确保您正在发射(触发)事件并使用发射器的相同实例来监听它们。否则,它将不起作用。

    4. 对于带有 Vue js 的事件总线,我更喜欢 emittery (https://github.com/sindresorhus/emittery)。它具有出色的 Typescript 支持,功能强大。我也通过 Adonisjs 框架在 Node js 上使用它。

    5. 创建一个 useEvent 钩子 //文件:composables/useEvent.ts

    import Emittery from 'emittery';
    const emitter = new Emittery();
    // Export the Emittery class and its instance.
    // The `emitter` instance is more important for us here
    export {emitter, Emittery};
    

    // 导出 Emittery 类及其实例 出口{发射器,发射器};

    1. 在任何 vue 组件中监听一个事件 // 文件:AnyVueComponent.vue
    <script lang="ts">
    import { defineComponent, onMounted } from 'vue';
    import {emitter} from '../composables/useEvent'
    
    export default defineComponent({
      name: 'ExampleComponent',
      components: {},
      props: {},
      setup() {
        onMounted(() => {
          emitter.on('event-name', async () => {
            // Perform actions. async...await is supported
          });
        })
        return {};
      },
    });
    </script>
    
    1. 在任何 vue 组件中发出事件
    <script lang="ts">
    import { defineComponent, onMounted } from 'vue';
    import {emitter} from '../composables/useEvent'
    
    export default defineComponent({
      name: 'ExampleComponent',
      components: {},
      props: {},
      setup() {
        void emitter.emit('event-name');
        return {};
      },
    });
    </script>
    
    1. 请注意,您可以将useEvent 挂钩导入任何非Vue 文件,它会起作用。它只是一个 JS/TS 文件。

    对于 Quasar 框架:

    1. 创建启动文件
    ./node_modules/.bin/quasar new boot EventBus --format ts
    
    1. // 文件:EventBus.ts
    import { boot } from 'quasar/wrappers';
    import Emittery from 'emittery';
    
    const emitter = new Emittery();
    
    export default boot(({ app }) => {
      app.config.globalProperties.$event = emitter;
    });
    
    // Export the Emittery class and its instance
    export { emitter, Emittery };
    
    1. 注册quasar.conf.js文件
    module.exports = configure(function(/* ctx */){
      return {
        boot: [
          ...,
          'EventBus',
        ],
      }
    }
    
    1. 在任何 vue 组件中监听一个事件 // 文件:AnyVueComponent.vue
    <script lang="ts">
    import { defineComponent, onMounted } from 'vue';
    import {emitter} from '../boot/EventBus'
    
    export default defineComponent({
      name: 'ExampleComponent',
      components: {},
      props: {},
      setup() {
        onMounted(() => {
          emitter.on('event-name', async () => {
            // Perform actions. async...await is supported
          });
        })
        return {};
      },
    });
    </script>
    
    1. 在任何 vue 组件中发出事件
    <script lang="ts">
    import { defineComponent, onMounted } from 'vue';
    import {emitter} from '../boot/EventBus'
    
    export default defineComponent({
      name: 'ExampleComponent',
      components: {},
      props: {},
      setup() {
        void emitter.emit('event-name');
        return {};
      },
    });
    </script>
    

    【讨论】:

      【解决方案2】:

      Vue 3 migration guide for using Vue as an event bus 之后,将该总线替换为tiny-emitter 的实例:

      // event-bus.js
      import emitter from 'tiny-emitter/instance'
      
      export default {
        $on: (...args) => emitter.on(...args),
        $once: (...args) => emitter.once(...args),
        $off: (...args) => emitter.off(...args),
        $emit: (...args) => emitter.emit(...args),
      }
      

      并像这样使用它:

      // main.js
      import eventBus from './event-bus'
      
      //...
      global.context.authorization = eventBus
      

      demo

      【讨论】:

        猜你喜欢
        • 2022-01-23
        • 1970-01-01
        • 1970-01-01
        • 2020-12-07
        • 2020-08-25
        • 2021-11-26
        • 1970-01-01
        • 1970-01-01
        • 2018-12-14
        相关资源
        最近更新 更多