vue.js 3活动巴士

发布于 2025-02-13 16:33:12 字数 361 浏览 0 评论 0 原文

如何在VUE 3中创建活动总线?


在VUE 2中,它是:

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

在VUE 3中, vue 不再是构造函数, vue.createapp({}); 返回一个没有的对象$ on $ emit 方法。

How to create Event Bus in Vue 3?


In Vue 2, it was:

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

In Vue 3, Vue is not a constructor anymore, and Vue.createApp({}); returns an object that has no $on and $emit methods.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

风铃鹿 2025-02-20 16:33:12

如官方 docs 您可以使用<< a href =“ https://github.com/developit/mitt” rel =“ noreferrer”> mitt 库要在组件之间调度事件,让我们假设我们有一个侧边栏和标题,其中包含一个关闭/打开侧边栏的按钮,我们需要该按钮来切换侧栏组件内的某些属性:

在main.js中导入该库并创建一个发射器的实例,并将其定义为a 全局属性

安装:

npm install --save mitt

用法:

import { createApp } from 'vue'
import App from './App.vue'
import mitt from 'mitt';
const emitter = mitt();
const 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>

对于使用构图API的人,他们可以使用 emitter 如下:

创建一个文件src/composables/useemitter.js

import { getCurrentInstance } from 'vue'

export default function useEmitter() {
    const internalInstance = getCurrentInstance(); 
    const emitter = internalInstance.appContext.config.globalProperties.emitter;

    return emitter;
}

,从那里您可以使用 use -empitter ,就像您一样使用 UserOuter

import useEmitter from '@/composables/useEmitter'

export default {
  setup() {
    const emitter = useEmitter()
    ...
  }
  ...
}

使用构图API

您也可以从新的组成API中受益,并定义一个可组合的事件总线:

eventbus.js

import { ref } from "vue";
const bus = ref(new Map());

export default function useEventsBus(){

    function emit(event, ...args) {
        bus.value.set(event, args);
    }

    return {
        emit,
        bus
    }
}

在组件A中:

import useEventsBus from './eventBus';
...
//in script setup or inside the setup hook
const {emit}=useEventsBus()
...
 emit('sidebarCollapsed',val)

在组件B中:

const { bus } = useEventsBus()

watch(()=>bus.value.get('sidebarCollapsed'), (val) => {
  // destruct the parameters
    const [sidebarCollapsedBus] = val ?? []
    sidebarCollapsed.value = sidebarCollapsedBus
})

As suggested in official docs you could use mitt library to dispatch events between components, let suppose that we have a sidebar and header which contains a button that close/open the sidebar and we need that button to toggle some property inside the sidebar component :

in main.js import that library and create an instance of that emitter and define as a global property:

Installation :

npm install --save mitt

Usage :

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

in header emit the toggle-sidebar event with some payload :

<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>

In sidebar receive the event with the payload:

<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>

For those using composition api they could use emitter as follows :

Create a file src/composables/useEmitter.js

import { getCurrentInstance } from 'vue'

export default function useEmitter() {
    const internalInstance = getCurrentInstance(); 
    const emitter = internalInstance.appContext.config.globalProperties.emitter;

    return emitter;
}

And from there on you can use useEmitter just like you would with useRouter:

import useEmitter from '@/composables/useEmitter'

export default {
  setup() {
    const emitter = useEmitter()
    ...
  }
  ...
}

Using the composition API

You could also take benefit from the new composition API and define a composable event bus :

eventBus.js

import { ref } from "vue";
const bus = ref(new Map());

export default function useEventsBus(){

    function emit(event, ...args) {
        bus.value.set(event, args);
    }

    return {
        emit,
        bus
    }
}

in component A do:

import useEventsBus from './eventBus';
...
//in script setup or inside the setup hook
const {emit}=useEventsBus()
...
 emit('sidebarCollapsed',val)

in component B :

const { bus } = useEventsBus()

