vue.jsvue-componentvuejs3vuejs-slots

How to create an array of slots' indices in Vue.js?


I'm creating my own carousel where images are added by <img>. I think that the method of creating carousel component in vue is way more flexible because I want to add inside LightBox component inside my carousel's slots

This is my parent component carousel

<template>
    <div class="carousel">
        {{ slides }}
        <slot></slot>
</div>

</template>
<script>
import { ref } from 'vue';
export default{
    data(){
        return{
            Currentslide: 0,
        }
    },
    setup(props, {slots}){
        const slides=ref(slots.default().map((slides) => slides.props.id))
        return{
            slides,
        }
    }
}

</script>

This is my child component slide

<template>
    <div class="slide">
        <slot/>
    </div>
</template>
<script>

</script>
<template>
<Carousel>
  <Slide id="1">1243423</Slide>
  <Slide id=2>
    1231
  </Slide>
  <Slide id="3">r445</Slide>
</Carousel>
</template>

<script>
import Carousel from "../../components/Reusable components/Carousel.vue"
import Slide from "../../components/Reusable components/Slide.vue"
export default{
  components:{
    Carousel,
    Slide
  }
}

Using the inefficient method in the world, I somehow can create an array of slots' indexes. But this is the worst solution to this problem. So, I want to explore another way of extracting IDs from slots in Vue.js


Solution

  • Do you really need slots? It can be done much simpler, I guess.

    See the playground

    const { createApp } = Vue;
    
    const MyImg = {
      props: ['src'],
      template: '<img :src="src" class="image" />'
    }
    
    const MyGallery= {
      components: { MyImg },
      props: ['images'],
      data() {
        return {
            current: 0
            }
      },
      methods: {
        prev() {
          this.current--;
          if (this.current < 0) this.current = this.images.length - 1;
        },
        next() {
          this.current++;
          if (this.current > this.images.length -1) this.current = 0;
        }
      },
      template: '#my-gallery'
    }
    
    const App = { 
      components: { MyGallery },
      data() {
        return {
            images: [
            'https://images.unsplash.com/photo-1517423568366-8b83523034fd?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=300&q=80',
            'https://images.unsplash.com/photo-1609910063430-33fc20be9f88?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=300&q=80',
            'https://images.unsplash.com/photo-1576138089064-2ca7edab2f49?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=300&q=80',
            'https://images.unsplash.com/photo-1612637306950-fd33786d912e?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=300&q=80'        
            ]
        }
      }
    }
    const app = createApp(App)
    app.mount('#app')
    #app { line-height: 2; }
    [v-cloak] { display: none; }
    label { font-weight: bold; }
    .container {
      min-height: 320px;
    }
    .image {
      max-width: 300px;
      max-height: 300px;
      position: absolute;  
    }
    
    .slide-left-enter-active,
    .slide-left-leave-active {
      transition: all 0.3s ease-out;
    }
    
    .slide-left-enter-from {
      opacity: 0;
      transform: translateX(150px);
    }
    
    .slide-left-leave-to {
      opacity: 0;
      transform: translateX(-150px);
    }
    <div id="app">
    <div class="container">
      <my-gallery :images="images">
      </my-gallery>
    </div>
    <p>Pictures &copy Unsplash</p>
    </div>
    
    <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
    <script type="text/x-template" id="my-gallery">
    <button @click="prev()">&lt;</button>&nbsp;Bild {{current + 1}}
      <button @click="next()">&gt;</button>
      <br />
      <transition-group name="slide-left">
        <my-img v-for="(img, index) in images" v-show="current == index" :key="index" :src="img">
        </my-img>
      </transition-group> 
    </script>