swiper
swiper copied to clipboard
Ability to disable image lazy loading listeners
Clear and concise description of the problem
I am running a multi row (swiper) image gallery which is actionable and I am lazy loading the images with my custom logic. Because I need the performance I didn't want to relay on the swiper but unfortunately it attaches listeners anyway. Which makes it 100% unusable for my usecase. Currently I am patching the swiper to stop that behavior.
Suggested solution
diff --git a/shared/swiper-core.mjs b/shared/swiper-core.mjs
index 619c42a4ee03ac543db7869eb80aa7e782bccab2..06880c6f982f6d2d62dad27700a3ea13a5652a20 100644
--- a/shared/swiper-core.mjs
+++ b/shared/swiper-core.mjs
@@ -2860,9 +2860,9 @@ const events = (swiper, method) => {
}
// Images loader
- el[domMethod]('load', swiper.onLoad, {
- capture: true
- });
+ // el[domMethod]('load', swiper.onLoad, {
+ // capture: true
+ // });
};
function attachEvents() {
const swiper = this;
@@ -3614,11 +3614,11 @@ class Swiper {
if (params.breakpoints) {
swiper.setBreakpoint();
}
- [...swiper.el.querySelectorAll('[loading="lazy"]')].forEach(imageEl => {
- if (imageEl.complete) {
- processLazyPreloader(swiper, imageEl);
- }
- });
+ // [...swiper.el.querySelectorAll('[loading="lazy"]')].forEach(imageEl => {
+ // if (imageEl.complete) {
+ // processLazyPreloader(swiper, imageEl);
+ // }
+ // });
swiper.updateSize();
swiper.updateSlides();
swiper.updateProgress();
@@ -3786,19 +3786,19 @@ class Swiper {
// Attach events
swiper.attachEvents();
- const lazyElements = [...swiper.el.querySelectorAll('[loading="lazy"]')];
- if (swiper.isElement) {
- lazyElements.push(...swiper.hostEl.querySelectorAll('[loading="lazy"]'));
- }
- lazyElements.forEach(imageEl => {
- if (imageEl.complete) {
- processLazyPreloader(swiper, imageEl);
- } else {
- imageEl.addEventListener('load', e => {
- processLazyPreloader(swiper, e.target);
- });
- }
- });
+ // const lazyElements = [...swiper.el.querySelectorAll('[loading="lazy"]')];
+ // if (swiper.isElement) {
+ // lazyElements.push(...swiper.hostEl.querySelectorAll('[loading="lazy"]'));
+ // }
+ // lazyElements.forEach(imageEl => {
+ // if (imageEl.complete) {
+ // processLazyPreloader(swiper, imageEl);
+ // } else {
+ // imageEl.addEventListener('load', e => {
+ // processLazyPreloader(swiper, e.target);
+ // });
+ // }
+ // });
preload(swiper);
// Init Flag
We can add if( preloadEnabled ) props around this behavior
Alternative
No response
Additional context
No response
Validations
- [X] Follow our Code of Conduct
- [X] Read the docs.
- [X] Check that there isn't already an issue that request the same feature to avoid creating a duplicate.
Would you like to open a PR for this feature?
- [x] I'm willing to open a PR
t0ggles-create swiper
I can confirm this patch for my use case as well. When having multiple instances of swiper on a page, will lead to blocking of the main thread, which is a major issue.
This should be prioritized , if possible, as swiper is useless in list rendering scenario (50 instances in my case).
Hm, after more testing Im not sure this fix alone helps with these performance issues.
@PerpetualWar if you are using tailwind removing the classes from swiper component helps a lot. Its an undocumended behavior that swiper emits all the classes prefixed with swiper.
@Xenossolitarius I do not use tailwind or having classes on swiper component.
I have actually dealt with this by avoiding rendering those swipers if they are not visible in viewport. Works great for me , cause I have 3-4 swipers visible in the list at any given time, and perf increase is massive.
@PerpetualWar made this, hope it gets approved https://github.com/nolimits4web/swiper/pull/7638
Any examples with the issue?
I should probably make a stackblitz but overall I am not interested into coupling my lazy loading logic which adheres to counting elements on the screen and registering them to actually pull images when business rules apply to the case. When i want to show 100 slides and 5 rows of swipers and virtual slides are out of option bcs i want to use slidesPerPage auto bcs of layout it just produces a 1 sec swiper recalculation lag
I've been delving a little deeper into this today.
I believe the cause of the performance related issues is down to the update [1] method being called once an image has been lazy loaded. This causes resizes, which calls clientWidth [2] which causes layout/reflow [3], which causes performance issues.
I believe the issue is down to capture: true being passed into the event listener [4].
[1] https://github.com/nolimits4web/swiper/blob/06532aff36fed3ecfa9e57d2c90af3f81f8f7eec/src/core/core.mjs#L399 [2] https://github.com/nolimits4web/swiper/blob/06532aff36fed3ecfa9e57d2c90af3f81f8f7eec/src/core/update/updateSize.mjs#L11 [3] https://gist.github.com/paulirish/5d52fb081b3570c81e3a [4] https://github.com/nolimits4web/swiper/blob/06532aff36fed3ecfa9e57d2c90af3f81f8f7eec/src/core/events/index.mjs#L56
For us, we show a carousel of images which are lazy loaded, but it's their parent element that changes height/width. The image loading does not change the height width.
It's a horrible hack, but monkey patching the addEventListener within swiper's beforeInit call stops the load event from being fired when an image is loaded, and therefore stops the above layout/reflow issues.
on: {
beforeInit: (instance) => {
instance.el._addEventListener = instance.el.addEventListener
instance.el.addEventListener = (event, callback, options) => {
if (event === 'load' && options.capture) {
return
}
return instance.el._addEventListener(event, callback, options)
}
},
},
For Vue, it's only necessary to simply add @load.capture.stop to the parent component of Swiper.
<div
@load.capture.stop 👈
>
<Swiper
class="swiper-container"
:class="{ transition: swiperTransitionEnable }"
centered-slides
slide-to-clicked-slide
slides-per-view="auto"
:space-between="8"
:normalize-slide-index="false"
@swiper="onSwiperInit"
@touch-end="onSwiperTouchEnd"
@slide-change="onSlideChange"
>
<SwiperSlide v-for="(picClip, idx) in flattenPicClip" :key="picClip.extra.flattenIndex">
<SwiperSlideContent />
</SwiperSlide>
</Swiper>
</div>
Thats a nice workaround. Solves the problem but doesnt resolve perf issues