Vuejs-冒泡自定义事件 [英] Vuejs - bubbling custom events

查看:352
本文介绍了Vuejs-冒泡自定义事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在组件中使用组件时,是否有办法允许事件冒泡?

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

我的应用程序是一个动态菜单.动态菜单是组件(dyn-menu),它对每个<li>元素使用本地组件(menu-item).每个<menu-item>都有一个与之关联的单击处理程序,该处理程序发出一个自定义事件(在完整实现中具有菜单项的ID).但是应用程序看不到<menu-item>发出的事件,因为它们没有冒泡.

My application is a dynamic menu. The dynamic menu is a component (dyn-menu) and it uses a local component (menu-item) for each of the <li> elements. Each <menu-item> has a click handler associated with it that emits a custom event (with an ID for menu item in the full implementation). But the application doesn't see the events issued by <menu-item> because they are not bubbled up.

是否有一种方法可以允许<dyn-menu>组件本地的<menu-item>组件发出事件,并且仍然允许vapp看到并处理该事件?

Is there a way to allow the <menu-item> component, which is local to the <dyn-menu> component, emit the event and still allow vapp to see and handle the event?

我是Vuejs的新手,所以我可能会遗漏一些明显的东西.而且我可能试图通过使用两个组件来解决此问题,而这并不是处理它的最佳方法.有没有更好的方法来解决这个问题?

I'm pretty new to Vuejs so I might be missing something obvious. And it's possible that I'm trying to solve this by using two components and that's not the best way to handle it. Is there is a better way to approach it?

这是 jsfiddle .您必须删除<dyn-menu>模板中的@dyn-menu-item-click='itemClick'行,以说明如果组件不处理事件,则该事件不会冒泡.如果删除了该行,则<dyn-menu>不会处理该事件,但是vapp也不会看到该事件.

Here's a jsfiddle. You have to remove the @dyn-menu-item-click='itemClick' line in the <dyn-menu> template to illustrate that the event doesn't bubble up if the component doesn't handle the event. If that line is removed then <dyn-menu> doesn't handle the event but vapp never sees the event either.

推荐答案

我知道4个选项

  1. 像您一样重新发送事件
  2. 在子组件上重复使用this.$parent来访问所需的父组件并发出事件. (请参见下面的实现您自己的冒泡事件插件")
  3. 使用事件总线,该事件总线由父级provide d且在子级中inject d.
  4. 使用Vuex存储并将事件推送到子组件中的事件队列.在应用程序中的其他位置,观看该反应性事件队列中是否有新元素,或者将其绑定到某些东西.
  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.

实现自己的冒泡事件插件

这很简单.该插件添加了一个新的$bubble方法,该方法发出会冒泡其父母的事件.我考虑过发布一个可以做到这一点的插件,但是它是如此简单,以至于开销是不值得的.

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: `
    <button type="button" @click="$bubble('my-event', 'payload')">
      Emit bubbling event
    </button>`,
});

Vue.component('component-b', {
  template: `<component-c @my-event="onMyEvent" />`,
  
  methods: {
    onMyEvent(...args) {
      console.log('component-b listener: ', ...args);
    },
  },
});

Vue.component('component-a', {
  template: `<component-b @my-event="onMyEvent" />`,
  
  methods: {
    onMyEvent(...args) {
      console.log('component-a listener: ', ...args);
    },
  },
});

var vapp = new Vue({
  el: '#app',

  methods: {
    onMyEvent(...args) {
      console.log('root listener: ', ...args);
    },
  },
});

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <component-a @my-event="onMyEvent" />
</div>

事件总线如下所示:

Vue.component('dyn-menu', {
  components: {
    'menu-item': {
      template: '<li @click="itemClick">{{item.text}}</li>',
      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) {}
  }
})

工作示例: https://jsfiddle.net/7vwfx52b/

此处列出了许多事件总线插件: https://github.com/vuejs/awesome-vue#custom-events

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

这篇关于Vuejs-冒泡自定义事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