如何使用Vue js 2在组件子组件链上冒泡事件?

koa*_*aok 15 javascript vuejs2

我有我的vue应用程序使用:

由component-child组成的组件父组件

在component-parent里面我有按钮,当有人点击我想发出一个事件的按钮,以便由vue处理并传递给另一个组件

到目前为止我做了什么:

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

        methods:{

            itemSelectedListener: function(item){
                console.log('itemSelectedListener', item);
            }
        }
    });




 Vue.component('component-child', {

                        template: ' <span  v-on:click="chooseItem(pty )" >Button  </span>'
                        ,
                        methods: {

                            chooseItem: function(pty){
                                console.log(pty);
                                this.$emit('itemSelected', {
                                    'priority' : pty
                                });
                            }
                        }
                    });

Vue.component('component-parent', {
                        template: '<component-child  v-for="q in items" ></component-child>'
                    });
Run Code Online (Sandbox Code Playgroud)

HTML:

<component-parent v-on:itemSelected="itemSelectedListener"  ></component-parent>
Run Code Online (Sandbox Code Playgroud)

它到达我的console.log(pty); 但似乎这个.$ emit('itemSelected'不会通过:

console.log('itemSelectedListener',item); //这不会被称为......

暗示?

我应该从child-> parent-> Vue-instance冒泡事件?(我也试过但没有成功)

Cri*_*ora 14

component-parent模板在尝试呈现多个子组件时存在一个问题.Vue通常需要在组件内部使用单个根div,因此您需要将其包装在div或其他标记中.

<div>
    <component-child  v-for="q in items"></component-child>
</div>
Run Code Online (Sandbox Code Playgroud)

需要指出的第二点是,您从子组件中发出一个事件,该组件的级别为2级,您可以在根目录中侦听它.

Root //but you listen to the event up here 1 level above
 Component 1 //you should listen to the event here
  Component 2 //your try to emit it from here
Run Code Online (Sandbox Code Playgroud)

你有两个选择.要么从component-child听也发出,即使在component-parent那时甚至向上传播.小提琴https://jsfiddle.net/bjqwh74t/29/

第二种选择是注册一个所谓的全局,bus这是一个空的vue实例,当你想要非子父组件之间的通信时,你可以使用这种实例.小提琴https://jsfiddle.net/bjqwh74t/30/

通常在父组件和子组件之间,您可以通过从子级发出并在父级中侦听来直接使用事件,v-on:event-name="handler"但是如果组件之间有更多级别,则使用第二种方法.

第一个案例的Doc链接:https://vuejs.org/v2/guide/components.html#Using-v-on-with-Custom-Events

第二种情况的Doc链接:https://vuejs.org/v2/guide/components.html#Non-Parent-Child-Communication

PS:喜欢使用kebab-case作为事件名称,这意味着你用-大写字母而不是大写字母.使用大写字母书写可能会导致您的事件未被根目录捕获的奇怪情况.


cod*_*key 7

值得的是,您可以使用浏览器的事件API。与Vue的内置内容相比,它需要的脚本更多,但是它也可以带您解决这些冒泡的问题(与接受的答案中的代码和创建“总线”的代码量差不多)。

在子组件上:

this.$el.dispatchEvent(new CustomEvent('itemSelected', { detail: { 'priority' : pty }, bubbles: true, composed: true });
Run Code Online (Sandbox Code Playgroud)

在父组件的mounted生命周期部分中:

mounted() {
    this.$el.addListener('itemSelected', e => console.log('itemSelectedListener', e.detail));
}
Run Code Online (Sandbox Code Playgroud)

  • 常规 vue 事件绑定 v-bind:itemSelected 也有效 (2认同)
  • 这对我有用!简单的解决方案。我使用“v-on:itemSelected.native”来使其工作。如果没有“.native”后缀,它就无法工作。 (2认同)

beh*_*ani 6

有点晚了,但我是这样做的:

组件子:

this.$root.$emit('foobar',{...});
Run Code Online (Sandbox Code Playgroud)

组件父:

this.$root.$on('foobar')
Run Code Online (Sandbox Code Playgroud)

  • 注意:自 Vue 3.0 起,`$on` 和 `$off` 已被**弃用** (4认同)
  • 您还需要在`beforeDestroy()`或`destroy()`中调用`this.$root.$off('foobar', fn)`以避免内存泄漏,fn变量必须与`中的值匹配this.$root.$on('foobar', fn)` 所以回调函数不能是匿名函数。 (2认同)