javascriptvue.jsvue-componentvuejs-slots

Change index of array in order to show the next slide


<template>
    <div class="carousel">
        
        <slot></slot>
         <button @click="index++">Next</button>
    </div>

</template>
<script setup>
import { useSlots, onMounted, onUpdated, ref} from 'vue';

const slots = useSlots()
const index = ref(0)
onMounted(() => {
  const defaultSlotElements = slots.default()
  console.log(`My default slot has ${defaultSlotElements.length} elements.`)
  
}),
onUpdated(() =>{
    console.log(defaultSlotElements[index])
}
)

</script>

I'm trying to create carousel based on slots. Thanks to the previous person on stack overflow, he helped me to figured out how to extract array of slots. Now, I'm dealing with another issue. In order to create carousel, I have to somehow change index of element in the array, so I can move to the next slide of my carousel. Later I have to inject it to my slide component to let V-show render current slot that is 0 by default. But index's value is changed by v-on directive that changes index, so it selects the next or previous slot in the array. I know that I've chosen a complex subject in vue but I don't want to use simpler version of carousel based on images' array because I can't add another component inside this one.

It turned out that I cannot simply by changing index arr[index] select the next object in the array.


Solution

  • If you really need to do it with slots, then you will have to do it with Vue Render Functions & JSX

    <script setup>
    import { useSlots, onMounted, onUpdated, ref, h} from 'vue';
    
    const slots = useSlots()
    const index = ref(0)
    const current = ref(null)
    onMounted(() => {
      const defaultSlotElements = slots.default()
      current.value = defaultSlotElements[0]
    }),
    onUpdated(() =>{
        console.log(defaultSlotElements[index])
        }
    )  
    const render = () => {
        return h('div', { class: 'carousel'}, [
        h('p', `My default slot has ${slots.default().length} elements.`),
        h('div', slots.default()[index.value]),
        h('p', `Picture ${ index.value + 1 }`),
        h('button', { onClick: () => { 
          index.value = index.value + 1 == slots.default().length ? 0 : index.value + 1
        } }, 'Next')
      ]);
    };
    </script>
    
    <template>
        <render />
    </template>
    

    Here is the working SFC Playground

    UPDATE

    The render function does work with custom components.

    Here is an attempt to build up your <Carousel><Slide><Lightbox></Lightbox></Slide></Carousel structure.

    SFC Playground

    I don't see any other way to build what you want using the default slot and not using a render function.