Vuejs - bubbling custom events

前端 未结 2 1823
隐瞒了意图╮
隐瞒了意图╮ 2021-01-04 02:50

Is there a way to allow events to bubble up when using a component within a component?

My application is a dynamic menu. The dynamic menu is a component (dyn-m

2条回答
  •  没有蜡笔的小新
    2021-01-04 03:44

    There are 4 options I know of

    1. Re-emit events like you did
    2. Use this.$parent (repetitively) on the child component to access the desired parent and emit the event. (see "Implement your own bubbling event plugin" below)
    3. Use an event bus that is provided by the parent and injected in the children.
    4. Use a Vuex store and push events to an event queue in the child component. Somewhere else in the app, watch that reactive event queue for new elements or just bind it to something.

    Implement your own bubbling event plugin

    It's very simple. The plugin adds a new $bubble method that emits events that bubble to their parents. I considered publishing a plugin that does this, but it's so simple that the overhead is not worth it.

    // Add this as a Vue plugin
    Vue.use((Vue) => {
      Vue.prototype.$bubble = function $bubble(eventName, ...args) {
        // Emit the event on all parent components
        let component = this;
        do {
          component.$emit(eventName, ...args);
          component = component.$parent;
        } while (component);
      };
    });
    
    // Some nested components as an example
    
    // note usage of "$bubble" instead of "$emit"
    Vue.component('component-c', {
      template: `
        `,
    });
    
    Vue.component('component-b', {
      template: ``,
      
      methods: {
        onMyEvent(...args) {
          console.log('component-b listener: ', ...args);
        },
      },
    });
    
    Vue.component('component-a', {
      template: ``,
      
      methods: {
        onMyEvent(...args) {
          console.log('component-a listener: ', ...args);
        },
      },
    });
    
    var vapp = new Vue({
      el: '#app',
    
      methods: {
        onMyEvent(...args) {
          console.log('root listener: ', ...args);
        },
      },
    });
    
    
    

    Event bus

    The event bus looks like this:

    Vue.component('dyn-menu', {
      components: {
        'menu-item': {
          template: '
  • {{item.text}}
  • ', props: ['item'], inject: ['eventBus'], // <-- Inject in the child methods: { itemClick() { // Emit the event on the event bus this.eventBus.$emit('dyn-menu-item-click', ['menu-item dyn-menu-item-click']); } } } }, // ... }); var vapp = new Vue({ el: '#app', data: { // ... eventBus: new Vue(), }, provide() { return { // The parent component provides the event bus to its children eventBus: this.eventBus, }; }, created() { // Listen to events on the event bus this.eventBus.$on('dyn-menu-item-click', this.menuClick); }, methods: { menuClick(message) {} } })

    Working example: https://jsfiddle.net/7vwfx52b/

    There are plenty of event bus plugins listed here: https://github.com/vuejs/awesome-vue#custom-events

提交回复
热议问题