What is IntersectionObserve?

웹 개발을 하면서 조금 있어 보이는(?) 애니메이션을 손에 꼽자면 바로 스크롤을 기반으로 하는 애니메이션이다. 스크를을 기반으로 하는 애니메이션을 만들려면 다음과 같이 작성해야한다.

window.addEventListener('scroll', () => {
  // do something
})

위와 같이 해당하는 스크롤을 작성을 하면 된다. 하지만 위의 방법대로 만들게 되면 불편하거나 리소스를 낭비를 할 수 있다. 그 이유는 다음과 같다.

  1. 스크롤 이벤트는 너무나도 빈번하게 일어나게 되어 계속 스크립트를 갱신하게 된다. 그렇게 되면 리소스를 낭비하게 된다.
  2. 스크롤 이벤트를 만들려면 해당하는 요소의 크기 및 뷰포인트를 기반으로 계산을 해야하며, 또 브라우저에 따라서 미묘하게 원하는 방식으로 작동되지 않는다.

이와 같은 문제떄문에 외부의 라이브러리를 가져와서 편하게 사용하거나, 직접 복잡한 로직을 통해 만들게 된다. 하지만 이러한 방법은 라이브러리를 가져오거나, 복잡한 로직을 통해 만들게 되면서 코드의 가독성이 떨어지게 된다.

그렇다면 이러한 문제를 어떻게 해결할 수 있을까? 그것이 바로 IntersectionObserver이다.

IntersectionObserver

IntersectionObserver는 브라우저에서 지원하는 api로, 해당하는 요소가 뷰포인트안에 들어와있는지 확인을 할 수 있다. 게다가 IntersectionObserver는 뷰포인트에 들어와있는지 확인을 할 때, 해당하는 요소의 크기를 기반으로 확인을 하기 때문에 브라우저에 따라서 미묘하게 원하는 방식으로 작동되지 않는다는 문제를 해결할 수 있다.

게다가 사용방법도 꽤 간단하다. 다음과 같이 사용하면 된다.

const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      entry.target.classList.add('active')
      // do something
    } else{
        entry.target.classList.remove('active')
      // do something
    }
  })
})

observer.observe(document.querySelector('.target'))

위와 같이 사용될 수 있다. IntersectionObserver는 생성자를 통해 생성을 하며, 생성자의 인자로는 콜백함수를 받는다. 콜백함수의 인자로는 entries가 들어오게 되는데, 이는 IntersectionObserverEntry의 배열이다.

entries의 인자는 여러개가 있는 데 그 중 하나는 isIntersecting인데, 해당하는 요소가 뷰포인트안에 들어와있는지 확인을 할 수 있다. isIntersectingtrue이면 해당하는 요소가 뷰포인트안에 들어와있는 것이고, false이면 해당하는 요소가 뷰포인트안에 들어와있지 않은 것이다.

게다가 해당하는 요소도 확인을 할 수 있는데, target이라는 속성을 통해 확인을 할 수 있다. 이렇게만 사용해도 충분히 좋지만 만약 원한다면 더 많은 옵션들도 사용할 수 있다.

IntersectionObserver 옵션

IntersectionObserver는 생성자의 두번째 인자로 옵션을 받을 수 있다. 이 옵션들은 다음과 같다.

  • root: 기준이 되는 요소를 지정할 수 있다. 기본값은 브라우저의 뷰포인트이다.
  • rootMargin: 기준이 되는 요소의 여백을 지정할 수 있다. 기본값은 0이다.
  • threshold: 기준이 되는 요소의 어느정도가 뷰포인트안에 들어와있어야 isIntersectingtrue가 되는지 지정할 수 있다. 기본값은 0이다.

위의 옵션들을 사용한다면, 더 세밀한 부분을 조정하여 조금은 더 복합적으로 사용할 수 있다.

IntersectionObserver 사용 예시

위의 옵션들을 사용하여, 더 복합적으로 사용해보자. 다음과 같이 사용하면 된다.

const opt =  {
  root: document.querySelector('.container'),
  rootMargin: '0px 0px -100px 0px',
  threshold: 0.5
}
const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      entry.target.classList.add('active')
      // do something
    } else{
        entry.target.classList.remove('active')
      // do something
    }
  })
}, opt)

위의 코드에서는 root.container로 지정하였다. 이는 .container안에 있는 요소들이 뷰포인트안에 들어와있는지 확인을 하겠다는 의미이다.
또한 rootMargin0px 0px -100px 0px로 지정하였다. 이는 .container의 아래쪽으로 100px의 여백을 준 것이다. 이렇게 하면 .container의 아래쪽으로 100px의 여백이 생기게 되고, 그 여백안에 들어와있는 요소들이 뷰포인트안에 들어와있는지 확인을 할 수 있게 된다.
그리고 threshold0.5로 지정하여, .container의 아래쪽으로 100px의 여백안에 들어와있는 요소들이 뷰포인트안에 50%가 들어와있는지 확인을 하겠다는 의미이다.

위의 모든 조건들을 만족하데 된다면 isIntersectingtrue가 되고, 그렇지 않다면 false가 된다. 그렇게 된다면 클래스를 이용해 조작하거나 별도의 로직을 적용시켜주거나 외부 라이브러리를 사용하여 애니메이션을 넣어주면 된다.

나 같은 경우에는 다음과 같이 IntersectionObserve api를 사용하여 무한 스크롤을 구현하였다.

function infiniteScrollHandel() {
  const infiniteScroll = document.querySelector(".infinite-scroll");

  const options = {
    rootMargin: "300px 0px 0px 0px",
    threshold: 0,
  };

  const observer = new IntersectionObserver(async (entries) => {
      if (entry.isIntersecting) {
        if (searchValue) {
           renderMovies()
        } else if (movieListEl.classList.contains("movie-list__error")) {
        }
      }
  }, options);

  observer.observe(infiniteScroll);
}

infinite-scroll이라는 클래스를 가진 요소가 뷰포인트에 들어오면, renderMovies()를 실행시켜 무한정으로 영화를 불러오게 만들었다. 이렇게 무궁무진하게 활용하여 사용할 수 있다.

Conclusion

이렇게 간단하게 IntersectionObserver를 사용하여 다양한 예시를 살펴보았다. 스크롤을 기반으로 하는 이벤트는 구현하기에도 복잡하기도 하고 리소스 및 성능에도 적지않은 영향을 줄 수도 있기 때문에, IntersectionObserver를 사용하여 스크롤을 기반으로 하는 이벤트를 구현하면 좋을 것 같다.

어때요 스크롤 기반 애니메이션 만들기 정말 쉽죠?

참고자료

profile
항상 즐겁고 재밌게!

0개의 댓글