Search code examples
csstogglelazy-loadingsvelteintersection-observer

Intersection Observer classlist.toggle() not adding class


In the code below I am unsure why I cannot see my class 'show' being added in the DOM inspector. I only have styling for img. The class 'show' is not getting applied/toggled. MY goal is to lazy load images. I also need it to be compatible for webkit(safari). Thanks!

<script lang="ts">
    import { onMount } from 'svelte';
    export let image;

  
    let imageRef;

    //Lazy loading attempt...
    onMount(() => {
        //create observer, observe the target elements...
        const observer = new IntersectionObserver(
            (entries) => {

                //toggle the show class...
                entries[0].target.classList.toggle('show', entries[0].isIntersecting);
                //if element is now intersecting, stop observing it...
                if (entries[0].isIntersecting) {
                    observer.unobserve(entries[0].target);
                }
            },
            {
                threshold: 0.3, //30% of target needs to be visible
            },
        );
        observer.observe(imageRef);
    });

</script>

<img
    bind:this={imageRef}
    id="vodImage-{rowIndex}-{index}"
    aria-hidden="true"
    alt={title}
    src={image.uri}
    loading="lazy"
/>



<style lang="postcss"> <----tailwind css

    img {
        @apply w-full h-full opacity-0 duration-300;
        -webkit-animation-duration: 300ms;
    }

    .show {
        @apply opacity-100;
    }
</style>

Solution

  • Cannot reproduce the class not being added, the problem is probably that the CSS is being removed because Svelte does not detect the class being used.

    DOM manipulation like that is not a good idea anyway, just use the native class:name directive instead. onMount can also be replaced with an action.

    E.g.

    <script>
      // ...
    
      let show = false;
    
      function intersect(node) {
        const observer = new IntersectionObserver(
          entries => {
            show = entries[0].isIntersecting;
    
            if (show)
              observer.unobserve(node);
          },
          { threshold: 0.3 },
        );
        observer.observe(node);
    
        return {
          destroy: () => observer.disconnect(),
        };
      }
    </script>
    
    <img
      use:intersect
      class:show
      ...