Post

intersection Observer

intersection Observer

https://developer.mozilla.org/ko/docs/Web/API/Intersection_Observer_API

1. 소개

요소가 뷰포트(화면)에 관찰되는지, 즉 관찰하는 요소가 지금 화면에 보이는지 아닌지를 구별하는 기능을 제공한다.

비동기적으로 실행되기때문에 메인 스레드에 영향을 주지 않으며 변화를 관찰할 수 있다. 즉, scroll같은 이벤트 기반의 요소를 관찰하며 발생하는 렌더링 성능, 이벤트 연속 호출과 같은 문제를 해결해준다.

2. 기본 문법

생성자 함수인 new IntersectionObserver(callback, options);를 사용해서 새롭게 관찰할 observer를 생성합니다.

1
2
3
const observer = new IntersectionObserver(callback, options); // observer 초기화

observer.observer(element); // 관찰 대상 등록
  • callback: 변화가 생기면 실행할 함수
  • options: observer의 callback이 언제 호출될지를 제어하는 옵션

#callback

관찰할 요소(타겟)이 등록되거나 가시성(관찰 대상이 화면에 보이는지 안보이는지)이 변화하면 실행할 함수입니다.
callback은 entries,observer 2개의 인수를 가집니다.

1
2
const observer = new IntersectionObserver((entries, observer) => {}, options);
observer.observer(element);

■ entries

IntersectionObserverEntry의 배열을 의미합니다. 읽기전용의 속성들을 제공합니다.

  • boundingClientRect: 타겟의 사각형 정보
  • intersectionRect: 타겟의 교차한 영역 정보 (가시 영역 정보)
  • intersectionRatio: 타겟의 교차한 영역 비율 (0 ~ 1.0 사이의 숫자)
  • isIntersecting: 타겟의 교차 상태 (타겟이 화면에 보여지는지 여부)
  • rootBounds: 지정한 루트 요소의 사각형 정보
  • target: 타겟 요소
  • time: 변경이 발생한 시간 정보
속성에 대한 자세한 정보는 이곳에서 확인하세요.
1
2
3
4
5
6
7
const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach((entry) => {
    console.log(entry);
  });
}, options);

observer.observer(element);

■ observer

콜백이 실행되는 intersectionObserver를 의미합니다.
delay, rootMargin, thresholds, observe, unobserve …등의 값들을 가지고 있습니다.

1
2
3
4
5
const observer = new IntersectionObserver((entries, observer) => {
  console.log(observer);
}, options);

observer.observer(element);

#options

options를 사용하여 observer의 callback이 언제 호출될지를 제어할 수 있습니다.

  • root: 타겟의 가시성을 확인할 때 사용되는 뷰포트
  • rootMargin: root가 가진 바깥 여백
  • threshold: 타겟의 호출 시점을 결정

■ root

타겟의 가시성을 검사하기 위해 뷰포트대신 사용할 요소를 지정합니다.
타겟의 조상요소이어야 하며, 지정하지 않을 경우 또는 null인 경우에는 브라우저의 뷰포트가 기본값으로 지정됩니다.
safari, firefox for android에서는 지원되지 않는 옵션입니다. (출처: mdn 공식문서 - 브라우저 호환성)

1
2
3
4
5
6
7
const observer = new IntersectionObserver(callback, {
  root: null; // 브라우저 뷰포트
})

const observer = new IntersectionObserver(callback, {
  root: document.getElementById('new-viewport')
})

■ rootMargin

뷰포트의 바깥 여백을 의미합니다.
뷰포트의 바깥 여백을 이용해 root의 범위를 확장하거나 축소할 수 있습니다.
px또는 % 단위를 사용해야하며, css의 margin처럼 작성합니다.

1
2
3
4
5
6
7
8
9
10
11
const observer = new IntersectionObserver(callback, {
  rootMargin: '10px 20px 30px 40px';
})

const observer = new IntersectionObserver(callback, {
  rootMargin: '10% 0';
})

const observer = new IntersectionObserver(callback, {
  rootMargin: '200px';
})

■ threshold

