I'm trying to build a flexible carousel control that allows inner content elements to force changing a slide, aswell as the carousel controls itself to change slides
A sample structure in my page looks like
<my-carousel>
<div class="slide">
<button @click="$emit('next')">Next</button>
</div>
<div class="slide">
<button @click="$emit('close')">Close</button>
</div>
</my-carousel>
The template for my carousel is like
<div class="carousel">
<div class="slides" ref="slides">
<slot></slot>
</div>
<footer>
<!-- other carousel controls like arrows, indicators etc go here -->
</footer>
</div>
And script like
...
created() {
this.$on('next', this.next)
}
...
Accessing the slides etc is no problem, however using $emit
will not work and I can't seem to find a simple solution for this problem.
I want to component to be easily reusable without having to use
Slots are compiled against the parent component scope, therefore events you emit from the slot will only be received by the component the template belongs to.
If you want interaction between the carousel and slides, you can use a scoped slot instead which allows you to expose data and methods from the carousel to the slot.
Assuming your carousel component has next
and close
methods:
Carousel template:
<div class="carousel">
<div class="slides" ref="slides">
<slot :next="next" :close="close"></slot>
</div>
<footer>
<!-- Other carousel controls like arrows, indicators etc go here -->
</footer>
</div>
Carousel example usage:
<my-carousel v-slot="scope">
<div class="slide">
<button @click="scope.next">Next</button>
</div>
<div class="slide">
<button @click="scope.close">Close</button>
</div>
</my-carousel>
Just create an event listener component (e.g. "EventListener") and all it does is render the default slot like so:
EventListener.vue
export default {
name: 'EventListener'
render() {
return this.$slots.default;
}
}
Now use this <event-listener>
component and wrap it on your <slot>
. Child components inside the slot should emit events to the parent like so: this.$parent.$emit('myevent')
.
Attach your custom events to the <event-listener @myevent="handleEvent">
component.
<div class="carousel">
<event-listener @next="handleNext" @close="handleClose">
<div class="slides" ref="slides">
<slot></slot>
</div>
</event-listener>
<footer>
<!-- other carousel controls like arrows, indicators etc go here -->
</footer>
</div>
<my-carousel>
<div class="slide">
<button @click="$parent.$emit('next')">Next</button>
</div>
</div class="slide">
<button @click="$parent.$emit('close')">Close</button>
</div>
</my-carousel>
Note: The <event-listener>
component must only have one child vnode. It cannot be the <slot>
, so we just wrapped it on the div
instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With