Search code examples
vue.jsoptimizationvuejs3swiper.jsintersection-observer

Managing IntersectionObserver with SwiperJS Autoplay


I'm trying to set up an IntersectionObserver on my feedback section, which has an autoplay feature. I use SwiperJS in Vue 3. First check if the section is visible and then start autoplay, otherwise, I stop it. However, the observer continues to work endlessly, which might take up resources. I tried adding observer.disconnect() in the if statement, but then it stops observing after scrolling to the section for the first time.

// template
<Swiper
    class="swiper"
    v-bind="swiperOptions"
    ref="target"
    @swiper="onSwiper">
    <SwiperSlide class="swiper__slide">
        ...
    </SwiperSlide>
</Swiper>

// script
import { watchEffect, ref } from 'vue';
import { Swiper, SwiperSlide } from 'swiper/vue';
import { Autoplay } from 'swiper/modules';

const swiperOptions = {
    modules: [Autoplay],
    autoplay: {
        delay: 4000,
        disableOnInteraction: true,
    },
    loop: true,
};

const target = ref<HTMLElement | null>(null);
const isVisible = ref(false);

const onSwiper = swiper => {
    const observer = new IntersectionObserver(
        ([entry]) => {
            isVisible.value = entry.isIntersecting;
            if (isVisible.value) {
                swiper.autoplay.start();
            } else {
                swiper.autoplay.stop();
            }
        },
        { threshold: 0 }
    );
    if (target.value) {
        observer.observe(target.value);
    }
};

I get the error 'Uncaught (in promise) TypeError: Failed to execute 'observe' on 'IntersectionObserver': parameter 1 is not of type 'Element'.'

// This approach also didn't work.
if (isVisible.value) {
    swiper.autoplay.start();
    observer.disconnect();
} else {
    swiper.autoplay.stop();
    observer.observe(target.value);
}

Looking for a possible solution.


Solution

  • The issue was in the placement of the ref attribute. Initially, I had placed ref="target" on the <Swiper> component itself, which was causing the problem. The correct approach is to put ref="target" on the wrapper instead, in my case it's a <section>.