etterwin
etterwin

Reputation: 43

How to use multiple Clappr in slider, vue?

I have created a slider consisting of multiple images and videos. I use Swiper and Clappr (video player), but clappr doesn't work with multiple videos.

I tried to fix it through a cycle (code below), but even so, the script only works for the first video.

Vue v.3.1, Clappr v.0.3, Swiper v.4.5.

<section class="content__slider swiper-container"
         v-if="project_data && project_data.length">

    <ul class="swiper-wrapper">
        <li v-for="(object, index) in project_data" :key="index"
            class="content-item swiper-slide">

            <!-- it'll be show, if obj type is images -->
            <v-lazy-image v-if="object.type === 'images'"
                          :src="object.data"
                          class="content-img"/>

            <!-- it'll be show, if obj type is video -->
            <div v-if="object.type === 'video'"
                 class="content-video"
                 :id="'container_' + index"></div>

        </li>
    </ul>

</section>
import axios from 'axios'
import Swiper from "swiper/dist/js/swiper.esm.bundle";
import VLazyImage from "v-lazy-image";
import Clappr from 'clappr'

import 'swiper/dist/css/swiper.min.css'

export default {
    name: "Project",
    data: () => ({
        project_data: [], // data of project
        project_images: [], // arr of images
        project_videos: [], // arr of videos
    }),
    created() {

        axios.get('/getWorks/' + this.$route.params.name)
            .then(response => {

                 let arr = [];

                 this.project_images = response.data.work_images;
                 let images = response.data.work_images;

                 this.project_videos = response.data.work_videos;
                 let videos = response.data.work_videos;

                 for (let i = 0; i < images.length; i++) {
                     arr.push({"type": "images", "data": "/storage/" + images[i]});
                 }
                 for (let i = 0; i < videos.length; i++) {
                     arr.push({"type": "video", "data": "/storage/" + videos[i]});
                 }

                 this.project_data = arr;

            })
            .then(() => {

                // init slider
                new Swiper('.content__slider', {
                    mousewheel: true,
                    keyboard: true,
                    speed: 1200,
                    navigation: {
                        nextEl: '.content-arrow.swiper-button-next',
                        prevEl: '.content-arrow.swiper-button-prev',
                    },
                    pagination: {
                        el: '.content-pagination.swiper-pagination',
                        type: 'fraction',
                    },
                    breakpoints: {
                        959: {
                            zoom: {
                                maxRatio: 5,
                                toggle: true,
                                containerClass: '.content__slider',
                                zoomedSlideClass: '.content-item'
                            },
                        }
                    }
                });

                // init clappr (video player)
                if ( document.querySelector('.content-video') ) {
                    for (let i = 0; i < this.project_videos.length; i++) {
                        new Clappr.Player({
                            source: '/storage/' + this.project_videos[i],
                            parentId: '#container_' + (this.project_images.length - i),
                            mute: true,
                            width: document.querySelector('.content-item').offsetWidth,
                            height: document.querySelector('.content-item').offsetHeight
                        });
                    }
                }
            });
    }
}

It's works for the first video in array, but not for the following

Upvotes: 1

Views: 538

Answers (2)

S&#248;lve
S&#248;lve

Reputation: 4406

Your problem is:

  1. you are initializing clappr on created hook (not ideal)
  2. you are initializing only the first one due to using `v-if

The created hook is triggered before the component is finished building its DOM, therefore in theory, you would not be able to find any elements via your document.querySelector.

Why does this work tho?

Since you are running this querySelector inside a asynchronous function(the ajax call from axios), this means that the time it takes the server to respond your call to /getWorks/, the browser has been done creating the DOM. This is pure luck and not what you would want to do.

Solution to #1; Change created hook to a mounted hook. – Mounted is the hook Vue uses to tell you that the DOM is build and completed.

The second issue is that you are using v-if to "hide" the other elements. v-if completly removes the element from DOM. This makes your querySelector not being able to find it and initialize it. (Because there is only one, and that is your first element:

so, the script only works for the first video.

Solution to #2 Change v-if to v-show – v-show is keeping the element in DOM but hiding it via CSS. Therefore it is accessible via querySelector.

Upvotes: 0

etterwin
etterwin

Reputation: 43

Live and learn, I did not notice my mistake.

parentId: '#container_' + (this.project_images.length + i)

It was necessary to summarize. Now, it works)

Upvotes: 0

Related Questions