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
Your problem is:
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:
Solution to #2 Change
v-if
tov-show
– v-show is keeping the element in DOM but hiding it via CSS. Therefore it is accessible via querySelector.