javascriptvue.jsvuejs3nuxt.jsnuxt3.js

Using VueUse intersection observer for multiple elements of the same component


I need to apply an intersection observer from VueUse https://vueuse.org/core/useIntersectionObserver/#directive-usage to multiple elements. Instead of creating individual refs for each element, which is becoming cumbersome with over 10 elements in every component, I decided to use a directive. However, I need to create different states as well, because if I intersect one element, the isVisible sets to true and 'fade-in' class will apply to all of the elements. I need the class to apply only when I intersect a particular element. Is there any better way to make a reusable composable, so that I can pass options like rootMargin and so that I don't need to create a separate ref and a state for each element?

<h1 :class="{ 'fade-in': isVisible }" v-intersection-observer="onIntersectionObserver"></h1>
<h2 :class="{ 'fade-in': isVisible }" v-intersection-observer="onIntersectionObserver"></h2>

Solution

  • As @Estus Flask mentioned in the comments, the optimal solution is to create a component for intersection observer and use <slot>. We can also pass options as props from parent to child. Be sure to add ref, state, setup the observer and define props if needed in the script. You can find more about the observer usage here: https://vueuse.org/core/useIntersectionObserver/#useintersectionobserver.

    // observer child component
    <template>
      <div ref="observerRef">
        <slot :isVisible="isVisible"/>
      </div>
    </template>
    
    // parent component
    <Observer v-slot="{ isVisible }" rootMargin="10px">
      // some content
    </Observer>