我目前正在尝试启动并运行一个简单的 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.$on
和this.$emit
与hub.$on
和hub.$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/