타겟의 호출 시점을 결정하는 옵션입니다. 타겟의 가시성이 얼마나 필요한지, 즉 타겟이 얼마만큼 화면에 보여졌을 때 콜백을 실행할지 결정합니다.
0.0에서 1.0 사이의 값으로 작성하며 배열 형태로 여러 값들을 작성해도 됩니다. 기본값은 0입니다.

1
2
3
4
5
6
7
const observer = new IntersectionObserver(callback, {
  threshold: 0.3; // 요소가 화면에 30%만 보여졌을 때 콜백이 실행됨
})

const observer = new IntersectionObserver(callback, {
  threshold: [0.3, 1]; // 요소가 화면에 30% 또는 100% 보여졌을 때 콜백이 실행됨
})

3. intersectionObserver 메소드

#observe()

관찰을 시작할 때 사용합니다.

1
IntersectionObserver.observer(element);
1
2
3
4
5
const observer = new IntersectionObserver(callback, options);

const div = document.querySelector("div");

observer.observer(div);

#unobserve

특정 대상 요소에 대한 관찰을 종료할 때 사용합니다.

1
IntersectionObserver.unobserve(element);
1
2
3
4
5
6
7
const observer = new IntersectionObserver(callback, options);

const div = document.querySelector("div");

observer.observer(div); // 관찰 시작

observer.unobserve(div); // 관찰 종료

또는 callback 함수 안에서 사용하기도 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    // 관찰 대상이 보여지지 않은 경우 실행 X
    if (!entry.isIntersecting) {
      return;
    }

    // 관찰 대상이 보여질 때 실행할 코드 작성

    // 실행한 다음 관찰 종료
    observer.unobserve(entry.target);
  });
}, options);

#disconnect

IntersectionObserver가 관찰하는 모든 요소에 대해 관찰을 종료할 때 사용합니다.

1
IntersectionObserver.disconnect();
1
2
3
4
5
6
7
const observer = new IntersectionObserver(callback, options);

observer.observer(document.querySelector("div"));
observer.observer(document.querySelector("li"));
observer.observer(document.querySelector("h1"));

observer.disconnect(); // observer가 관찰하고 있는 모든 요소에 대해 관찰 종료

4. 활용 예

#무한 스크롤

페이지의 하단 또는 특정 요소가 관찰되면 새로운 콘텐츠를 동적으로 로드하는 무한 스크롤 기능을 구현할 때 사용합니다.

#이미지 lazy loading (이미지 지연 로딩)

이미지 지연 로딩은 웹 페이지 내부의 실제 이미지들이 실제로 화면에 보여질 필요가 있을 때 로딩을 할 수 있도록하는 기법입니다.

한번에 많은 양의 이미지를 로드한다면 로딩 시간이 오래 걸리기때문에, 이미지 요소가 화면에 보여졌을 때 이미지를 로드하는 기능을 구현할 때 사용합니다.

#스크롤 이벤트

사용자가 페이지를 스크롤할 때 특정 요소가 화면에 보여지고 보여지지 않을 때 이벤트를 추가할 때 사용합니다.
예를 들면 스크롤을 내릴 때 특정 요소가 화면 밖에서 안으로 날아들어오는 애니메이션 효과를 구현할 수 있습니다. 또는 화면에 보여질 때 광고 영상을 재생시키고, 화면에서 보여지지 않을 때 광고 영상을 일시정지 시키는 기능을 구현할 수 있습니다.

5. 무한 스크롤 예시코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function List() {
  const targetRef = useRef(null); // 관찰할 대상을

  useEffect(() => {
    const observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          // 관찰 대상이 보여진다면 실행할 코드 작성하기
          loadMore();
        }
      });
      if (targetRef.current) {
        observer.observe(targetRef.current); // 관찰할 대상이 존재한다면 관찰 시작하기

        observer.unobserve(targetRef.current); // 관찰 종료하기
      }
    }, options);
  }, []);

  return (
    <div>
      <span ref={targetRef}>이게 보여지면 코드가 실행됩니다</span>
    </div>
  );
}

참고 사이트

This post is licensed under CC BY 4.0 by the author.