watch(()=>bus.value.get('sidebarCollapsed'), (val) => {
  // destruct the parameters
    const [sidebarCollapsedBus] = val ?? []
    sidebarCollapsed.value = sidebarCollapsedBus
})

晨曦÷微暖 2025-02-20 16:33:12

在vue.js的版本3上,您可以使用第三方库,也可以使用发布者 - bubscriber(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;

On version 3 of Vue.js, you can use either a third-party library, or use the functionality written in the publisher-subscriber(PubSub concept) programming pattern.

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;
尘世孤行 2025-02-20 16:33:12

EventBus类文件的内容:

class EventBusEvent extends Event {
  public data: any

  constructor({type, data} : {type: string, data: any}) {
    super(type)
    this.data = data
  }
}

class EventBus extends EventTarget {
  private static _instance: EventBus

  public static getInstance() : EventBus {
    if (!this._instance) this._instance = new EventBus()
    return this._instance
  }

  public emit(type : string, data?: any) : void {
    this.dispatchEvent(new EventBusEvent({type, data}))
  }
}

export default EventBus.getInstance()

在项目中使用,发射事件:

import EventBus from '...path to eventbus file with class'
//...bla bla bla... code...
EventBus.emit('event type', {..some data..}')

收听事件:

import EventBus from '...path to eventbus file with class' 
//...bla bla bla... code...
EventBus.addEventListener('event type', (event) => { console.log(event.data) })

Content of EventBus class file:

class EventBusEvent extends Event {
  public data: any

  constructor({type, data} : {type: string, data: any}) {
    super(type)
    this.data = data
  }
}

class EventBus extends EventTarget {
  private static _instance: EventBus

  public static getInstance() : EventBus {
    if (!this._instance) this._instance = new EventBus()
    return this._instance
  }

  public emit(type : string, data?: any) : void {
    this.dispatchEvent(new EventBusEvent({type, data}))
  }
}

export default EventBus.getInstance()

usage in project, emit event:

import EventBus from '...path to eventbus file with class'
//...bla bla bla... code...
EventBus.emit('event type', {..some data..}')

listen event:

import EventBus from '...path to eventbus file with class' 
//...bla bla bla... code...
EventBus.addEventListener('event type', (event) => { console.log(event.data) })
哎呦我呸! 2025-02-20 16:33:12

我只想在这里提到您也可以使用 useeventbus vueuse

这是打字稿的一个示例,因此使用注射键。

//myInjectionKey.ts
import type { EventBusKey } from '@vueuse/core'
export const myInjectionKey: EventBusKey<string> = Symbol('my-injection-key')

//emmitter
import { useEventBus } from '@vueuse/core'
import { myInjectionKey } from "src/config/myInjectionKey";

const bus = useEventBus(mapInjectionKey)
bus.emit("Hello")

//receiver
import { useEventBus } from '@vueuse/core'
import { myInjectionKey } from "src/config/myInjectionKey";
const bus = useEventBus(myInjectionKey)
bus.on((e) => {
    console.log(e) // "Hello"
})

I just want to mention here that you can also use useEventBus defined by VueUse.

Here is one example for TypeScript so using an injection key.

//myInjectionKey.ts
import type { EventBusKey } from '@vueuse/core'
export const myInjectionKey: EventBusKey<string> = Symbol('my-injection-key')

//emmitter
import { useEventBus } from '@vueuse/core'
import { myInjectionKey } from "src/config/myInjectionKey";

const bus = useEventBus(mapInjectionKey)
bus.emit("Hello")

//receiver
import { useEventBus } from '@vueuse/core'
import { myInjectionKey } from "src/config/myInjectionKey";
const bus = useEventBus(myInjectionKey)
bus.on((e) => {
    console.log(e) // "Hello"
})
万水千山粽是情ミ 2025-02-20 16:33:12

我已经改编了另一个答案具有与VUE实例的等效接口这不需要更改消耗代码。

此版本还支持 $ off 方法,第一个参数是事件名称的 array 。它还避免了 $ off 方法中的一个问题,即删除多个事件侦听器实际上会删除错误的侦听器,因为迭代沿向前的方向上的数组迭代,同时也从中删除了项目。

event-bus.js

// @ts-check

/**
 * Replacement for the Vue 2-based EventBus.
 *
 * @template EventName
 */
class Bus {
  constructor() {
    /**
     * @type {Map<EventName, Array<{ callback: Function, once: boolean }>>}
     */
    this.eventListeners = new Map()
  }

  /**
   * @param {EventName} eventName
   * @param {Function} callback
   * @param {boolean} [once]
   * @private
   */
  registerEventListener(eventName, callback, once = false) {
    if (!this.eventListeners.has(eventName)) {
      this.eventListeners.set(eventName, [])
    }

    const eventListeners = this.eventListeners.get(eventName)
    eventListeners.push({ callback, once })
  }

  /**
   * See: https://v2.vuejs.org/v2/api/#vm-on
   *
   * @param {EventName} eventName
   * @param {Function} callback
   */
  $on(eventName, callback) {
    this.registerEventListener(eventName, callback)
  }

  /**
   * See: https://v2.vuejs.org/v2/api/#vm-once
   *
   * @param {EventName} eventName
   * @param {Function} callback
   */
  $once(eventName, callback) {
    const once = true
    this.registerEventListener(eventName, callback, once)
  }

  /**
   * Removes all event listeners for the given event name or names.
   *
   * When provided with a callback function, removes only event listeners matching the provided function.
   *
   * See: https://v2.vuejs.org/v2/api/#vm-off
   *
   * @param {EventName | EventName[]} eventNameOrNames
   * @param {Function} [callback]
   */
  $off(eventNameOrNames, callback = undefined) {
    const eventNames = Array.isArray(eventNameOrNames) ? eventNameOrNames : [eventNameOrNames]

    for (const eventName of eventNames) {
      const eventListeners = this.eventListeners.get(eventName)

      if (eventListeners === undefined) {
        continue
      }

      if (typeof callback === 'function') {
        for (let i = eventListeners.length - 1; i >= 0; i--) {
          if (eventListeners[i].callback === callback) {
            eventListeners.splice(i, 1)
          }
        }
      } else {
        this.eventListeners.delete(eventName)
      }
    }
  }

  /**
   * See: https://v2.vuejs.org/v2/api/#vm-emit
   *
   * @param {EventName} eventName
   * @param {any} args
   */
  $emit(eventName, ...args) {
    if (!this.eventListeners.has(eventName)) {
      return
    }

    const eventListeners = this.eventListeners.get(eventName)
    const eventListenerIndexesToDelete = []
    for (const [eventListenerIndex, eventListener] of eventListeners.entries()) {
      eventListener.callback(...args)

      if (eventListener.once) {
        eventListenerIndexesToDelete.push(eventListenerIndex)
      }
    }

    for (let i = eventListenerIndexesToDelete.length - 1; i >= 0; i--) {
      eventListeners.splice(eventListenerIndexesToDelete[i], 1)
    }
  }
}

const EventBus = new Bus()

export default EventBus

old-event-bus.js

import Vue from 'vue'

const EventBus = new Vue()

export default EventBus

example.js

// import EventBus from './old-event-bus.js'
import EventBus from './event-bus.js'

I’ve adapted another answer to have an equivalent interface to a Vue instance so that the utility works as a drop-in replacement that doesn’t require changes in the consuming code.

This version also supports the $off method with the first argument being an array of event names. It also avoids an issue in the $off method were de-registering multiple event listeners would actually delete a wrong one due to iterating over the array in forwards direction while also deleting items from it.

event-bus.js:

// @ts-check

/**
 * Replacement for the Vue 2-based EventBus.
 *
 * @template EventName
 */
class Bus {
  constructor() {
    /**
     * @type {Map<EventName, Array<{ callback: Function, once: boolean }>>}
     */
    this.eventListeners = new Map()
  }

  /**
   * @param {EventName} eventName
   * @param {Function} callback
   * @param {boolean} [once]
   * @private
   */
  registerEventListener(eventName, callback, once = false) {
    if (!this.eventListeners.has(eventName)) {
      this.eventListeners.set(eventName, [])
    }

    const eventListeners = this.eventListeners.get(eventName)
    eventListeners.push({ callback, once })
  }

  /**
   * See: https://v2.vuejs.org/v2/api/#vm-on
   *
   * @param {EventName} eventName
   * @param {Function} callback
   */
  $on(eventName, callback) {
    this.registerEventListener(eventName, callback)
  }

  /**
   * See: https://v2.vuejs.org/v2/api/#vm-once
   *
   * @param {EventName} eventName
   * @param {Function} callback
   */
  $once(eventName, callback) {
    const once = true
    this.registerEventListener(eventName, callback, once)
  }

  /**
   * Removes all event listeners for the given event name or names.
   *
   * When provided with a callback function, removes only event listeners matching the provided function.
   *
   * See: https://v2.vuejs.org/v2/api/#vm-off
   *
   * @param {EventName | EventName[]} eventNameOrNames
   * @param {Function} [callback]
   */
  $off(eventNameOrNames, callback = undefined) {
    const eventNames = Array.isArray(eventNameOrNames) ? eventNameOrNames : [eventNameOrNames]

    for (const eventName of eventNames) {
      const eventListeners = this.eventListeners.get(eventName)

      if (eventListeners === undefined) {
        continue
      }

      if (typeof callback === 'function') {
        for (let i = eventListeners.length - 1; i >= 0; i--) {
          if (eventListeners[i].callback === callback) {
            eventListeners.splice(i, 1)
          }
        }
      } else {
        this.eventListeners.delete(eventName)
      }
    }
  }

  /**
   * See: https://v2.vuejs.org/v2/api/#vm-emit
   *
   * @param {EventName} eventName
   * @param {any} args
   */
  $emit(eventName, ...args) {
    if (!this.eventListeners.has(eventName)) {
      return
    }

    const eventListeners = this.eventListeners.get(eventName)
    const eventListenerIndexesToDelete = []
    for (const [eventListenerIndex, eventListener] of eventListeners.entries()) {
      eventListener.callback(...args)

      if (eventListener.once) {
        eventListenerIndexesToDelete.push(eventListenerIndex)
      }
    }

    for (let i = eventListenerIndexesToDelete.length - 1; i >= 0; i--) {
      eventListeners.splice(eventListenerIndexesToDelete[i], 1)
    }
  }
}

const EventBus = new Bus()

export default EventBus

old-event-bus.js:

import Vue from 'vue'

const EventBus = new Vue()

export default EventBus

example.js:

// import EventBus from './old-event-bus.js'
import EventBus from './event-bus.js'
妄想挽回 2025-02-20 16:33:12

这是Boussadjra Brahim的Reption Api的改进版本。
这种方法使您可以使用有效载荷多次触发事件。
请注意,如果几次触发同一事件时, counter 仅用于触发更改,则使用有效载荷或有效载荷相同。

还要谨慎使用SSR,在这种情况下,总线变量将共享,因此您最终会得到交叉要求的状态污染。为了避免这种情况,您可以将事件总线作为插件实现,并在需要时将其曝光。像这样,将为每个请求初始化总线变量。

useeventbus.js

import { ref, watch } from 'vue';

const bus = ref(new Map());

export function useEventsBus() {
  const emit = (event, props) => {
    const currentValue = bus.value.get(event);
    const counter = currentValue ? ++currentValue[1] : 1;
    bus.value.set(event, [props, counter]);
  };

  const on = (event, callback) => {
    watch(() => bus.value.get(event), (val) => {
      callback(val[0]);
    });
  };

  return {
    emit,
    on,
    bus,
  };
}

PublisherComponent.vue

<script setup lang="ts">
import { useEventsBus } from '~/composables/useEventsBus';
</script>

<template>
  <Button
    @click="useEventsBus().emit('btn-clicked', 'Hello there')"
  >
    Button with payload
  </Button>
  <Button
    @click="useEventsBus().emit('btn-another-clicked')"
  >
    Button without payload
  </Button>
</template>

subscribercomponent.vue

<script setup lang="ts">
import { useEventsBus } from '~/composables/useEventsBus';

useEventsBus().on('btn-clicked', (payload) => {
  console.log(payload); // 'Hello there'
});

useEventsBus().on('btn-another-clicked', (payload) => {
  console.log(payload); // undefined
})
// you can subscribe on the event several times
useEventsBus().on('btn-another-clicked', (payload) => {
  console.log(payload); // undefined
})
</script>

Here is improved version of Boussadjra Brahim's answer with composition API.
This approach allows you to trigger an event multiple times with payload or without it.
Note, that counter is used just to trigger a change if no payload or payload is the same when you trigger same event several times.

Also be careful with SSR, in this case the bus variable will be shared, so you end up with cross-request state pollution. To avoid this you may implement event bus as a plugin and if needed expose it with composable. Like this the bus variable will be initialized for each request.

useEventBus.js

import { ref, watch } from 'vue';

const bus = ref(new Map());

export function useEventsBus() {
  const emit = (event, props) => {
    const currentValue = bus.value.get(event);
    const counter = currentValue ? ++currentValue[1] : 1;
    bus.value.set(event, [props, counter]);
  };

  const on = (event, callback) => {
    watch(() => bus.value.get(event), (val) => {
      callback(val[0]);
    });
  };

  return {
    emit,
    on,
    bus,
  };
}

PublisherComponent.vue

<script setup lang="ts">
import { useEventsBus } from '~/composables/useEventsBus';
</script>

<template>
  <Button
    @click="useEventsBus().emit('btn-clicked', 'Hello there')"
  >
    Button with payload
  </Button>
  <Button
    @click="useEventsBus().emit('btn-another-clicked')"
  >
    Button without payload
  </Button>
</template>

SubscriberComponent.vue

<script setup lang="ts">
import { useEventsBus } from '~/composables/useEventsBus';

useEventsBus().on('btn-clicked', (payload) => {
  console.log(payload); // 'Hello there'
});

useEventsBus().on('btn-another-clicked', (payload) => {
  console.log(payload); // undefined
})
// you can subscribe on the event several times
useEventsBus().on('btn-another-clicked', (payload) => {
  console.log(payload); // undefined
})
</script>
找个人就嫁了吧 2025-02-20 16:33:12

不确定为什么VUE3文档不会引起此提示,但我们可以使用窗口上的事件并在我们所需的VUE3组件中捕获事件:

让我们考虑您想要能够要触发VUE3项目中任何地方的模态( app.vue ),而您

<script setup>
function showMyCustomModal() {
  const showModal = new CustomEvent('modal::show', {
    // for hiding, send `modal::hide`, just make sure
    // the component is currently mounted and it can listen to this event
    detail: 'my-custom-modal',
  })
  window.dispatchEvent(showModal);
}
</script>

的 源组件( app.vue )可以: .vue )可以在安装时开始聆听该事件:

<script setup>
  // define function for handling show modal event
  function handleModalShowEvent(event) {
    if (event.detail === props.id) {
      show();
    }
  }

  // define another for handling hide modal
  function handleModalHideEvent(event) {
    if (event.detail === props.id) {
      hide();
    }
  }

  onMounted(() => {
    // on mounted, listen to the events
    window.addEventListener('modal::show', handleModalShowEvent);
    window.addEventListener('modal::hide', handleModalHideEvent);
  })

  onUnmounted(() => {
    // on unmounted, remove them:
    window.removeEventListener('modal::show', handleModalShowEvent);
    window.removeEventListener('modal::hide', handleModalHideEvent);
  })
</script>

Not sure why vue3 documentation doesn't hint this but we can use javascript custom events on the window and capture the event in our desired vue3 component:

Let's consider you want to be able to trigger a modal from anywhere in your vue3 project (App.vue) and your source component (App.vue) can have:

<script setup>
function showMyCustomModal() {
  const showModal = new CustomEvent('modal::show', {
    // for hiding, send `modal::hide`, just make sure
    // the component is currently mounted and it can listen to this event
    detail: 'my-custom-modal',
  })
  window.dispatchEvent(showModal);
}
</script>

And your modal component (Modal.vue) can start listening to that event whenever mounted:

<script setup>
  // define function for handling show modal event
  function handleModalShowEvent(event) {
    if (event.detail === props.id) {
      show();
    }
  }

  // define another for handling hide modal
  function handleModalHideEvent(event) {
    if (event.detail === props.id) {
      hide();
    }
  }

  onMounted(() => {
    // on mounted, listen to the events
    window.addEventListener('modal::show', handleModalShowEvent);
    window.addEventListener('modal::hide', handleModalHideEvent);
  })

  onUnmounted(() => {
    // on unmounted, remove them:
    window.removeEventListener('modal::show', handleModalShowEvent);
    window.removeEventListener('modal::hide', handleModalHideEvent);
  })
</script>
左秋 2025-02-20 16:33:12

使用 https://www.npmjs.coms.com/package/package/package/vue-eventer 从VUE 2.X到VUE 3.0(只是初始化)时,代码会更改。-

// Vue 2.x
Vue.prototype.$eventBus = new Vue();

&gt;

// Vue 3.x
import VueEventer from 'vue-eventer';
YourVueApp.config.globalProperties.$eventBus = new VueEventer();

Using https://www.npmjs.com/package/vue-eventer means minimal code changes when migrating from Vue 2.x to Vue 3.0 (just initialization)...

// Vue 2.x
Vue.prototype.$eventBus = new Vue();

->

// Vue 3.x
import VueEventer from 'vue-eventer';
YourVueApp.config.globalProperties.$eventBus = new VueEventer();
负佳期 2025-02-20 16:33:12

有了Vue组成和定义,您甚至可以使其更容易:

<!-- 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 功能传递给其他孩子。

With Vue composition and defineEmit you can even make it easier :

<!-- 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>

I just showed it with one children, but you could pass though the emit function down to other children.

拧巴小姐 2025-02-20 16:33:12

基于 mitt 库的简单解决方案。

eventbus.js

import mitt from 'mitt'

const emitter = mitt()
export default {
    $on: (...args) => emitter.on(...args),
    $once: (...args) => emitter.once(...args),
    $off: (...args) => emitter.off(...args),
    $emit: (...args) => emitter.emit(...args)
}

在项目中使用:
component-emiter.js

import EventBus from "../../EventBus"; // path to EventBus.js

// ... code ...
EventBus.$emit('event name',{'some': 'data'});

component-receiver.js

import EventBus from "../../EventBus"; // path to EventBus.js

// ... code ...
EventBus.$on('event name', (data) => {
    console.log('Event emitted', data);      
});

Simple solution based on mitt library.

EventBus.js

import mitt from 'mitt'

const emitter = mitt()
export default {
    $on: (...args) => emitter.on(...args),
    $once: (...args) => emitter.once(...args),
    $off: (...args) => emitter.off(...args),
    $emit: (...args) => emitter.emit(...args)
}

Usage in project:
Component-emiter.js

import EventBus from "../../EventBus"; // path to EventBus.js

// ... code ...
EventBus.$emit('event name',{'some': 'data'});

Component-receiver.js

import EventBus from "../../EventBus"; // path to EventBus.js

// ... code ...
EventBus.$on('event name', (data) => {
    console.log('Event emitted', data);      
});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文