javascript - VueJS 2 : Catch event of direct child component

标签 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
    模板

如果...有效

  • ...我使用建议的“eventhub”功能(替换 this.$onthis.$emithub.$onhub.$emit)

但这不适合我,因为我想在同一页面上多次使用 Tabs 组件,而使用“eventhub”功能不允许这样做。

  • ...我使用this.$parent.$emit

但这感觉很奇怪而且不对。

文档指出可以在直接子组件上监听 $emit 触发的事件 https://v2.vuejs.org/v2/guide/migration.html#dispatch-and-broadcast-replaced

有人有想法吗?

最佳答案

你是对的,在vue 2中,不再有$dispatch。 $emit 可以用于单个组件,但它的作用域是他自己 (this)。推荐的解决方案是使用全局事件管理器 eventhub

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

window.bus = new Vue()

然后在任何组件中:

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

它的工作原理与 this.$root.$emit/this.$root.$on 相同。你说它在你调用 this.$parent.$emit 时有效,但是这段代码模拟了父组件中的作用域发射但从子组件中触发,不好。

我在您的代码中了解到,您想要创建一组已创建的选项卡,但要对它们做什么?

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

标签.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>

标签.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 就更加独立了。对于 parent / child 的沟通,请记住这一点:

  • parent 对 child > 通过 Prop
  • child 到 parent > 通过 $emit(全局总线)

如果您需要更复杂的状态管理,您绝对应该看看 vuex .


编辑

标签.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>

标签.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>

关于javascript - VueJS 2 : Catch event of direct child component,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40588013/

相关文章:

javascript - 对象文字类型的调用签名是什么?它们如何与泛型类型一起使用?

Javascript 和搜索引擎优化

objective-c - NSTextField 没有诸如 'Editing did Change' 之类的事件?

c# - EventWaitHandle 未在进程终止时关闭

jsf - 在加载时执行支持 bean 操作?

javascript - JSON.parse 的问题

javascript - 我的外部 jQuery 文件有什么问题?

oop - 如何改进事件类的层次结构?

java - 如何在循环(循环)运行的程序中处理事件?

javascript - 跨浏览器禁用用户选择(Ctrl + A)