I'm building a thumbnail gallery with a slider feature using Swiper (v6.5.1). By default, the slider is hidden, and when the user clicks one of the images, the slider must be displayed showing the clicked image. Once the slider is open, the user can click a Close button to hide it and return to the thumbnail gallery.
This is the code I'm using:
JS:
var swiper;
swiper = new Swiper( '.gallery-slider .swiper-container', {
loop: true,
observer: true,
observeParents: true,
autoplay: {
delay: 3000,
disableOnInteraction: false,
},
navigation: {
nextEl: '.swiper-next',
prevEl: '.swiper-prev',
},
});
document.querySelectorAll( '.gallery-thumbnails a[data-slide]' ).forEach( item => {
item.addEventListener( 'click', function( e ) {
e.preventDefault();
window.scrollTo( 0, 0 );
document.querySelector( '.gallery-thumbnails' ).style.display = 'none';
document.querySelector( '.gallery-slider .swiper-container' ).style.display = 'block';
var slideno = $( this ).data( 'slide' );
swiper.slideTo( slideno + 1, false, false );
});
});
document.querySelector( '.gallery-slider .close' ).addEventListener( 'click', function( e ) {
e.preventDefault();
document.querySelector( '.gallery-slider .swiper-container' ).style.display = 'none';
document.querySelector( '.gallery-thumbnails' ).style.display = 'flex';
});
CSS:
.gallery-slider .swiper-container {
display: none;
}
HTML:
<div class="gallery-thumbnails">
<div class="gallery-image"><a href="" data-slide="0"><img src="thumb0.jpg" /></a></div>
<div class="gallery-image"><a href="" data-slide="1"><img src="thumb1.jpg" /></a></div>
<div class="gallery-image"><a href="" data-slide="2"><img src="thumb2.jpg" /></a></div>
<div class="gallery-image"><a href="" data-slide="3"><img src="thumb3.jpg" /></a></div>
....
</div>
<div class="gallery-slider">
<div class="swiper-container">
<div class="swiper-prev">previous</div>
<div class="swiper-next">next</div>
<div class="close">close</div>
<div class="swiper-wrapper">
<div class="swiper-slide"><img src="slide0.jpg" /></div>
<div class="swiper-slide"><img src="slide1.jpg" /></div>
<div class="swiper-slide"><img src="slide2.jpg" /></div>
<div class="swiper-slide"><img src="slide3.jpg" /></div>
....
</div>
</div>
</div>
As you can see, the code uses Swiper's observer feature, which reinitializes Swiper each time there's a change in its style (like hide/show) or in its child elements (like adding/removing slides).
Everything works as expected the first time I click an image in the thumbnail gallery. But, if I hide the slider using the Close button and then click in a new image to open the slider again, the slider appears but is not responsive until some seconds have passed. The strange thing is that this delay is not always the same. Sometimes is almost instantaneous and sometimes more than x seconds have already passed when the slider begins to respond to clicks in the next and previous buttons. One thing I noticed is that if I resize the window, the slider becomes responsive instantly.
I tried this code in the latest Chrome and Firefox with the same results.
Is this the expected behavior? Is the MutationObserver
used by the observer feature not always listening to changes in the DOM? Am I initializing Swiper the wrong way?
This is the code for the Swiper observer:
https://github.com/nolimits4web/swiper/blob/master/src/modules/observer/observer.js
hidden
instead ofnone
. There is method to this madness as the DOM essentially kills the nodes when you usedisplay: none
, having to build these again when display is set back to a visible state (flex
in this case). Meaning the re-rendering might be the bottleneck here. On resize they exist already, so this is fast. This seems inline with obeservations.visibility: hidden
instead ofdisplay: none
makes no difference in result. The delay is still there when setting thevisibility
prop tovisible
.