Reputation: 43
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
Reputation: 4406
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:
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
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