Vue.js 将事件从插槽中的内容发射到父级
我正在尝试构建一个灵活的旋转木马控件,允许内部内容元素强制更改幻灯片,以及旋转木马控件本身更改幻灯片 我的页面中的示例结构如下所示Vue.js 将事件从插槽中的内容发射到父级,vue.js,vuejs2,vue-component,Vue.js,Vuejs2,Vue Component,我正在尝试构建一个灵活的旋转木马控件,允许内部内容元素强制更改幻灯片,以及旋转木马控件本身更改幻灯片 我的页面中的示例结构如下所示 <my-carousel> <div class="slide"> <button @click="$emit('next')">Next</button> </div> <div class="slide"> <button @click="$emit('c
<my-carousel>
<div class="slide">
<button @click="$emit('next')">Next</button>
</div>
<div class="slide">
<button @click="$emit('close')">Close</button>
</div>
</my-carousel>
访问幻灯片等没有问题,但是使用$emit
将不起作用,我似乎无法找到解决此问题的简单方法
我希望组件能够轻松地重用,而无需使用
- 中央活动巴士
- 传送带内的硬编码幻灯片
- 在页面级别实现下一个幻灯片方法,并将当前索引传递给控件(因为每次使用旋转木马时都必须这样做)
无法侦听事件next
和close
根据父组件范围编译插槽内容。
作为解决方法,您可以执行以下操作:
<div class="carousel">
<!-- Listen to click event here -->
<div class="slides" @click="doSomething($event)" ref="slides">
<slot></slot>
</div>
<footer>
<!-- other carousel controls like arrows, indicators etc go here -->
</footer>
</div>
在doSomething
中,您可以使用$event.target
找到单击的按钮。有关此问题的更多信息,请访问和
还有一种更高级的方法可以做到这一点,那就是编写自定义渲染函数。将父级传递的单击处理程序包装到
carousel
render函数中,并将新函数传递给槽内容。但是,这是非常罕见的事情,并且会考虑它接近反模式。时隙是针对父组件范围编译的,因此,从槽中发出的事件将只由模板所属的组件接收。
如果您想在旋转木马和幻灯片之间进行交互,可以使用一个允许您将数据和方法从旋转木马公开到插槽的方法 假设您的转盘组件具有next
和close
方法:
旋转木马模板:
转盘示例用法:
下一个
接近
我的解决方案
只需创建一个事件监听器组件(例如“EventListener”),它所做的只是呈现默认插槽,如下所示:
EventListener.vue
现在使用此
组件并将其包装在
上。插槽中的子组件应该向父组件发出事件,如下所示:this.$parent.$emit('myevent')
将自定义事件附加到
组件
转盘模板:
转盘示例:
下一个
接近
注意:组件必须只有一个子vnode。它不能是
,所以我们只是将它包装在div
上。我发现这可以使用$root完成
<h1>Regular html document content</h1>
<parent-component>
<h2>Some parent html that goes inside the slot</h2>
<child-component></child-component>
</parent-component>
常规html文档内容
插槽中的某些父html
父组件:
<template>
<div>
<slot></slot>
<h3>extra html that is displayed</h3>
</div>
</template>
<script>
export default {
created() {
this.$root.$on('child-event', this.reactOnChildEvent);
},
methods: {
this.reactOnChildEvent: function(message) {
console.log(message);
}
}
};
</script>
<template>
<div>
<button @click="$root.$emit('child-event', 'hello world')">
click here
</button>
</div>
</template>
显示的额外html
导出默认值{
创建(){
this.root.on('child-event',this.reactionChildevent);
},
方法:{
this.reactionChildEvent:函数(消息){
控制台日志(消息);
}
}
};
子组件:
<template>
<div>
<slot></slot>
<h3>extra html that is displayed</h3>
</div>
</template>
<script>
export default {
created() {
this.$root.$on('child-event', this.reactOnChildEvent);
},
methods: {
this.reactOnChildEvent: function(message) {
console.log(message);
}
}
};
</script>
<template>
<div>
<button @click="$root.$emit('child-event', 'hello world')">
click here
</button>
</div>
</template>
点击这里
但是,如果可能,请使用上面提到的作用域插槽。只需将$emit('next')
替换为$parent。$emit('next')简单方法
export default {
computed: {
defaultSlot() {
return this.$scopedSlots.default();
}
},
methods: {
this.defaultSlot.forEach(vnode => {
vnode.componentInstance.$on('someevent', (e) => {
console.log(e)
});
});
}
}
检查。假设您的转盘组件具有fnext
和fnClose
方法:
旋转木马模板:
转盘示例用法:
下一个
接近
或者,使用v-slot
(更干净、最新的做事方式):
下一个
接近
以防万一,如果您希望看到更多扩展的代码形式,而不是es6
,尽管这看起来有点混乱,但这会向您显示传递/使用内容的位置和方式
转盘示例用法:
下一个
接近
这似乎很不灵活,因为我不知道旋转木马中有哪些按钮(可能还有其他组件有很多按钮,它们可以做不同的事情)。我需要提供常量或按钮上附加的东西,以确定应该发生什么-对吗?@FrankProvost,不幸的是,这就是它的工作原理。过去一年半以来,我们将Vue.js用于相当大的应用程序。我们很少遇到这个要求。如果你不喜欢这个,有其他的方法,但它不会有你需要的自由结构。此外,考虑注入功能作为一个道具或使用范围和多个槽的组合。这有任何不利之处-它似乎很好地工作只是一个抬头,如果你使用包装组件,而不是像上面的例子一样简单按钮,可能,你需要一个V-on =“$听众”。若要转发所有事件侦听器。@mejiamanuel57如果需要有多个侦听器,可以将一个道具传递到包含对象的插槽中,该对象的所有事件名称都作为键,它们应该作为值运行。例如::on=“{input:onInput,click:onClick}”
,其中onXxxxx是包装器组件中的方法。然后,您可以使用作用域插槽和指令v-on=
将侦听器及其各自的处理程序分配给插槽中的组件(
)。Vuetify也可以做到这一点。我不知道为什么这个答案没有更多的UPs!谢谢,对我来说效果很好。很好的答案!!!不幸的是,答案在这里被低估了。不费吹灰之力就解决了这个问题
<template>
<div>
<slot></slot>
<h3>extra html that is displayed</h3>
</div>
</template>
<script>
export default {
created() {
this.$root.$on('child-event', this.reactOnChildEvent);
},
methods: {
this.reactOnChildEvent: function(message) {
console.log(message);
}
}
};
</script>
<template>
<div>
<button @click="$root.$emit('child-event', 'hello world')">
click here
</button>
</div>
</template>
export default {
computed: {
defaultSlot() {
return this.$scopedSlots.default();
}
},
methods: {
this.defaultSlot.forEach(vnode => {
vnode.componentInstance.$on('someevent', (e) => {
console.log(e)
});
});
}
}