VueJS 2:捕获直接子组件的事件

时间:2016-11-14 11:47:14

标签: javascript events event-handling vue-component vue.js

我目前正在尝试启动并运行一个简单的Tabs / Tab组件。 事件处理机制似乎发生了变化,因此我无法使其发挥作用。

目前的实施:

Tabs.vue

<template>
    <div class="tabbed-pane">
        <ul class="tab-list">
            <li class="tab" v-for="tab in tabs" @click="activateTab(tab)">{{ tab.header }}</li>
        </ul>
        <slot></slot>
    </div>
</template>
<script>
    import hub from '../eventhub';
    export default {
        props: [],
        data() {
            return  {
                tabs: []
            }
        },
        created() {
            this.$on('tabcreated', this.registerTab)
        },
        methods: {
            registerTab(tab) {
                this.tabs.push(tab);
            },
            activateTab(tab) {

            }
        }
    }
</script>

Tab.vue

<template>
    <div class="tab-pane" v-show="active">
        <slot></slot>
    </div>
</template>
<script>
    import hub from '../eventhub';
    export default {
        props: {
            'header': String
        },
        data() {
            return {
                active: false
            }
        },
        mounted() {
            this.$emit('tabcreated', this);
        }
    }
</script>

eventhub.js

import Vue from 'vue';

export default new Vue();

查看

<tabs>
    <tab header="Test">
        First Tab
    </tab>
    <tab header="Test2">
        Second Tab
    </tab>
    <tab header="Test3">
        Third Tab
    </tab>
</tabs>

我尝试过以下事项:

  • 使用$emit的超时来测试它是否是计时问题(确实如此) 不)
  • Tabs组件的根元素中使用@tabcreated 模板

如果...

  • ...我使用建议的&#34; eventhub&#34;功能(替换this.$onthis.$emit hub.$onhub.$emit
  • Tabs

但这不适合我,因为我想在同一页面上多次使用this.$parent.$emit组件,并使用&#34; eventhub&#34;功能不允许这样做。

  • ...我使用$emit

但这只是感觉奇怪和错误。

文档说明可以在直接子组件上侦听由#banner { background-image: url(http://lorempixel.com/400/200); padding: 150px 0; text-align: center; background-size: cover; color: white; }触发的事件 https://vuejs.org/v2/guide/migration.html#dispatch-and-broadcast-replaced

有没有人有想法?

3 个答案:

答案 0 :(得分:0)

你是对的,在第二阶段,没有更多的$ dispatch。 $ emit可以用于单个组件,但它将作用于自己(this)。建议的解决方案是使用全局事件管理器eventhub

eventhub可以存储在窗口对象中,无需导入即可在任何地方使用,我喜欢在我的main.js文件中声明如下:

window.bus = new Vue()

然后在任何组件中:

bus.$emit(...)
bus.$on(...)

它与this.$root.$emit / this.$root.$on的作用相同。你说它在你调用this.$parent.$emit时有效,但是这段代码在父组件中模拟了一个范围内的发射但是从孩子那里发射了,不好。

我在您的代码中理解的是,您希望拥有一组已创建的标签,但要对它们执行哪些操作?

您应该考虑更实用的方法,而不是将标签实例存储在父级中,然后从父级激活。 应在选项卡组件上声明activateTab方法,并通过data管理实例化,例如:

Tabs.vue

<template>
    <div class="tabbed-pane">
        <ul class="tab-list">
            <tab v-for="tab in tabs" :header="tab.header"></tab>
        </ul>
    </div>
</template>
<script>
    import hub from '../eventhub';
    import Tab from 'path/to/Tab.vue';
    export default {
        components: [Tab],
        props: [],
        data() {
            return  {
                tabs: ['First Tab', 'Second Tab', 'Third Tab']
            }
        }
    }
</script>

Tab.vue

<template>
    <div class="tab tab-pane" @click:activeTab()>
        <span v-show="active">Activated</span>
        <span>{{ header }}</span>
    </div>
</template>
<script>
    import hub from '../eventhub';
    export default {
        props: {
            'header': String
        },
        data() {
            return {
                active: false
            }
        },
        methods: {
            activeTab () {
               this.active = true
            }
        }
    }
</script>

这样,您的Tab更加独立。对于父母/子女沟通,请牢记这一点:

  • 父母与孩子&gt;通过道具
  • 孩子到父母&gt;通过$ emit(全球公交车)

如果您需要更复杂的状态管理,您一定要查看vuex

修改

Tabs.vue

<template>
    <div class="tabbed-pane">
        <ul class="tab-list">
            <tab v-for="tabData in tabs" :custom="tabData"></tab>
        </ul>
    </div>
</template>
<script>
    import Tab from 'path/to/Tab.vue';
    export default {
        components: [Tab],
        props: [],
        data() {
            return  {
                tabs: [
                  {foo: "foo 1"},
                  {foo: "foo 2"}
                  {foo: "foo 3"}
                ]
            }
        }
    }
</script>

Tab.vue

<template>
    <div class="tab tab-pane" @click:activeTab()>
        <span v-show="active">Activated</span>
        <span>{{ custom.foo }}</span>
    </div>
</template>
<script>

    export default {
        props: ['custom'],
        data() {
            return {
                active: false
            }
        },
        methods: {
            activeTab () {
               this.active = true
            }
        }
    }
</script>

答案 1 :(得分:0)

这就是我对VueJS(2)的看法,没有方便的方法来捕捉子组件发送到父组件的事件。

无论如何,如果您不想使用eventhub方法,那么另一种方法是,如果您只想在相关组件(子组件和父组件)之间进行事件通信而不是与非相关组件之间进行事件通信,那么您可以做这些步骤。

  1. 在其数据属性上引用您的父vue组件(非常重要的是,您不能将传递给子组件)
  2. 将父vue组件引用作为属性传递给子组件(确保绑定它)
  3. 只要发出了所需的事件,
  4. 就会在子组件内触发父组件的相应事件
  5. 伪代码

    // Parent vue component
    Vue.component( 'parent_component' , {
    
       // various codes here ...
    
       data : {
          parent_component_ref : this // reference to the parent component
       },
    
       methods : {
    
          custom_event_cb : function() {
             // custom method to execute when child component emits 'custom_event'
          }
    
       }
    
       // various codes here ...
    
    } );
    
    // Parent component template
    <div id="parent_component">
       <child_component :parent_component_ref="parent_component_ref"></child_component>
    </div>
    
    // Child component
    Vue.component( 'child_component' , {
    
       // various codes here ...
    
       props : [ 'parent_component_ref' ],
    
       mounted : function() {
    
          this.$on( 'custom_event' , this.parent_component_ref.custom_event_cb );
    
    
          this.$emit( 'custom_event' );
    
       },
    
       // You can also, of course, emit the event on events inside the child component, ex. button click, etc..
    
    } );
    

    希望这有助于任何人。

答案 2 :(得分:0)

使用自{Vue v-on="$listeners"以来可用的v2.4.0。然后,您可以订阅父母所需的任何事件,请参阅fiddle

来自Vue Support @ Discord的BogdanL